vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/insert_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  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    25  
    26  	"vitess.io/vitess/go/vt/vtgate/evalengine"
    27  
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"vitess.io/vitess/go/sqltypes"
    31  	"vitess.io/vitess/go/vt/vtgate/vindexes"
    32  
    33  	querypb "vitess.io/vitess/go/vt/proto/query"
    34  	vschemapb "vitess.io/vitess/go/vt/proto/vschema"
    35  )
    36  
    37  func TestInsertUnsharded(t *testing.T) {
    38  	ins := NewQueryInsert(
    39  		InsertUnsharded,
    40  		&vindexes.Keyspace{
    41  			Name:    "ks",
    42  			Sharded: false,
    43  		},
    44  		"dummy_insert",
    45  	)
    46  
    47  	vc := newDMLTestVCursor("0")
    48  	vc.results = []*sqltypes.Result{{
    49  		InsertID: 4,
    50  	}}
    51  
    52  	result, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    53  	if err != nil {
    54  		t.Fatal(err)
    55  	}
    56  	vc.ExpectLog(t, []string{
    57  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
    58  		`ExecuteMultiShard ks.0: dummy_insert {} true true`,
    59  	})
    60  	expectResult(t, "Execute", result, &sqltypes.Result{InsertID: 4})
    61  
    62  	// Failure cases
    63  	vc = &loggingVCursor{shardErr: errors.New("shard_error")}
    64  	_, err = ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    65  	require.EqualError(t, err, `shard_error`)
    66  
    67  	vc = &loggingVCursor{}
    68  	_, err = ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    69  	require.EqualError(t, err, `Keyspace does not have exactly one shard: []`)
    70  }
    71  
    72  func TestInsertUnshardedGenerate(t *testing.T) {
    73  	ins := NewQueryInsert(
    74  		InsertUnsharded,
    75  		&vindexes.Keyspace{
    76  			Name:    "ks",
    77  			Sharded: false,
    78  		},
    79  		"dummy_insert",
    80  	)
    81  	ins.Generate = &Generate{
    82  		Keyspace: &vindexes.Keyspace{
    83  			Name:    "ks2",
    84  			Sharded: false,
    85  		},
    86  		Query: "dummy_generate",
    87  		Values: evalengine.NewTupleExpr(
    88  			evalengine.NewLiteralInt(1),
    89  			evalengine.NullExpr,
    90  			evalengine.NewLiteralInt(2),
    91  			evalengine.NullExpr,
    92  			evalengine.NewLiteralInt(3),
    93  		),
    94  	}
    95  
    96  	vc := newDMLTestVCursor("0")
    97  	vc.results = []*sqltypes.Result{
    98  		sqltypes.MakeTestResult(
    99  			sqltypes.MakeTestFields(
   100  				"nextval",
   101  				"int64",
   102  			),
   103  			"4",
   104  		),
   105  		{InsertID: 1},
   106  	}
   107  
   108  	result, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   109  	if err != nil {
   110  		t.Fatal(err)
   111  	}
   112  	vc.ExpectLog(t, []string{
   113  		// Fetch two sequence value.
   114  		`ResolveDestinations ks2 [] Destinations:DestinationAnyShard()`,
   115  		`ExecuteStandalone dummy_generate n: type:INT64 value:"2" ks2 0`,
   116  		// Fill those values into the insert.
   117  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
   118  		`ExecuteMultiShard ks.0: dummy_insert {__seq0: type:INT64 value:"1" __seq1: type:INT64 value:"4" __seq2: type:INT64 value:"2" __seq3: type:INT64 value:"5" __seq4: type:INT64 value:"3"} true true`,
   119  	})
   120  
   121  	// The insert id returned by ExecuteMultiShard should be overwritten by processGenerateFromValues.
   122  	expectResult(t, "Execute", result, &sqltypes.Result{InsertID: 4})
   123  }
   124  
   125  func TestInsertUnshardedGenerate_Zeros(t *testing.T) {
   126  	ins := NewQueryInsert(
   127  		InsertUnsharded,
   128  		&vindexes.Keyspace{
   129  			Name:    "ks",
   130  			Sharded: false,
   131  		},
   132  		"dummy_insert",
   133  	)
   134  	ins.Generate = &Generate{
   135  		Keyspace: &vindexes.Keyspace{
   136  			Name:    "ks2",
   137  			Sharded: false,
   138  		},
   139  		Query: "dummy_generate",
   140  		Values: evalengine.NewTupleExpr(
   141  			evalengine.NewLiteralInt(1),
   142  			evalengine.NewLiteralInt(0),
   143  			evalengine.NewLiteralInt(2),
   144  			evalengine.NewLiteralInt(0),
   145  			evalengine.NewLiteralInt(3),
   146  		),
   147  	}
   148  
   149  	vc := newDMLTestVCursor("0")
   150  	vc.results = []*sqltypes.Result{
   151  		sqltypes.MakeTestResult(
   152  			sqltypes.MakeTestFields(
   153  				"nextval",
   154  				"int64",
   155  			),
   156  			"4",
   157  		),
   158  		{InsertID: 1},
   159  	}
   160  
   161  	result, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   162  	if err != nil {
   163  		t.Fatal(err)
   164  	}
   165  	vc.ExpectLog(t, []string{
   166  		// Fetch two sequence value.
   167  		`ResolveDestinations ks2 [] Destinations:DestinationAnyShard()`,
   168  		`ExecuteStandalone dummy_generate n: type:INT64 value:"2" ks2 0`,
   169  		// Fill those values into the insert.
   170  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
   171  		`ExecuteMultiShard ks.0: dummy_insert {__seq0: type:INT64 value:"1" __seq1: type:INT64 value:"4" __seq2: type:INT64 value:"2" __seq3: type:INT64 value:"5" __seq4: type:INT64 value:"3"} true true`,
   172  	})
   173  
   174  	// The insert id returned by ExecuteMultiShard should be overwritten by processGenerateFromValues.
   175  	expectResult(t, "Execute", result, &sqltypes.Result{InsertID: 4})
   176  }
   177  
   178  func TestInsertShardedSimple(t *testing.T) {
   179  	invschema := &vschemapb.SrvVSchema{
   180  		Keyspaces: map[string]*vschemapb.Keyspace{
   181  			"sharded": {
   182  				Sharded: true,
   183  				Vindexes: map[string]*vschemapb.Vindex{
   184  					"hash": {
   185  						Type: "hash",
   186  					},
   187  				},
   188  				Tables: map[string]*vschemapb.Table{
   189  					"t1": {
   190  						ColumnVindexes: []*vschemapb.ColumnVindex{{
   191  							Name:    "hash",
   192  							Columns: []string{"id"},
   193  						}},
   194  					},
   195  				},
   196  			},
   197  		},
   198  	}
   199  	vs := vindexes.BuildVSchema(invschema)
   200  	ks := vs.Keyspaces["sharded"]
   201  
   202  	// A single row insert should be autocommitted
   203  	ins := NewInsert(
   204  		InsertSharded,
   205  		false,
   206  		ks.Keyspace,
   207  		[][][]evalengine.Expr{{
   208  			// colVindex columns: id
   209  			{
   210  				evalengine.NewLiteralInt(1),
   211  			},
   212  		}},
   213  		ks.Tables["t1"],
   214  		"prefix",
   215  		[]string{" mid1"},
   216  		" suffix",
   217  	)
   218  	vc := newDMLTestVCursor("-20", "20-")
   219  	vc.shardForKsid = []string{"20-", "-20", "20-"}
   220  
   221  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   222  	if err != nil {
   223  		t.Fatal(err)
   224  	}
   225  	vc.ExpectLog(t, []string{
   226  		// Based on shardForKsid, values returned will be 20-.
   227  		`ResolveDestinations sharded [value:"0"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
   228  		// Row 2 will go to -20, rows 1 & 3 will go to 20-
   229  		`ExecuteMultiShard ` +
   230  			`sharded.20-: prefix mid1 suffix {_id_0: type:INT64 value:"1"} ` +
   231  			`true true`,
   232  	})
   233  
   234  	// Multiple rows are not autocommitted by default
   235  	ins = NewInsert(
   236  		InsertSharded,
   237  		false,
   238  		ks.Keyspace,
   239  		[][][]evalengine.Expr{{
   240  			// colVindex columns: id
   241  			// 3 rows.
   242  			{
   243  				evalengine.NewLiteralInt(1),
   244  				evalengine.NewLiteralInt(2),
   245  				evalengine.NewLiteralInt(3),
   246  			},
   247  		}},
   248  		ks.Tables["t1"],
   249  		"prefix",
   250  		[]string{" mid1", " mid2", " mid3"},
   251  		" suffix",
   252  	)
   253  	vc = newDMLTestVCursor("-20", "20-")
   254  	vc.shardForKsid = []string{"20-", "-20", "20-"}
   255  
   256  	_, err = ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   257  	if err != nil {
   258  		t.Fatal(err)
   259  	}
   260  	vc.ExpectLog(t, []string{
   261  		// Based on shardForKsid, values returned will be 20-, -20, 20-.
   262  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
   263  		// Row 2 will go to -20, rows 1 & 3 will go to 20-
   264  		`ExecuteMultiShard ` +
   265  			`sharded.20-: prefix mid1, mid3 suffix {_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
   266  			`sharded.-20: prefix mid2 suffix {_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
   267  			`true false`,
   268  	})
   269  
   270  	// Optional flag overrides autocommit
   271  	ins = NewInsert(
   272  		InsertSharded,
   273  		false,
   274  		ks.Keyspace,
   275  		[][][]evalengine.Expr{{
   276  			// colVindex columns: id
   277  			// 3 rows.
   278  			{
   279  				evalengine.NewLiteralInt(1),
   280  				evalengine.NewLiteralInt(2),
   281  				evalengine.NewLiteralInt(3),
   282  			},
   283  		}},
   284  
   285  		ks.Tables["t1"],
   286  		"prefix",
   287  		[]string{" mid1", " mid2", " mid3"},
   288  		" suffix",
   289  	)
   290  	ins.MultiShardAutocommit = true
   291  
   292  	vc = newDMLTestVCursor("-20", "20-")
   293  	vc.shardForKsid = []string{"20-", "-20", "20-"}
   294  
   295  	_, err = ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   296  	if err != nil {
   297  		t.Fatal(err)
   298  	}
   299  	vc.ExpectLog(t, []string{
   300  		// Based on shardForKsid, values returned will be 20-, -20, 20-.
   301  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
   302  		// Row 2 will go to -20, rows 1 & 3 will go to 20-
   303  		`ExecuteMultiShard ` +
   304  			`sharded.20-: prefix mid1, mid3 suffix {_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
   305  			`sharded.-20: prefix mid2 suffix {_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
   306  			`true true`,
   307  	})
   308  }
   309  
   310  func TestInsertShardedFail(t *testing.T) {
   311  	invschema := &vschemapb.SrvVSchema{
   312  		Keyspaces: map[string]*vschemapb.Keyspace{
   313  			"sharded": {
   314  				Sharded: true,
   315  				Vindexes: map[string]*vschemapb.Vindex{
   316  					"primary": {
   317  						Type: "lookup_unique",
   318  						Params: map[string]string{
   319  							"table": "prim",
   320  							"from":  "from1",
   321  							"to":    "toc",
   322  						},
   323  					},
   324  				},
   325  				Tables: map[string]*vschemapb.Table{
   326  					"t1": {
   327  						ColumnVindexes: []*vschemapb.ColumnVindex{{
   328  							Name:    "primary",
   329  							Columns: []string{"id"},
   330  						}},
   331  					},
   332  				},
   333  			},
   334  		},
   335  	}
   336  	vs := vindexes.BuildVSchema(invschema)
   337  	ks := vs.Keyspaces["sharded"]
   338  
   339  	ins := NewInsert(
   340  		InsertSharded,
   341  		false,
   342  		ks.Keyspace,
   343  		[][][]evalengine.Expr{{
   344  			// colVindex columns: id
   345  			{
   346  				evalengine.NewLiteralInt(1),
   347  			},
   348  		}},
   349  
   350  		ks.Tables["t1"],
   351  		"prefix",
   352  		[]string{" mid1", " mid2", " mid3"},
   353  		" suffix",
   354  	)
   355  
   356  	vc := &loggingVCursor{}
   357  
   358  	// The lookup will fail to map to a keyspace id.
   359  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   360  	require.EqualError(t, err, `could not map [INT64(1)] to a keyspace id`)
   361  }
   362  
   363  func TestInsertShardedGenerate(t *testing.T) {
   364  	invschema := &vschemapb.SrvVSchema{
   365  		Keyspaces: map[string]*vschemapb.Keyspace{
   366  			"sharded": {
   367  				Sharded: true,
   368  				Vindexes: map[string]*vschemapb.Vindex{
   369  					"hash": {
   370  						Type: "hash",
   371  					},
   372  				},
   373  				Tables: map[string]*vschemapb.Table{
   374  					"t1": {
   375  						ColumnVindexes: []*vschemapb.ColumnVindex{{
   376  							Name:    "hash",
   377  							Columns: []string{"id"},
   378  						}},
   379  					},
   380  				},
   381  			},
   382  		},
   383  	}
   384  	vs := vindexes.BuildVSchema(invschema)
   385  	ks := vs.Keyspaces["sharded"]
   386  
   387  	ins := NewInsert(
   388  		InsertSharded,
   389  		false,
   390  		ks.Keyspace,
   391  		[][][]evalengine.Expr{{
   392  			// colVindex columns: id
   393  			{
   394  				// 3 rows.
   395  				evalengine.NewLiteralInt(1),
   396  				evalengine.NewLiteralInt(2),
   397  				evalengine.NewLiteralInt(3),
   398  			},
   399  		}},
   400  		ks.Tables["t1"],
   401  		"prefix",
   402  		[]string{" mid1", " mid2", " mid3"},
   403  		" suffix",
   404  	)
   405  
   406  	ins.Generate = &Generate{
   407  		Keyspace: &vindexes.Keyspace{
   408  			Name:    "ks2",
   409  			Sharded: false,
   410  		},
   411  		Query: "dummy_generate",
   412  		Values: evalengine.NewTupleExpr(
   413  			evalengine.NewLiteralInt(1),
   414  			evalengine.NullExpr,
   415  			evalengine.NewLiteralInt(2),
   416  		),
   417  	}
   418  
   419  	vc := newDMLTestVCursor("-20", "20-")
   420  	vc.shardForKsid = []string{"20-", "-20", "20-"}
   421  	vc.results = []*sqltypes.Result{
   422  		sqltypes.MakeTestResult(
   423  			sqltypes.MakeTestFields(
   424  				"nextval",
   425  				"int64",
   426  			),
   427  			"2",
   428  		),
   429  		{InsertID: 1},
   430  	}
   431  
   432  	result, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   433  	if err != nil {
   434  		t.Fatal(err)
   435  	}
   436  	vc.ExpectLog(t, []string{
   437  		`ResolveDestinations ks2 [] Destinations:DestinationAnyShard()`,
   438  		`ExecuteStandalone dummy_generate n: type:INT64 value:"1" ks2 -20`,
   439  		// Based on shardForKsid, values returned will be 20-, -20, 20-.
   440  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
   441  		// Row 2 will go to -20, rows 1 & 3 will go to 20-
   442  		`ExecuteMultiShard ` +
   443  			`sharded.20-: prefix mid1, mid3 suffix ` +
   444  			`{__seq0: type:INT64 value:"1" __seq1: type:INT64 value:"2" __seq2: type:INT64 value:"2" ` +
   445  			`_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
   446  			`sharded.-20: prefix mid2 suffix ` +
   447  			`{__seq0: type:INT64 value:"1" __seq1: type:INT64 value:"2" __seq2: type:INT64 value:"2" ` +
   448  			`_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
   449  			`true false`,
   450  	})
   451  
   452  	// The insert id returned by ExecuteMultiShard should be overwritten by processGenerateFromValues.
   453  	expectResult(t, "Execute", result, &sqltypes.Result{InsertID: 2})
   454  }
   455  
   456  func TestInsertShardedOwned(t *testing.T) {
   457  	invschema := &vschemapb.SrvVSchema{
   458  		Keyspaces: map[string]*vschemapb.Keyspace{
   459  			"sharded": {
   460  				Sharded: true,
   461  				Vindexes: map[string]*vschemapb.Vindex{
   462  					"hash": {
   463  						Type: "hash",
   464  					},
   465  					"twocol": {
   466  						Type: "lookup",
   467  						Params: map[string]string{
   468  							"table": "lkp2",
   469  							"from":  "from1,from2",
   470  							"to":    "toc",
   471  						},
   472  						Owner: "t1",
   473  					},
   474  					"onecol": {
   475  						Type: "lookup",
   476  						Params: map[string]string{
   477  							"table": "lkp1",
   478  							"from":  "from",
   479  							"to":    "toc",
   480  						},
   481  						Owner: "t1",
   482  					},
   483  				},
   484  				Tables: map[string]*vschemapb.Table{
   485  					"t1": {
   486  						ColumnVindexes: []*vschemapb.ColumnVindex{{
   487  							Name:    "hash",
   488  							Columns: []string{"id"},
   489  						}, {
   490  							Name:    "twocol",
   491  							Columns: []string{"c1", "c2"},
   492  						}, {
   493  							Name:    "onecol",
   494  							Columns: []string{"c3"},
   495  						}},
   496  					},
   497  				},
   498  			},
   499  		},
   500  	}
   501  	vs := vindexes.BuildVSchema(invschema)
   502  	ks := vs.Keyspaces["sharded"]
   503  
   504  	ins := NewInsert(
   505  		InsertSharded,
   506  		false,
   507  		ks.Keyspace,
   508  		[][][]evalengine.Expr{{
   509  			// colVindex columns: id
   510  			{
   511  				// rows for id
   512  				evalengine.NewLiteralInt(1),
   513  				evalengine.NewLiteralInt(2),
   514  				evalengine.NewLiteralInt(3),
   515  			},
   516  		}, {
   517  			// colVindex columns: c1, c2
   518  			{
   519  				evalengine.NewLiteralInt(4),
   520  				evalengine.NewLiteralInt(5),
   521  				evalengine.NewLiteralInt(6),
   522  			},
   523  			{
   524  				evalengine.NewLiteralInt(7),
   525  				evalengine.NewLiteralInt(8),
   526  				evalengine.NewLiteralInt(9),
   527  			},
   528  		}, {
   529  			// colVindex columns: c3
   530  			{
   531  				evalengine.NewLiteralInt(10),
   532  				evalengine.NewLiteralInt(11),
   533  				evalengine.NewLiteralInt(12),
   534  			},
   535  		}},
   536  		ks.Tables["t1"],
   537  		"prefix",
   538  		[]string{" mid1", " mid2", " mid3"},
   539  		" suffix",
   540  	)
   541  
   542  	vc := newDMLTestVCursor("-20", "20-")
   543  	vc.shardForKsid = []string{"20-", "-20", "20-"}
   544  
   545  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   546  	if err != nil {
   547  		t.Fatal(err)
   548  	}
   549  	vc.ExpectLog(t, []string{
   550  		`Execute insert into lkp2(from1, from2, toc) values(:from1_0, :from2_0, :toc_0), (:from1_1, :from2_1, :toc_1), (:from1_2, :from2_2, :toc_2) ` +
   551  			`from1_0: type:INT64 value:"4" from1_1: type:INT64 value:"5" from1_2: type:INT64 value:"6" ` +
   552  			`from2_0: type:INT64 value:"7" from2_1: type:INT64 value:"8" from2_2: type:INT64 value:"9" ` +
   553  			`toc_0: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" toc_1: type:VARBINARY value:"\x06\xe7\xea\"Βp\x8f" toc_2: type:VARBINARY value:"N\xb1\x90ɢ\xfa\x16\x9c" true`,
   554  		`Execute insert into lkp1(from, toc) values(:from_0, :toc_0), (:from_1, :toc_1), (:from_2, :toc_2) ` +
   555  			`from_0: type:INT64 value:"10" from_1: type:INT64 value:"11" from_2: type:INT64 value:"12" ` +
   556  			`toc_0: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" toc_1: type:VARBINARY value:"\x06\xe7\xea\"Βp\x8f" toc_2: type:VARBINARY value:"N\xb1\x90ɢ\xfa\x16\x9c" true`,
   557  		// Based on shardForKsid, values returned will be 20-, -20, 20-.
   558  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
   559  		`ExecuteMultiShard ` +
   560  			`sharded.20-: prefix mid1, mid3 suffix ` +
   561  			`{_c1_0: type:INT64 value:"4" _c1_1: type:INT64 value:"5" _c1_2: type:INT64 value:"6" ` +
   562  			`_c2_0: type:INT64 value:"7" _c2_1: type:INT64 value:"8" _c2_2: type:INT64 value:"9" ` +
   563  			`_c3_0: type:INT64 value:"10" _c3_1: type:INT64 value:"11" _c3_2: type:INT64 value:"12" ` +
   564  			`_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
   565  			`sharded.-20: prefix mid2 suffix ` +
   566  			`{_c1_0: type:INT64 value:"4" _c1_1: type:INT64 value:"5" _c1_2: type:INT64 value:"6" ` +
   567  			`_c2_0: type:INT64 value:"7" _c2_1: type:INT64 value:"8" _c2_2: type:INT64 value:"9" ` +
   568  			`_c3_0: type:INT64 value:"10" _c3_1: type:INT64 value:"11" _c3_2: type:INT64 value:"12" ` +
   569  			`_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
   570  			`true false`,
   571  	})
   572  }
   573  
   574  func TestInsertShardedOwnedWithNull(t *testing.T) {
   575  	invschema := &vschemapb.SrvVSchema{
   576  		Keyspaces: map[string]*vschemapb.Keyspace{
   577  			"sharded": {
   578  				Sharded: true,
   579  				Vindexes: map[string]*vschemapb.Vindex{
   580  					"hash": {
   581  						Type: "hash",
   582  					},
   583  					"onecol": {
   584  						Type: "lookup",
   585  						Params: map[string]string{
   586  							"table":        "lkp1",
   587  							"from":         "from",
   588  							"to":           "toc",
   589  							"ignore_nulls": "true",
   590  						},
   591  						Owner: "t1",
   592  					},
   593  				},
   594  				Tables: map[string]*vschemapb.Table{
   595  					"t1": {
   596  						ColumnVindexes: []*vschemapb.ColumnVindex{{
   597  							Name:    "hash",
   598  							Columns: []string{"id"},
   599  						}, {
   600  							Name:    "onecol",
   601  							Columns: []string{"c3"},
   602  						}},
   603  					},
   604  				},
   605  			},
   606  		},
   607  	}
   608  	vs := vindexes.BuildVSchema(invschema)
   609  	ks := vs.Keyspaces["sharded"]
   610  
   611  	ins := NewInsert(
   612  		InsertSharded,
   613  		false,
   614  		ks.Keyspace,
   615  		[][][]evalengine.Expr{{
   616  			// colVindex columns: id
   617  			{
   618  				// rows for id
   619  				evalengine.NewLiteralInt(1),
   620  			},
   621  		}, {
   622  			// colVindex columns: c3
   623  			{
   624  				evalengine.NullExpr,
   625  			},
   626  		}},
   627  		ks.Tables["t1"],
   628  		"prefix",
   629  		[]string{" mid1", " mid2", " mid3"},
   630  		" suffix",
   631  	)
   632  
   633  	vc := newDMLTestVCursor("-20", "20-")
   634  	vc.shardForKsid = []string{"20-", "-20", "20-"}
   635  
   636  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   637  	if err != nil {
   638  		t.Fatal(err)
   639  	}
   640  	vc.ExpectLog(t, []string{
   641  		`ResolveDestinations sharded [value:"0"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
   642  		`ExecuteMultiShard sharded.20-: prefix mid1 suffix ` +
   643  			`{_c3_0:  _id_0: type:INT64 value:"1"} true true`,
   644  	})
   645  }
   646  
   647  func TestInsertShardedGeo(t *testing.T) {
   648  	invschema := &vschemapb.SrvVSchema{
   649  		Keyspaces: map[string]*vschemapb.Keyspace{
   650  			"sharded": {
   651  				Sharded: true,
   652  				Vindexes: map[string]*vschemapb.Vindex{
   653  					"geo": {
   654  						Type: "region_experimental",
   655  						Params: map[string]string{
   656  							"region_bytes": "1",
   657  						},
   658  					},
   659  					"lookup": {
   660  						Type: "lookup_unique",
   661  						Params: map[string]string{
   662  							"table": "id_idx",
   663  							"from":  "id",
   664  							"to":    "keyspace_id",
   665  						},
   666  						Owner: "t1",
   667  					},
   668  				},
   669  				Tables: map[string]*vschemapb.Table{
   670  					"t1": {
   671  						ColumnVindexes: []*vschemapb.ColumnVindex{{
   672  							Name:    "geo",
   673  							Columns: []string{"region", "id"},
   674  						}, {
   675  							Name:    "lookup",
   676  							Columns: []string{"id"},
   677  						}},
   678  					},
   679  				},
   680  			},
   681  		},
   682  	}
   683  	vs := vindexes.BuildVSchema(invschema)
   684  	ks := vs.Keyspaces["sharded"]
   685  
   686  	ins := NewInsert(
   687  		InsertSharded,
   688  		false,
   689  		ks.Keyspace,
   690  		[][][]evalengine.Expr{{
   691  			// colVindex columns: region, id
   692  			{
   693  				// rows for region
   694  				evalengine.NewLiteralInt(1),
   695  				evalengine.NewLiteralInt(255),
   696  			},
   697  			{
   698  				// rows for id
   699  				evalengine.NewLiteralInt(1),
   700  				evalengine.NewLiteralInt(1),
   701  			},
   702  		}, {
   703  			// colVindex columns: id
   704  			{
   705  				// rows for id
   706  				evalengine.NewLiteralInt(1),
   707  				evalengine.NewLiteralInt(1),
   708  			},
   709  		}},
   710  		ks.Tables["t1"],
   711  		"prefix",
   712  		[]string{" mid1", " mid2"},
   713  		" suffix",
   714  	)
   715  	for _, colVindex := range ks.Tables["t1"].ColumnVindexes {
   716  		if colVindex.IsPartialVindex() {
   717  			continue
   718  		}
   719  		ins.ColVindexes = append(ins.ColVindexes, colVindex)
   720  	}
   721  
   722  	vc := newDMLTestVCursor("-20", "20-")
   723  	vc.shardForKsid = []string{"20-", "-20"}
   724  
   725  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   726  	if err != nil {
   727  		t.Fatal(err)
   728  	}
   729  	vc.ExpectLog(t, []string{
   730  		`Execute insert into id_idx(id, keyspace_id) values(:id_0, :keyspace_id_0), (:id_1, :keyspace_id_1) ` +
   731  			`id_0: type:INT64 value:"1" id_1: type:INT64 value:"1" ` +
   732  			`keyspace_id_0: type:VARBINARY value:"\x01\x16k@\xb4J\xbaK\xd6" keyspace_id_1: type:VARBINARY value:"\xff\x16k@\xb4J\xbaK\xd6" true`,
   733  		`ResolveDestinations sharded [value:"0" value:"1"] Destinations:DestinationKeyspaceID(01166b40b44aba4bd6),DestinationKeyspaceID(ff166b40b44aba4bd6)`,
   734  		`ExecuteMultiShard sharded.20-: prefix mid1 suffix ` +
   735  			`{_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"1" ` +
   736  			`_region_0: type:INT64 value:"1" _region_1: type:INT64 value:"255"} ` +
   737  			`sharded.-20: prefix mid2 suffix ` +
   738  			`{_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"1" ` +
   739  			`_region_0: type:INT64 value:"1" _region_1: type:INT64 value:"255"} ` +
   740  			`true false`,
   741  	})
   742  }
   743  
   744  func TestInsertShardedIgnoreOwned(t *testing.T) {
   745  	invschema := &vschemapb.SrvVSchema{
   746  		Keyspaces: map[string]*vschemapb.Keyspace{
   747  			"sharded": {
   748  				Sharded: true,
   749  				Vindexes: map[string]*vschemapb.Vindex{
   750  					"primary": {
   751  						Type: "lookup_unique",
   752  						Params: map[string]string{
   753  							"table": "prim",
   754  							"from":  "from1",
   755  							"to":    "toc",
   756  						},
   757  					},
   758  					"twocol": {
   759  						Type: "lookup",
   760  						Params: map[string]string{
   761  							"table": "lkp2",
   762  							"from":  "from1,from2",
   763  							"to":    "toc",
   764  						},
   765  						Owner: "t1",
   766  					},
   767  					"onecol": {
   768  						Type: "lookup",
   769  						Params: map[string]string{
   770  							"table": "lkp1",
   771  							"from":  "from",
   772  							"to":    "toc",
   773  						},
   774  						Owner: "t1",
   775  					},
   776  				},
   777  				Tables: map[string]*vschemapb.Table{
   778  					"t1": {
   779  						ColumnVindexes: []*vschemapb.ColumnVindex{{
   780  							Name:    "primary",
   781  							Columns: []string{"id"},
   782  						}, {
   783  							Name:    "twocol",
   784  							Columns: []string{"c1", "c2"},
   785  						}, {
   786  							Name:    "onecol",
   787  							Columns: []string{"c3"},
   788  						}},
   789  					},
   790  				},
   791  			},
   792  		},
   793  	}
   794  	vs := vindexes.BuildVSchema(invschema)
   795  	ks := vs.Keyspaces["sharded"]
   796  
   797  	ins := NewInsert(
   798  		InsertSharded,
   799  		true,
   800  		ks.Keyspace,
   801  		[][][]evalengine.Expr{{
   802  			// colVindex columns: id
   803  			{
   804  				// rows for id
   805  
   806  				evalengine.NewLiteralInt(1),
   807  				evalengine.NewLiteralInt(2),
   808  				evalengine.NewLiteralInt(3),
   809  				evalengine.NewLiteralInt(4),
   810  			},
   811  		}, {
   812  			// colVindex columns: c1, c2
   813  			{
   814  				// rows for c1
   815  				evalengine.NewLiteralInt(5),
   816  				evalengine.NewLiteralInt(6),
   817  				evalengine.NewLiteralInt(7),
   818  				evalengine.NewLiteralInt(8),
   819  			},
   820  			{
   821  				// rows for c2
   822  				evalengine.NewLiteralInt(9),
   823  				evalengine.NewLiteralInt(10),
   824  				evalengine.NewLiteralInt(11),
   825  				evalengine.NewLiteralInt(12),
   826  			},
   827  		}, {
   828  			// colVindex columns: c3
   829  			{
   830  				// rows for c3
   831  				evalengine.NewLiteralInt(13),
   832  				evalengine.NewLiteralInt(14),
   833  				evalengine.NewLiteralInt(15),
   834  				evalengine.NewLiteralInt(16),
   835  			},
   836  		}},
   837  		ks.Tables["t1"],
   838  		"prefix",
   839  		[]string{" mid1", " mid2", " mid3", " mid4"},
   840  		" suffix",
   841  	)
   842  
   843  	ksid0Lookup := sqltypes.MakeTestResult(
   844  		sqltypes.MakeTestFields(
   845  			"from|to",
   846  			"int64|varbinary",
   847  		),
   848  		"1|\x00",
   849  		"3|\x00",
   850  		"4|\x00",
   851  	)
   852  	ksid0 := sqltypes.MakeTestResult(
   853  		sqltypes.MakeTestFields(
   854  			"to",
   855  			"varbinary",
   856  		),
   857  		"\x00",
   858  	)
   859  	noresult := &sqltypes.Result{}
   860  	vc := newDMLTestVCursor("-20", "20-")
   861  	vc.shardForKsid = []string{"20-", "-20"}
   862  	vc.results = []*sqltypes.Result{
   863  		// primary vindex lookups: fail row 2.
   864  		ksid0Lookup,
   865  		// insert lkp2
   866  		noresult,
   867  		// fail one verification (row 3)
   868  		ksid0,
   869  		noresult,
   870  		ksid0,
   871  		// insert lkp1
   872  		noresult,
   873  		// verify lkp1 (only two rows to verify)
   874  		ksid0,
   875  		ksid0,
   876  	}
   877  
   878  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   879  	if err != nil {
   880  		t.Fatal(err)
   881  	}
   882  	vc.ExpectLog(t, []string{
   883  		`Execute select from1, toc from prim where from1 in ::from1 from1: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"} values:{type:INT64 value:"3"} values:{type:INT64 value:"4"} false`,
   884  		`Execute insert ignore into lkp2(from1, from2, toc) values(:from1_0, :from2_0, :toc_0), (:from1_1, :from2_1, :toc_1), (:from1_2, :from2_2, :toc_2) ` +
   885  			`from1_0: type:INT64 value:"5" from1_1: type:INT64 value:"7" from1_2: type:INT64 value:"8" ` +
   886  			`from2_0: type:INT64 value:"9" from2_1: type:INT64 value:"11" from2_2: type:INT64 value:"12" ` +
   887  			`toc_0: type:VARBINARY value:"\x00" toc_1: type:VARBINARY value:"\x00" toc_2: type:VARBINARY value:"\x00" ` +
   888  			`true`,
   889  		// row 2 is out because it didn't map to a ksid.
   890  		`Execute select from1 from lkp2 where from1 = :from1 and toc = :toc from1: type:INT64 value:"5" toc: type:VARBINARY value:"\x00" false`,
   891  		`Execute select from1 from lkp2 where from1 = :from1 and toc = :toc from1: type:INT64 value:"7" toc: type:VARBINARY value:"\x00" false`,
   892  		`Execute select from1 from lkp2 where from1 = :from1 and toc = :toc from1: type:INT64 value:"8" toc: type:VARBINARY value:"\x00" false`,
   893  		`Execute insert ignore into lkp1(from, toc) values(:from_0, :toc_0), (:from_1, :toc_1) ` +
   894  			`from_0: type:INT64 value:"13" from_1: type:INT64 value:"16" ` +
   895  			`toc_0: type:VARBINARY value:"\x00" toc_1: type:VARBINARY value:"\x00" ` +
   896  			`true`,
   897  		// row 3 is out because it failed Verify. Only two verifications from lkp1.
   898  		`Execute select from from lkp1 where from = :from and toc = :toc from: type:INT64 value:"13" toc: type:VARBINARY value:"\x00" false`,
   899  		`Execute select from from lkp1 where from = :from and toc = :toc from: type:INT64 value:"16" toc: type:VARBINARY value:"\x00" false`,
   900  		`ResolveDestinations sharded [value:"0" value:"3"] Destinations:DestinationKeyspaceID(00),DestinationKeyspaceID(00)`,
   901  		// Bind vars for rows 2 & 3 may be missing because they were not sent.
   902  		`ExecuteMultiShard ` +
   903  			`sharded.20-: prefix mid1 suffix ` +
   904  			`{_c1_0: type:INT64 value:"5" _c1_3: type:INT64 value:"8" ` +
   905  			`_c2_0: type:INT64 value:"9" _c2_3: type:INT64 value:"12" ` +
   906  			`_c3_0: type:INT64 value:"13" _c3_3: type:INT64 value:"16" ` +
   907  			`_id_0: type:INT64 value:"1" _id_3: type:INT64 value:"4"} ` +
   908  			`sharded.-20: prefix mid4 suffix ` +
   909  			`{_c1_0: type:INT64 value:"5" _c1_3: type:INT64 value:"8" ` +
   910  			`_c2_0: type:INT64 value:"9" _c2_3: type:INT64 value:"12" ` +
   911  			`_c3_0: type:INT64 value:"13" _c3_3: type:INT64 value:"16" ` +
   912  			`_id_0: type:INT64 value:"1" _id_3: type:INT64 value:"4"} ` +
   913  			`true false`,
   914  	})
   915  }
   916  
   917  func TestInsertShardedIgnoreOwnedWithNull(t *testing.T) {
   918  	invschema := &vschemapb.SrvVSchema{
   919  		Keyspaces: map[string]*vschemapb.Keyspace{
   920  			"sharded": {
   921  				Sharded: true,
   922  				Vindexes: map[string]*vschemapb.Vindex{
   923  					"primary": {
   924  						Type: "hash",
   925  					},
   926  					"onecol": {
   927  						Type: "lookup",
   928  						Params: map[string]string{
   929  							"table":        "lkp1",
   930  							"from":         "from",
   931  							"to":           "toc",
   932  							"ignore_nulls": "true",
   933  						},
   934  						Owner: "t1",
   935  					},
   936  				},
   937  				Tables: map[string]*vschemapb.Table{
   938  					"t1": {
   939  						ColumnVindexes: []*vschemapb.ColumnVindex{{
   940  							Name:    "primary",
   941  							Columns: []string{"id"},
   942  						}, {
   943  							Name:    "onecol",
   944  							Columns: []string{"c3"},
   945  						}},
   946  					},
   947  				},
   948  			},
   949  		},
   950  	}
   951  	vs := vindexes.BuildVSchema(invschema)
   952  	ks := vs.Keyspaces["sharded"]
   953  
   954  	ins := NewInsert(
   955  		InsertSharded,
   956  		true,
   957  		ks.Keyspace,
   958  		[][][]evalengine.Expr{{
   959  			// colVindex columns: id
   960  			{
   961  				// rows for id
   962  				evalengine.NewLiteralInt(1),
   963  			},
   964  		}, {
   965  			// colVindex columns: c3
   966  			{
   967  				// rows for c3
   968  				evalengine.NullExpr,
   969  			},
   970  		}},
   971  		ks.Tables["t1"],
   972  		"prefix",
   973  		[]string{" mid1", " mid2", " mid3", " mid4"},
   974  		" suffix",
   975  	)
   976  
   977  	ksid0 := sqltypes.MakeTestResult(
   978  		sqltypes.MakeTestFields(
   979  			"to",
   980  			"varbinary",
   981  		),
   982  		"\x00",
   983  	)
   984  	vc := newDMLTestVCursor("-20", "20-")
   985  	vc.shardForKsid = []string{"-20", "20-"}
   986  	vc.results = []*sqltypes.Result{
   987  		ksid0,
   988  		ksid0,
   989  		ksid0,
   990  	}
   991  
   992  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   993  	if err != nil {
   994  		t.Fatal(err)
   995  	}
   996  	vc.ExpectLog(t, []string{
   997  		`Execute select from from lkp1 where from = :from and toc = :toc from:  toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" false`,
   998  		`ResolveDestinations sharded [value:"0"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
   999  		`ExecuteMultiShard sharded.-20: prefix mid1 suffix ` +
  1000  			`{_c3_0:  _id_0: type:INT64 value:"1"} true true`,
  1001  	})
  1002  }
  1003  
  1004  func TestInsertShardedUnownedVerify(t *testing.T) {
  1005  	invschema := &vschemapb.SrvVSchema{
  1006  		Keyspaces: map[string]*vschemapb.Keyspace{
  1007  			"sharded": {
  1008  				Sharded: true,
  1009  				Vindexes: map[string]*vschemapb.Vindex{
  1010  					"hash": {
  1011  						Type: "hash",
  1012  					},
  1013  					"twocol": {
  1014  						Type: "lookup",
  1015  						Params: map[string]string{
  1016  							"table": "lkp2",
  1017  							"from":  "from1,from2",
  1018  							"to":    "toc",
  1019  						},
  1020  					},
  1021  					"onecol": {
  1022  						Type: "lookup",
  1023  						Params: map[string]string{
  1024  							"table": "lkp1",
  1025  							"from":  "from",
  1026  							"to":    "toc",
  1027  						},
  1028  					},
  1029  				},
  1030  				Tables: map[string]*vschemapb.Table{
  1031  					"t1": {
  1032  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1033  							Name:    "hash",
  1034  							Columns: []string{"id"},
  1035  						}, {
  1036  							Name:    "twocol",
  1037  							Columns: []string{"c1", "c2"},
  1038  						}, {
  1039  							Name:    "onecol",
  1040  							Columns: []string{"c3"},
  1041  						}},
  1042  					},
  1043  				},
  1044  			},
  1045  		},
  1046  	}
  1047  	vs := vindexes.BuildVSchema(invschema)
  1048  	ks := vs.Keyspaces["sharded"]
  1049  
  1050  	ins := NewInsert(
  1051  		InsertSharded,
  1052  		false,
  1053  		ks.Keyspace,
  1054  		[][][]evalengine.Expr{{
  1055  			// colVindex columns: id
  1056  			{
  1057  				// rows for id
  1058  				evalengine.NewLiteralInt(1),
  1059  				evalengine.NewLiteralInt(2),
  1060  				evalengine.NewLiteralInt(3),
  1061  			},
  1062  		}, {
  1063  			// colVindex columns: c1, c2
  1064  			{
  1065  				// rows for c1
  1066  				evalengine.NewLiteralInt(4),
  1067  				evalengine.NewLiteralInt(5),
  1068  				evalengine.NewLiteralInt(6),
  1069  			},
  1070  			{
  1071  				// rows for c2
  1072  				evalengine.NewLiteralInt(7),
  1073  				evalengine.NewLiteralInt(8),
  1074  				evalengine.NewLiteralInt(9),
  1075  			},
  1076  		}, {
  1077  			// colVindex columns: c3
  1078  			{
  1079  				// rows for c3
  1080  				evalengine.NewLiteralInt(10),
  1081  				evalengine.NewLiteralInt(11),
  1082  				evalengine.NewLiteralInt(12),
  1083  			},
  1084  		}},
  1085  		ks.Tables["t1"],
  1086  		"prefix",
  1087  		[]string{" mid1", " mid2", " mid3"},
  1088  		" suffix",
  1089  	)
  1090  
  1091  	// nonemptyResult will cause the lookup verify queries to succeed.
  1092  	nonemptyResult := sqltypes.MakeTestResult(
  1093  		sqltypes.MakeTestFields(
  1094  			"c1",
  1095  			"int64",
  1096  		),
  1097  		"1",
  1098  	)
  1099  
  1100  	vc := newDMLTestVCursor("-20", "20-")
  1101  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  1102  	vc.results = []*sqltypes.Result{
  1103  		nonemptyResult,
  1104  		nonemptyResult,
  1105  		nonemptyResult,
  1106  		nonemptyResult,
  1107  		nonemptyResult,
  1108  		nonemptyResult,
  1109  	}
  1110  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1111  	if err != nil {
  1112  		t.Fatal(err)
  1113  	}
  1114  	vc.ExpectLog(t, []string{
  1115  		// Perform verification for each colvindex.
  1116  		// Note that only first column of each colvindex is used.
  1117  		`Execute select from1 from lkp2 where from1 = :from1 and toc = :toc from1: type:INT64 value:"4" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" false`,
  1118  		`Execute select from1 from lkp2 where from1 = :from1 and toc = :toc from1: type:INT64 value:"5" toc: type:VARBINARY value:"\x06\xe7\xea\"Βp\x8f" false`,
  1119  		`Execute select from1 from lkp2 where from1 = :from1 and toc = :toc from1: type:INT64 value:"6" toc: type:VARBINARY value:"N\xb1\x90ɢ\xfa\x16\x9c" false`,
  1120  		`Execute select from from lkp1 where from = :from and toc = :toc from: type:INT64 value:"10" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" false`,
  1121  		`Execute select from from lkp1 where from = :from and toc = :toc from: type:INT64 value:"11" toc: type:VARBINARY value:"\x06\xe7\xea\"Βp\x8f" false`,
  1122  		`Execute select from from lkp1 where from = :from and toc = :toc from: type:INT64 value:"12" toc: type:VARBINARY value:"N\xb1\x90ɢ\xfa\x16\x9c" false`,
  1123  		// Based on shardForKsid, values returned will be 20-, -20, 20-.
  1124  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
  1125  		`ExecuteMultiShard ` +
  1126  			`sharded.20-: prefix mid1, mid3 suffix ` +
  1127  			`{_c1_0: type:INT64 value:"4" _c1_1: type:INT64 value:"5" _c1_2: type:INT64 value:"6" ` +
  1128  			`_c2_0: type:INT64 value:"7" _c2_1: type:INT64 value:"8" _c2_2: type:INT64 value:"9" ` +
  1129  			`_c3_0: type:INT64 value:"10" _c3_1: type:INT64 value:"11" _c3_2: type:INT64 value:"12" ` +
  1130  			`_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
  1131  			`sharded.-20: prefix mid2 suffix ` +
  1132  			`{_c1_0: type:INT64 value:"4" _c1_1: type:INT64 value:"5" _c1_2: type:INT64 value:"6" ` +
  1133  			`_c2_0: type:INT64 value:"7" _c2_1: type:INT64 value:"8" _c2_2: type:INT64 value:"9" ` +
  1134  			`_c3_0: type:INT64 value:"10" _c3_1: type:INT64 value:"11" _c3_2: type:INT64 value:"12" ` +
  1135  			`_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
  1136  			`true false`,
  1137  	})
  1138  }
  1139  
  1140  func TestInsertShardedIgnoreUnownedVerify(t *testing.T) {
  1141  	invschema := &vschemapb.SrvVSchema{
  1142  		Keyspaces: map[string]*vschemapb.Keyspace{
  1143  			"sharded": {
  1144  				Sharded: true,
  1145  				Vindexes: map[string]*vschemapb.Vindex{
  1146  					"hash": {
  1147  						Type: "hash",
  1148  					},
  1149  					"onecol": {
  1150  						Type: "lookup",
  1151  						Params: map[string]string{
  1152  							"table": "lkp1",
  1153  							"from":  "from",
  1154  							"to":    "toc",
  1155  						},
  1156  					},
  1157  				},
  1158  				Tables: map[string]*vschemapb.Table{
  1159  					"t1": {
  1160  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1161  							Name:    "hash",
  1162  							Columns: []string{"id"},
  1163  						}, {
  1164  							Name:    "onecol",
  1165  							Columns: []string{"c3"},
  1166  						}},
  1167  					},
  1168  				},
  1169  			},
  1170  		},
  1171  	}
  1172  	vs := vindexes.BuildVSchema(invschema)
  1173  	ks := vs.Keyspaces["sharded"]
  1174  
  1175  	ins := NewInsert(
  1176  		InsertSharded,
  1177  		true,
  1178  		ks.Keyspace,
  1179  		[][][]evalengine.Expr{{
  1180  			// colVindex columns: id
  1181  			{
  1182  				// rows for id
  1183  				evalengine.NewLiteralInt(1),
  1184  				evalengine.NewLiteralInt(2),
  1185  				evalengine.NewLiteralInt(3),
  1186  			},
  1187  		}, {
  1188  			// colVindex columns: c3
  1189  			{
  1190  				// rows for c3
  1191  				evalengine.NewLiteralInt(10),
  1192  				evalengine.NewLiteralInt(11),
  1193  				evalengine.NewLiteralInt(12),
  1194  			},
  1195  		}},
  1196  		ks.Tables["t1"],
  1197  		"prefix",
  1198  		[]string{" mid1", " mid2", " mid3"},
  1199  		" suffix",
  1200  	)
  1201  
  1202  	// nonemptyResult will cause the lookup verify queries to succeed.
  1203  	nonemptyResult := sqltypes.MakeTestResult(
  1204  		sqltypes.MakeTestFields(
  1205  			"c1",
  1206  			"int64",
  1207  		),
  1208  		"1",
  1209  	)
  1210  
  1211  	vc := newDMLTestVCursor("-20", "20-")
  1212  	vc.shardForKsid = []string{"20-", "-20"}
  1213  	vc.results = []*sqltypes.Result{
  1214  		nonemptyResult,
  1215  		// fail verification of second row.
  1216  		{},
  1217  		nonemptyResult,
  1218  	}
  1219  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1220  	if err != nil {
  1221  		t.Fatal(err)
  1222  	}
  1223  	vc.ExpectLog(t, []string{
  1224  		// Perform verification for each colvindex.
  1225  		// Note that only first column of each colvindex is used.
  1226  		`Execute select from from lkp1 where from = :from and toc = :toc from: type:INT64 value:"10" toc: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" false`,
  1227  		`Execute select from from lkp1 where from = :from and toc = :toc from: type:INT64 value:"11" toc: type:VARBINARY value:"\x06\xe7\xea\"Βp\x8f" false`,
  1228  		`Execute select from from lkp1 where from = :from and toc = :toc from: type:INT64 value:"12" toc: type:VARBINARY value:"N\xb1\x90ɢ\xfa\x16\x9c" false`,
  1229  		// Based on shardForKsid, values returned will be 20-, -20.
  1230  		`ResolveDestinations sharded [value:"0" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(4eb190c9a2fa169c)`,
  1231  		`ExecuteMultiShard ` +
  1232  			`sharded.20-: prefix mid1 suffix ` +
  1233  			`{_c3_0: type:INT64 value:"10" _c3_2: type:INT64 value:"12" ` +
  1234  			`_id_0: type:INT64 value:"1" _id_2: type:INT64 value:"3"} ` +
  1235  			`sharded.-20: prefix mid3 suffix ` +
  1236  			`{_c3_0: type:INT64 value:"10" _c3_2: type:INT64 value:"12" ` +
  1237  			`_id_0: type:INT64 value:"1" _id_2: type:INT64 value:"3"} ` +
  1238  			`true false`,
  1239  	})
  1240  }
  1241  
  1242  func TestInsertShardedIgnoreUnownedVerifyFail(t *testing.T) {
  1243  	invschema := &vschemapb.SrvVSchema{
  1244  		Keyspaces: map[string]*vschemapb.Keyspace{
  1245  			"sharded": {
  1246  				Sharded: true,
  1247  				Vindexes: map[string]*vschemapb.Vindex{
  1248  					"hash": {
  1249  						Type: "hash",
  1250  					},
  1251  					"onecol": {
  1252  						Type: "lookup",
  1253  						Params: map[string]string{
  1254  							"table": "lkp1",
  1255  							"from":  "from",
  1256  							"to":    "toc",
  1257  						},
  1258  					},
  1259  				},
  1260  				Tables: map[string]*vschemapb.Table{
  1261  					"t1": {
  1262  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1263  							Name:    "hash",
  1264  							Columns: []string{"id"},
  1265  						}, {
  1266  							Name:    "onecol",
  1267  							Columns: []string{"c3"},
  1268  						}},
  1269  					},
  1270  				},
  1271  			},
  1272  		},
  1273  	}
  1274  	vs := vindexes.BuildVSchema(invschema)
  1275  	ks := vs.Keyspaces["sharded"]
  1276  
  1277  	ins := NewInsert(
  1278  		InsertSharded,
  1279  		false,
  1280  		ks.Keyspace,
  1281  		[][][]evalengine.Expr{{
  1282  			// colVindex columns: id
  1283  			{
  1284  				// rows for id
  1285  				evalengine.NewLiteralInt(1),
  1286  			},
  1287  		}, {
  1288  			// colVindex columns: c3
  1289  			{
  1290  				// rows for c3
  1291  				evalengine.NewLiteralInt(2),
  1292  			},
  1293  		}},
  1294  		ks.Tables["t1"],
  1295  		"prefix",
  1296  		[]string{" mid1", " mid2", " mid3"},
  1297  		" suffix",
  1298  	)
  1299  
  1300  	vc := newDMLTestVCursor("-20", "20-")
  1301  
  1302  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1303  	require.EqualError(t, err, `values [[INT64(2)]] for column [c3] does not map to keyspace ids`)
  1304  }
  1305  
  1306  func TestInsertShardedUnownedReverseMap(t *testing.T) {
  1307  	invschema := &vschemapb.SrvVSchema{
  1308  		Keyspaces: map[string]*vschemapb.Keyspace{
  1309  			"sharded": {
  1310  				Sharded: true,
  1311  				Vindexes: map[string]*vschemapb.Vindex{
  1312  					"hash": {
  1313  						Type: "hash",
  1314  					},
  1315  					"twocol": {
  1316  						Type: "lookup",
  1317  						Params: map[string]string{
  1318  							"table": "lkp2",
  1319  							"from":  "from1,from2",
  1320  							"to":    "toc",
  1321  						},
  1322  					},
  1323  					"onecol": {
  1324  						Type: "lookup",
  1325  						Params: map[string]string{
  1326  							"table": "lkp1",
  1327  							"from":  "from",
  1328  							"to":    "toc",
  1329  						},
  1330  					},
  1331  				},
  1332  				Tables: map[string]*vschemapb.Table{
  1333  					"t1": {
  1334  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1335  							Name:    "hash",
  1336  							Columns: []string{"id"},
  1337  						}, {
  1338  							Name:    "hash",
  1339  							Columns: []string{"c1", "c2"},
  1340  						}, {
  1341  							Name:    "hash",
  1342  							Columns: []string{"c3"},
  1343  						}},
  1344  					},
  1345  				},
  1346  			},
  1347  		},
  1348  	}
  1349  	vs := vindexes.BuildVSchema(invschema)
  1350  	ks := vs.Keyspaces["sharded"]
  1351  
  1352  	ins := NewInsert(
  1353  		InsertSharded,
  1354  		false,
  1355  		ks.Keyspace,
  1356  		[][][]evalengine.Expr{{
  1357  			// colVindex columns: id
  1358  			{
  1359  				// rows for id
  1360  				evalengine.NewLiteralInt(1),
  1361  				evalengine.NewLiteralInt(2),
  1362  				evalengine.NewLiteralInt(3),
  1363  			},
  1364  		}, {
  1365  			// colVindex columns: c1, c2
  1366  			{
  1367  				// rows for c1
  1368  				evalengine.NullExpr,
  1369  				evalengine.NullExpr,
  1370  				evalengine.NullExpr,
  1371  			},
  1372  			{
  1373  				// rows for c2
  1374  				evalengine.NullExpr,
  1375  				evalengine.NullExpr,
  1376  				evalengine.NullExpr,
  1377  			},
  1378  		}, {
  1379  			// colVindex columns: c3
  1380  			{
  1381  				// rows for c3
  1382  				evalengine.NullExpr,
  1383  				evalengine.NullExpr,
  1384  				evalengine.NullExpr,
  1385  			},
  1386  		}},
  1387  		ks.Tables["t1"],
  1388  		"prefix",
  1389  		[]string{" mid1", " mid2", " mid3"},
  1390  		" suffix",
  1391  	)
  1392  
  1393  	// nonemptyResult will cause the lookup verify queries to succeed.
  1394  	nonemptyResult := sqltypes.MakeTestResult(
  1395  		sqltypes.MakeTestFields(
  1396  			"c1",
  1397  			"int64",
  1398  		),
  1399  		"1",
  1400  	)
  1401  
  1402  	vc := newDMLTestVCursor("-20", "20-")
  1403  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  1404  	vc.results = []*sqltypes.Result{
  1405  		nonemptyResult,
  1406  	}
  1407  
  1408  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1409  	if err != nil {
  1410  		t.Fatal(err)
  1411  	}
  1412  	vc.ExpectLog(t, []string{
  1413  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
  1414  		`ExecuteMultiShard ` +
  1415  			`sharded.20-: prefix mid1, mid3 suffix ` +
  1416  			`{_c1_0: type:UINT64 value:"1" _c1_1: type:UINT64 value:"2" _c1_2: type:UINT64 value:"3" ` +
  1417  			`_c2_0:  _c2_1:  _c2_2:  ` +
  1418  			`_c3_0: type:UINT64 value:"1" _c3_1: type:UINT64 value:"2" _c3_2: type:UINT64 value:"3" ` +
  1419  			`_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
  1420  			`sharded.-20: prefix mid2 suffix ` +
  1421  			`{_c1_0: type:UINT64 value:"1" _c1_1: type:UINT64 value:"2" _c1_2: type:UINT64 value:"3" ` +
  1422  			`_c2_0:  _c2_1:  _c2_2:  ` +
  1423  			`_c3_0: type:UINT64 value:"1" _c3_1: type:UINT64 value:"2" _c3_2: type:UINT64 value:"3" ` +
  1424  			`_id_0: type:INT64 value:"1" _id_1: type:INT64 value:"2" _id_2: type:INT64 value:"3"} ` +
  1425  			`true false`,
  1426  	})
  1427  }
  1428  
  1429  func TestInsertShardedUnownedReverseMapSuccess(t *testing.T) {
  1430  	invschema := &vschemapb.SrvVSchema{
  1431  		Keyspaces: map[string]*vschemapb.Keyspace{
  1432  			"sharded": {
  1433  				Sharded: true,
  1434  				Vindexes: map[string]*vschemapb.Vindex{
  1435  					"hash": {
  1436  						Type: "hash",
  1437  					},
  1438  					"onecol": {
  1439  						Type: "lookup",
  1440  						Params: map[string]string{
  1441  							"table": "lkp1",
  1442  							"from":  "from",
  1443  							"to":    "toc",
  1444  						},
  1445  					},
  1446  				},
  1447  				Tables: map[string]*vschemapb.Table{
  1448  					"t1": {
  1449  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1450  							Name:    "hash",
  1451  							Columns: []string{"id"},
  1452  						}, {
  1453  							Name:    "onecol",
  1454  							Columns: []string{"c3"},
  1455  						}},
  1456  					},
  1457  				},
  1458  			},
  1459  		},
  1460  	}
  1461  	vs := vindexes.BuildVSchema(invschema)
  1462  	ks := vs.Keyspaces["sharded"]
  1463  
  1464  	ins := NewInsert(
  1465  		InsertSharded,
  1466  		false,
  1467  		ks.Keyspace,
  1468  		[][][]evalengine.Expr{{
  1469  			// colVindex columns: id
  1470  			{
  1471  				// rows for id
  1472  				evalengine.NewLiteralInt(1),
  1473  			},
  1474  		}, {
  1475  			// colVindex columns: c3
  1476  			{
  1477  				// rows for c3
  1478  				evalengine.NullExpr,
  1479  			},
  1480  		}},
  1481  		ks.Tables["t1"],
  1482  		"prefix",
  1483  		[]string{" mid1", " mid2", " mid3"},
  1484  		" suffix",
  1485  	)
  1486  
  1487  	vc := newDMLTestVCursor("-20", "20-")
  1488  
  1489  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1490  	require.NoError(t, err)
  1491  }
  1492  
  1493  func TestInsertSelectSimple(t *testing.T) {
  1494  	invschema := &vschemapb.SrvVSchema{
  1495  		Keyspaces: map[string]*vschemapb.Keyspace{
  1496  			"sharded": {
  1497  				Sharded: true,
  1498  				Vindexes: map[string]*vschemapb.Vindex{
  1499  					"hash": {Type: "hash"}},
  1500  				Tables: map[string]*vschemapb.Table{
  1501  					"t1": {
  1502  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1503  							Name:    "hash",
  1504  							Columns: []string{"id"}}}}}}}}
  1505  
  1506  	vs := vindexes.BuildVSchema(invschema)
  1507  	ks := vs.Keyspaces["sharded"]
  1508  
  1509  	// A single row insert should be autocommitted
  1510  	ins := &Insert{
  1511  		Opcode:            InsertSelect,
  1512  		Keyspace:          ks.Keyspace,
  1513  		Query:             "dummy_insert",
  1514  		Table:             ks.Tables["t1"],
  1515  		VindexValueOffset: [][]int{{1}},
  1516  		Input: &Route{
  1517  			Query:      "dummy_select",
  1518  			FieldQuery: "dummy_field_query",
  1519  			RoutingParameters: &RoutingParameters{
  1520  				Opcode:   Scatter,
  1521  				Keyspace: ks.Keyspace}}}
  1522  
  1523  	ins.ColVindexes = append(ins.ColVindexes, ks.Tables["t1"].ColumnVindexes...)
  1524  	ins.Prefix = "prefix "
  1525  	ins.Suffix = " suffix"
  1526  
  1527  	vc := newDMLTestVCursor("-20", "20-")
  1528  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  1529  	vc.results = []*sqltypes.Result{
  1530  		sqltypes.MakeTestResult(
  1531  			sqltypes.MakeTestFields(
  1532  				"name|id",
  1533  				"varchar|int64"),
  1534  			"a|1",
  1535  			"a|3",
  1536  			"b|2")}
  1537  
  1538  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1539  	require.NoError(t, err)
  1540  	vc.ExpectLog(t, []string{
  1541  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  1542  
  1543  		// the select query
  1544  		`ExecuteMultiShard sharded.-20: dummy_select {} sharded.20-: dummy_select {} false false`,
  1545  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(4eb190c9a2fa169c),DestinationKeyspaceID(06e7ea22ce92708f)`,
  1546  
  1547  		// two rows go to the 20- shard, and one row go to the -20 shard
  1548  		`ExecuteMultiShard ` +
  1549  			`sharded.20-: prefix values (:_c0_0, :_c0_1), (:_c2_0, :_c2_1) suffix ` +
  1550  			`{_c0_0: type:VARCHAR value:"a" _c0_1: type:INT64 value:"1"` +
  1551  			` _c2_0: type:VARCHAR value:"b" _c2_1: type:INT64 value:"2"} ` +
  1552  			`sharded.-20: prefix values (:_c1_0, :_c1_1) suffix` +
  1553  			` {_c1_0: type:VARCHAR value:"a" _c1_1: type:INT64 value:"3"} true false`})
  1554  
  1555  	vc.Rewind()
  1556  	err = ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  1557  		return nil
  1558  	})
  1559  	require.NoError(t, err)
  1560  	vc.ExpectLog(t, []string{
  1561  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  1562  
  1563  		// the select query
  1564  		`StreamExecuteMulti dummy_select sharded.-20: {} sharded.20-: {} `,
  1565  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(4eb190c9a2fa169c),DestinationKeyspaceID(06e7ea22ce92708f)`,
  1566  
  1567  		// two rows go to the 20- shard, and one row go to the -20 shard
  1568  		`ExecuteMultiShard ` +
  1569  			`sharded.20-: prefix values (:_c0_0, :_c0_1), (:_c2_0, :_c2_1) suffix ` +
  1570  			`{_c0_0: type:VARCHAR value:"a" _c0_1: type:INT64 value:"1"` +
  1571  			` _c2_0: type:VARCHAR value:"b" _c2_1: type:INT64 value:"2"} ` +
  1572  			`sharded.-20: prefix values (:_c1_0, :_c1_1) suffix` +
  1573  			` {_c1_0: type:VARCHAR value:"a" _c1_1: type:INT64 value:"3"} true false`})
  1574  }
  1575  
  1576  func TestInsertSelectOwned(t *testing.T) {
  1577  	invschema := &vschemapb.SrvVSchema{
  1578  		Keyspaces: map[string]*vschemapb.Keyspace{
  1579  			"sharded": {
  1580  				Sharded: true,
  1581  				Vindexes: map[string]*vschemapb.Vindex{
  1582  					"hash": {Type: "hash"},
  1583  					"onecol": {
  1584  						Type: "lookup",
  1585  						Params: map[string]string{
  1586  							"table": "lkp1",
  1587  							"from":  "from",
  1588  							"to":    "toc"},
  1589  						Owner: "t1"}},
  1590  				Tables: map[string]*vschemapb.Table{
  1591  					"t1": {
  1592  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1593  							Name:    "hash",
  1594  							Columns: []string{"id"}}, {
  1595  							Name:    "onecol",
  1596  							Columns: []string{"c3"}}}}}}}}
  1597  
  1598  	vs := vindexes.BuildVSchema(invschema)
  1599  	ks := vs.Keyspaces["sharded"]
  1600  
  1601  	ins := &Insert{
  1602  		Opcode:   InsertSelect,
  1603  		Keyspace: ks.Keyspace,
  1604  		Query:    "dummy_insert",
  1605  		Table:    ks.Tables["t1"],
  1606  		VindexValueOffset: [][]int{
  1607  			{1},  // The primary vindex has a single column as sharding key
  1608  			{0}}, // the onecol vindex uses the 'name' column
  1609  		Input: &Route{
  1610  			Query:      "dummy_select",
  1611  			FieldQuery: "dummy_field_query",
  1612  			RoutingParameters: &RoutingParameters{
  1613  				Opcode:   Scatter,
  1614  				Keyspace: ks.Keyspace}}}
  1615  
  1616  	ins.ColVindexes = append(ins.ColVindexes, ks.Tables["t1"].ColumnVindexes...)
  1617  	ins.Prefix = "prefix "
  1618  	ins.Suffix = " suffix"
  1619  
  1620  	vc := newDMLTestVCursor("-20", "20-")
  1621  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  1622  	vc.results = []*sqltypes.Result{
  1623  		sqltypes.MakeTestResult(
  1624  			sqltypes.MakeTestFields(
  1625  				"name|id",
  1626  				"varchar|int64"),
  1627  			"a|1",
  1628  			"a|3",
  1629  			"b|2")}
  1630  
  1631  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1632  	require.NoError(t, err)
  1633  	vc.ExpectLog(t, []string{
  1634  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  1635  
  1636  		// the select query
  1637  		`ExecuteMultiShard sharded.-20: dummy_select {} sharded.20-: dummy_select {} false false`,
  1638  
  1639  		// insert values into the owned lookup vindex
  1640  		`Execute insert into lkp1(from, toc) values(:from_0, :toc_0), (:from_1, :toc_1), (:from_2, :toc_2) from_0: type:VARCHAR value:"a" from_1: type:VARCHAR value:"a" from_2: type:VARCHAR value:"b" toc_0: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" toc_1: type:VARBINARY value:"N\xb1\x90ɢ\xfa\x16\x9c" toc_2: type:VARBINARY value:"\x06\xe7\xea\"Βp\x8f" true`,
  1641  
  1642  		// Values 0 1 2 come from the id column
  1643  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(4eb190c9a2fa169c),DestinationKeyspaceID(06e7ea22ce92708f)`,
  1644  
  1645  		// insert values into the main table
  1646  		`ExecuteMultiShard ` +
  1647  			// first we insert two rows on the 20- shard
  1648  			`sharded.20-: prefix values (:_c0_0, :_c0_1), (:_c2_0, :_c2_1) suffix ` +
  1649  			`{_c0_0: type:VARCHAR value:"a" _c0_1: type:INT64 value:"1" _c2_0: type:VARCHAR value:"b" _c2_1: type:INT64 value:"2"} ` +
  1650  
  1651  			// next we insert one row on the -20 shard
  1652  			`sharded.-20: prefix values (:_c1_0, :_c1_1) suffix ` +
  1653  			`{_c1_0: type:VARCHAR value:"a" _c1_1: type:INT64 value:"3"} ` +
  1654  			`true false`})
  1655  
  1656  	vc.Rewind()
  1657  	err = ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  1658  		return nil
  1659  	})
  1660  	require.NoError(t, err)
  1661  	vc.ExpectLog(t, []string{
  1662  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  1663  
  1664  		// the select query
  1665  		`StreamExecuteMulti dummy_select sharded.-20: {} sharded.20-: {} `,
  1666  
  1667  		// insert values into the owned lookup vindex
  1668  		`Execute insert into lkp1(from, toc) values(:from_0, :toc_0), (:from_1, :toc_1), (:from_2, :toc_2) from_0: type:VARCHAR value:"a" from_1: type:VARCHAR value:"a" from_2: type:VARCHAR value:"b" toc_0: type:VARBINARY value:"\x16k@\xb4J\xbaK\xd6" toc_1: type:VARBINARY value:"N\xb1\x90ɢ\xfa\x16\x9c" toc_2: type:VARBINARY value:"\x06\xe7\xea\"Βp\x8f" true`,
  1669  
  1670  		// Values 0 1 2 come from the id column
  1671  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(4eb190c9a2fa169c),DestinationKeyspaceID(06e7ea22ce92708f)`,
  1672  
  1673  		// insert values into the main table
  1674  		`ExecuteMultiShard ` +
  1675  			// first we insert two rows on the 20- shard
  1676  			`sharded.20-: prefix values (:_c0_0, :_c0_1), (:_c2_0, :_c2_1) suffix ` +
  1677  			`{_c0_0: type:VARCHAR value:"a" _c0_1: type:INT64 value:"1" _c2_0: type:VARCHAR value:"b" _c2_1: type:INT64 value:"2"} ` +
  1678  
  1679  			// next we insert one row on the -20 shard
  1680  			`sharded.-20: prefix values (:_c1_0, :_c1_1) suffix ` +
  1681  			`{_c1_0: type:VARCHAR value:"a" _c1_1: type:INT64 value:"3"} ` +
  1682  			`true false`})
  1683  }
  1684  
  1685  func TestInsertSelectGenerate(t *testing.T) {
  1686  	invschema := &vschemapb.SrvVSchema{
  1687  		Keyspaces: map[string]*vschemapb.Keyspace{
  1688  			"sharded": {
  1689  				Sharded: true,
  1690  				Vindexes: map[string]*vschemapb.Vindex{
  1691  					"hash": {
  1692  						Type: "hash"}},
  1693  				Tables: map[string]*vschemapb.Table{
  1694  					"t1": {
  1695  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1696  							Name:    "hash",
  1697  							Columns: []string{"id"}}}}}}}}
  1698  
  1699  	vs := vindexes.BuildVSchema(invschema)
  1700  	ks := vs.Keyspaces["sharded"]
  1701  
  1702  	ins := &Insert{
  1703  		Opcode:   InsertSelect,
  1704  		Keyspace: ks.Keyspace,
  1705  		Query:    "dummy_insert",
  1706  		Table:    ks.Tables["t1"],
  1707  		VindexValueOffset: [][]int{
  1708  			{1}}, // The primary vindex has a single column as sharding key
  1709  		Input: &Route{
  1710  			Query:      "dummy_select",
  1711  			FieldQuery: "dummy_field_query",
  1712  			RoutingParameters: &RoutingParameters{
  1713  				Opcode:   Scatter,
  1714  				Keyspace: ks.Keyspace}}}
  1715  
  1716  	ins.Generate = &Generate{
  1717  		Keyspace: &vindexes.Keyspace{
  1718  			Name:    "ks2",
  1719  			Sharded: false,
  1720  		},
  1721  		Query:  "dummy_generate",
  1722  		Offset: 1,
  1723  	}
  1724  	ins.Prefix = "prefix "
  1725  	ins.Suffix = " suffix"
  1726  
  1727  	vc := newDMLTestVCursor("-20", "20-")
  1728  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  1729  	vc.results = []*sqltypes.Result{
  1730  		// This is the result from the input SELECT
  1731  		sqltypes.MakeTestResult(
  1732  			sqltypes.MakeTestFields(
  1733  				"name|id",
  1734  				"varchar|int64"),
  1735  			"a|1",
  1736  			"a|null",
  1737  			"b|null"),
  1738  		// This is the result for the sequence query
  1739  		sqltypes.MakeTestResult(
  1740  			sqltypes.MakeTestFields(
  1741  				"nextval",
  1742  				"int64",
  1743  			),
  1744  			"2",
  1745  		),
  1746  		{InsertID: 1},
  1747  	}
  1748  
  1749  	result, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1750  	require.NoError(t, err)
  1751  	vc.ExpectLog(t, []string{
  1752  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  1753  		// this is the input query
  1754  		`ExecuteMultiShard sharded.-20: dummy_select {} sharded.20-: dummy_select {} false false`,
  1755  		`ResolveDestinations ks2 [] Destinations:DestinationAnyShard()`,
  1756  
  1757  		// this is the sequence table query
  1758  		`ExecuteStandalone dummy_generate n: type:INT64 value:"2" ks2 -20`,
  1759  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
  1760  		`ExecuteMultiShard ` +
  1761  			// first we send the insert to the 20- shard
  1762  			`sharded.20-: prefix values (:_c0_0, :_c0_1), (:_c2_0, :_c2_1) suffix ` +
  1763  			`{_c0_0: type:VARCHAR value:"a" ` +
  1764  			`_c0_1: type:INT64 value:"1" ` +
  1765  			`_c2_0: type:VARCHAR value:"b" ` +
  1766  			`_c2_1: type:INT64 value:"3"} ` +
  1767  			// next we send the insert to the -20 shard
  1768  			`sharded.-20: prefix values (:_c1_0, :_c1_1) suffix ` +
  1769  			`{_c1_0: type:VARCHAR value:"a" _c1_1: type:INT64 value:"2"} ` +
  1770  			`true false`,
  1771  	})
  1772  
  1773  	// The insert id returned by ExecuteMultiShard should be overwritten by processGenerateFromValues.
  1774  	expectResult(t, "Execute", result, &sqltypes.Result{InsertID: 2})
  1775  }
  1776  
  1777  func TestStreamingInsertSelectGenerate(t *testing.T) {
  1778  	invschema := &vschemapb.SrvVSchema{
  1779  		Keyspaces: map[string]*vschemapb.Keyspace{
  1780  			"sharded": {
  1781  				Sharded: true,
  1782  				Vindexes: map[string]*vschemapb.Vindex{
  1783  					"hash": {
  1784  						Type: "hash"}},
  1785  				Tables: map[string]*vschemapb.Table{
  1786  					"t1": {
  1787  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1788  							Name:    "hash",
  1789  							Columns: []string{"id"}}}}}}}}
  1790  
  1791  	vs := vindexes.BuildVSchema(invschema)
  1792  	ks := vs.Keyspaces["sharded"]
  1793  
  1794  	ins := &Insert{
  1795  		Opcode:   InsertSelect,
  1796  		Keyspace: ks.Keyspace,
  1797  		Query:    "dummy_insert",
  1798  		Table:    ks.Tables["t1"],
  1799  		VindexValueOffset: [][]int{
  1800  			{1}}, // The primary vindex has a single column as sharding key
  1801  		Input: &Route{
  1802  			Query:      "dummy_select",
  1803  			FieldQuery: "dummy_field_query",
  1804  			RoutingParameters: &RoutingParameters{
  1805  				Opcode:   Scatter,
  1806  				Keyspace: ks.Keyspace}}}
  1807  
  1808  	ins.Generate = &Generate{
  1809  		Keyspace: &vindexes.Keyspace{
  1810  			Name:    "ks2",
  1811  			Sharded: false,
  1812  		},
  1813  		Query:  "dummy_generate",
  1814  		Offset: 1,
  1815  	}
  1816  	ins.Prefix = "prefix "
  1817  	ins.Suffix = " suffix"
  1818  
  1819  	vc := newDMLTestVCursor("-20", "20-")
  1820  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  1821  	vc.results = []*sqltypes.Result{
  1822  		// This is the result from the input SELECT
  1823  		sqltypes.MakeTestResult(
  1824  			sqltypes.MakeTestFields(
  1825  				"name|id",
  1826  				"varchar|int64"),
  1827  			"a|1",
  1828  			"a|null",
  1829  			"b|null"),
  1830  		// This is the result for the sequence query
  1831  		sqltypes.MakeTestResult(
  1832  			sqltypes.MakeTestFields(
  1833  				"nextval",
  1834  				"int64",
  1835  			),
  1836  			"2",
  1837  		),
  1838  		{InsertID: 1},
  1839  	}
  1840  
  1841  	var output *sqltypes.Result
  1842  	err := ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  1843  		output = result
  1844  		return nil
  1845  	})
  1846  	require.NoError(t, err)
  1847  	vc.ExpectLog(t, []string{
  1848  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  1849  		// this is the input query
  1850  		`StreamExecuteMulti dummy_select sharded.-20: {} sharded.20-: {} `,
  1851  		`ResolveDestinations ks2 [] Destinations:DestinationAnyShard()`,
  1852  
  1853  		// this is the sequence table query
  1854  		`ExecuteStandalone dummy_generate n: type:INT64 value:"2" ks2 -20`,
  1855  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
  1856  		`ExecuteMultiShard ` +
  1857  			// first we send the insert to the 20- shard
  1858  			`sharded.20-: prefix values (:_c0_0, :_c0_1), (:_c2_0, :_c2_1) suffix ` +
  1859  			`{_c0_0: type:VARCHAR value:"a" ` +
  1860  			`_c0_1: type:INT64 value:"1" ` +
  1861  			`_c2_0: type:VARCHAR value:"b" ` +
  1862  			`_c2_1: type:INT64 value:"3"} ` +
  1863  			// next we send the insert to the -20 shard
  1864  			`sharded.-20: prefix values (:_c1_0, :_c1_1) suffix ` +
  1865  			`{_c1_0: type:VARCHAR value:"a" _c1_1: type:INT64 value:"2"} ` +
  1866  			`true false`,
  1867  	})
  1868  
  1869  	// The insert id returned by ExecuteMultiShard should be overwritten by processGenerateFromValues.
  1870  	expectResult(t, "Execute", output, &sqltypes.Result{InsertID: 2})
  1871  }
  1872  
  1873  func TestInsertSelectGenerateNotProvided(t *testing.T) {
  1874  	invschema := &vschemapb.SrvVSchema{
  1875  		Keyspaces: map[string]*vschemapb.Keyspace{
  1876  			"sharded": {
  1877  				Sharded: true,
  1878  				Vindexes: map[string]*vschemapb.Vindex{
  1879  					"hash": {
  1880  						Type: "hash"}},
  1881  				Tables: map[string]*vschemapb.Table{
  1882  					"t1": {
  1883  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1884  							Name:    "hash",
  1885  							Columns: []string{"id"}}}}}}}}
  1886  
  1887  	vs := vindexes.BuildVSchema(invschema)
  1888  	ks := vs.Keyspaces["sharded"]
  1889  
  1890  	ins := &Insert{
  1891  		Opcode:   InsertSelect,
  1892  		Keyspace: ks.Keyspace,
  1893  		Query:    "dummy_insert",
  1894  		Table:    ks.Tables["t1"],
  1895  		VindexValueOffset: [][]int{
  1896  			{1}}, // The primary vindex has a single column as sharding key
  1897  		Input: &Route{
  1898  			Query:      "dummy_select",
  1899  			FieldQuery: "dummy_field_query",
  1900  			RoutingParameters: &RoutingParameters{
  1901  				Opcode:   Scatter,
  1902  				Keyspace: ks.Keyspace}}}
  1903  
  1904  	ins.Generate = &Generate{
  1905  		Keyspace: &vindexes.Keyspace{
  1906  			Name:    "ks2",
  1907  			Sharded: false,
  1908  		},
  1909  		Query:  "dummy_generate",
  1910  		Offset: 2,
  1911  	}
  1912  	ins.Prefix = "prefix "
  1913  	ins.Suffix = " suffix"
  1914  
  1915  	vc := newDMLTestVCursor("-20", "20-")
  1916  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  1917  	vc.results = []*sqltypes.Result{
  1918  		// This is the result from the input SELECT
  1919  		sqltypes.MakeTestResult(
  1920  			sqltypes.MakeTestFields(
  1921  				"name|id",
  1922  				"varchar|int64"),
  1923  			"a|1",
  1924  			"a|2",
  1925  			"b|3"),
  1926  		// This is the result for the sequence query
  1927  		sqltypes.MakeTestResult(
  1928  			sqltypes.MakeTestFields(
  1929  				"nextval",
  1930  				"int64",
  1931  			),
  1932  			"10",
  1933  		),
  1934  		{InsertID: 1},
  1935  	}
  1936  
  1937  	result, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1938  	require.NoError(t, err)
  1939  	vc.ExpectLog(t, []string{
  1940  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  1941  		// this is the input query
  1942  		`ExecuteMultiShard sharded.-20: dummy_select {} sharded.20-: dummy_select {} false false`,
  1943  		`ResolveDestinations ks2 [] Destinations:DestinationAnyShard()`,
  1944  
  1945  		// this is the sequence table query
  1946  		`ExecuteStandalone dummy_generate n: type:INT64 value:"3" ks2 -20`,
  1947  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
  1948  		`ExecuteMultiShard ` +
  1949  			`sharded.20-: prefix values (:_c0_0, :_c0_1, :_c0_2), (:_c2_0, :_c2_1, :_c2_2) suffix ` +
  1950  			`{_c0_0: type:VARCHAR value:"a" _c0_1: type:INT64 value:"1" _c0_2: type:INT64 value:"10" ` +
  1951  			`_c2_0: type:VARCHAR value:"b" _c2_1: type:INT64 value:"3" _c2_2: type:INT64 value:"12"} ` +
  1952  			`sharded.-20: prefix values (:_c1_0, :_c1_1, :_c1_2) suffix ` +
  1953  			`{_c1_0: type:VARCHAR value:"a" _c1_1: type:INT64 value:"2" _c1_2: type:INT64 value:"11"} ` +
  1954  			`true false`,
  1955  	})
  1956  
  1957  	// The insert id returned by ExecuteMultiShard should be overwritten by processGenerateFromValues.
  1958  	expectResult(t, "Execute", result, &sqltypes.Result{InsertID: 10})
  1959  }
  1960  
  1961  func TestStreamingInsertSelectGenerateNotProvided(t *testing.T) {
  1962  	invschema := &vschemapb.SrvVSchema{
  1963  		Keyspaces: map[string]*vschemapb.Keyspace{
  1964  			"sharded": {
  1965  				Sharded: true,
  1966  				Vindexes: map[string]*vschemapb.Vindex{
  1967  					"hash": {
  1968  						Type: "hash"}},
  1969  				Tables: map[string]*vschemapb.Table{
  1970  					"t1": {
  1971  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  1972  							Name:    "hash",
  1973  							Columns: []string{"id"}}}}}}}}
  1974  
  1975  	vs := vindexes.BuildVSchema(invschema)
  1976  	ks := vs.Keyspaces["sharded"]
  1977  
  1978  	ins := &Insert{
  1979  		Opcode:   InsertSelect,
  1980  		Keyspace: ks.Keyspace,
  1981  		Query:    "dummy_insert",
  1982  		Table:    ks.Tables["t1"],
  1983  		VindexValueOffset: [][]int{
  1984  			{1}}, // The primary vindex has a single column as sharding key
  1985  		Input: &Route{
  1986  			Query:      "dummy_select",
  1987  			FieldQuery: "dummy_field_query",
  1988  			RoutingParameters: &RoutingParameters{
  1989  				Opcode:   Scatter,
  1990  				Keyspace: ks.Keyspace}}}
  1991  
  1992  	ins.Generate = &Generate{
  1993  		Keyspace: &vindexes.Keyspace{
  1994  			Name:    "ks2",
  1995  			Sharded: false,
  1996  		},
  1997  		Query:  "dummy_generate",
  1998  		Offset: 2,
  1999  	}
  2000  	ins.Prefix = "prefix "
  2001  	ins.Suffix = " suffix"
  2002  
  2003  	vc := newDMLTestVCursor("-20", "20-")
  2004  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  2005  	vc.results = []*sqltypes.Result{
  2006  		// This is the result from the input SELECT
  2007  		sqltypes.MakeTestResult(
  2008  			sqltypes.MakeTestFields(
  2009  				"name|id",
  2010  				"varchar|int64"),
  2011  			"a|1",
  2012  			"a|2",
  2013  			"b|3"),
  2014  		// This is the result for the sequence query
  2015  		sqltypes.MakeTestResult(
  2016  			sqltypes.MakeTestFields(
  2017  				"nextval",
  2018  				"int64",
  2019  			),
  2020  			"10",
  2021  		),
  2022  		{InsertID: 1},
  2023  	}
  2024  
  2025  	var output *sqltypes.Result
  2026  	err := ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  2027  		output = result
  2028  		return nil
  2029  	})
  2030  	require.NoError(t, err)
  2031  	vc.ExpectLog(t, []string{
  2032  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  2033  		// this is the input query
  2034  		`StreamExecuteMulti dummy_select sharded.-20: {} sharded.20-: {} `,
  2035  		`ResolveDestinations ks2 [] Destinations:DestinationAnyShard()`,
  2036  
  2037  		// this is the sequence table query
  2038  		`ExecuteStandalone dummy_generate n: type:INT64 value:"3" ks2 -20`,
  2039  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(4eb190c9a2fa169c)`,
  2040  		`ExecuteMultiShard ` +
  2041  			`sharded.20-: prefix values (:_c0_0, :_c0_1, :_c0_2), (:_c2_0, :_c2_1, :_c2_2) suffix ` +
  2042  			`{_c0_0: type:VARCHAR value:"a" _c0_1: type:INT64 value:"1" _c0_2: type:INT64 value:"10" ` +
  2043  			`_c2_0: type:VARCHAR value:"b" _c2_1: type:INT64 value:"3" _c2_2: type:INT64 value:"12"} ` +
  2044  			`sharded.-20: prefix values (:_c1_0, :_c1_1, :_c1_2) suffix ` +
  2045  			`{_c1_0: type:VARCHAR value:"a" _c1_1: type:INT64 value:"2" _c1_2: type:INT64 value:"11"} ` +
  2046  			`true false`,
  2047  	})
  2048  
  2049  	// The insert id returned by ExecuteMultiShard should be overwritten by processGenerateFromValues.
  2050  	expectResult(t, "Execute", output, &sqltypes.Result{InsertID: 10})
  2051  }
  2052  
  2053  func TestInsertSelectUnowned(t *testing.T) {
  2054  	invschema := &vschemapb.SrvVSchema{
  2055  		Keyspaces: map[string]*vschemapb.Keyspace{
  2056  			"sharded": {
  2057  				Sharded: true,
  2058  				Vindexes: map[string]*vschemapb.Vindex{
  2059  					"hash": {Type: "hash"},
  2060  					"onecol": {
  2061  						Type: "lookup_unique",
  2062  						Params: map[string]string{
  2063  							"table": "lkp1",
  2064  							"from":  "from",
  2065  							"to":    "toc"},
  2066  						Owner: "t1"}},
  2067  				Tables: map[string]*vschemapb.Table{
  2068  					"t2": {
  2069  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  2070  							Name:    "onecol",
  2071  							Columns: []string{"id"}}}}}}}}
  2072  
  2073  	vs := vindexes.BuildVSchema(invschema)
  2074  	ks := vs.Keyspaces["sharded"]
  2075  
  2076  	ins := &Insert{
  2077  		Opcode:   InsertSelect,
  2078  		Keyspace: ks.Keyspace,
  2079  		Query:    "dummy_insert",
  2080  		Table:    ks.Tables["t2"],
  2081  		VindexValueOffset: [][]int{
  2082  			{0}}, // the onecol vindex as unowned lookup sharding column
  2083  		Input: &Route{
  2084  			Query:      "dummy_select",
  2085  			FieldQuery: "dummy_field_query",
  2086  			RoutingParameters: &RoutingParameters{
  2087  				Opcode:   Scatter,
  2088  				Keyspace: ks.Keyspace}}}
  2089  
  2090  	ins.ColVindexes = append(ins.ColVindexes, ks.Tables["t2"].ColumnVindexes...)
  2091  	ins.Prefix = "prefix "
  2092  	ins.Suffix = " suffix"
  2093  
  2094  	vc := newDMLTestVCursor("-20", "20-")
  2095  	vc.shardForKsid = []string{"20-", "-20", "20-"}
  2096  	vc.results = []*sqltypes.Result{
  2097  		sqltypes.MakeTestResult(sqltypes.MakeTestFields("id", "int64"), "1", "3", "2"),
  2098  		sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|tocol", "int64|int64"), "1|1", "3|2", "2|3"),
  2099  	}
  2100  
  2101  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  2102  	require.NoError(t, err)
  2103  
  2104  	vc.ExpectLog(t, []string{
  2105  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  2106  
  2107  		// the select query
  2108  		`ExecuteMultiShard sharded.-20: dummy_select {} sharded.20-: dummy_select {} false false`,
  2109  
  2110  		// select values into the unowned lookup vindex for routing
  2111  		`Execute select from, toc from lkp1 where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"3"} values:{type:INT64 value:"2"} false`,
  2112  
  2113  		// values from lookup vindex resolved to destination
  2114  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(31),DestinationKeyspaceID(32),DestinationKeyspaceID(33)`,
  2115  
  2116  		// insert values into the main table
  2117  		`ExecuteMultiShard ` +
  2118  			// first we insert two rows on the 20- shard
  2119  			`sharded.20-: prefix values (:_c0_0), (:_c2_0) suffix ` +
  2120  			`{_c0_0: type:INT64 value:"1" _c2_0: type:INT64 value:"2"} ` +
  2121  
  2122  			// next we insert one row on the -20 shard
  2123  			`sharded.-20: prefix values (:_c1_0) suffix ` +
  2124  			`{_c1_0: type:INT64 value:"3"} ` +
  2125  			`true false`})
  2126  
  2127  	vc.Rewind()
  2128  	err = ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  2129  		return nil
  2130  	})
  2131  	require.NoError(t, err)
  2132  	vc.ExpectLog(t, []string{
  2133  		`ResolveDestinations sharded [] Destinations:DestinationAllShards()`,
  2134  
  2135  		// the select query
  2136  		`StreamExecuteMulti dummy_select sharded.-20: {} sharded.20-: {} `,
  2137  
  2138  		// select values into the unowned lookup vindex for routing
  2139  		`Execute select from, toc from lkp1 where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"3"} values:{type:INT64 value:"2"} false`,
  2140  
  2141  		// values from lookup vindex resolved to destination
  2142  		`ResolveDestinations sharded [value:"0" value:"1" value:"2"] Destinations:DestinationKeyspaceID(31),DestinationKeyspaceID(32),DestinationKeyspaceID(33)`,
  2143  
  2144  		// insert values into the main table
  2145  		`ExecuteMultiShard ` +
  2146  			// first we insert two rows on the 20- shard
  2147  			`sharded.20-: prefix values (:_c0_0), (:_c2_0) suffix ` +
  2148  			`{_c0_0: type:INT64 value:"1" _c2_0: type:INT64 value:"2"} ` +
  2149  
  2150  			// next we insert one row on the -20 shard
  2151  			`sharded.-20: prefix values (:_c1_0) suffix ` +
  2152  			`{_c1_0: type:INT64 value:"3"} ` +
  2153  			`true false`})
  2154  }
  2155  
  2156  func TestInsertSelectShardingCases(t *testing.T) {
  2157  	invschema := &vschemapb.SrvVSchema{
  2158  		Keyspaces: map[string]*vschemapb.Keyspace{
  2159  			"sks1": {
  2160  				Sharded:  true,
  2161  				Vindexes: map[string]*vschemapb.Vindex{"hash": {Type: "hash"}},
  2162  				Tables: map[string]*vschemapb.Table{
  2163  					"s1": {
  2164  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  2165  							Name:    "hash",
  2166  							Columns: []string{"id"}}}}}},
  2167  			"sks2": {
  2168  				Sharded:  true,
  2169  				Vindexes: map[string]*vschemapb.Vindex{"hash": {Type: "hash"}},
  2170  				Tables: map[string]*vschemapb.Table{
  2171  					"s2": {
  2172  						ColumnVindexes: []*vschemapb.ColumnVindex{{
  2173  							Name:    "hash",
  2174  							Columns: []string{"id"}}}}}},
  2175  			"uks1": {Tables: map[string]*vschemapb.Table{"u1": {}}},
  2176  			"uks2": {Tables: map[string]*vschemapb.Table{"u2": {}}},
  2177  		}}
  2178  
  2179  	vs := vindexes.BuildVSchema(invschema)
  2180  	sks1 := vs.Keyspaces["sks1"]
  2181  	sks2 := vs.Keyspaces["sks2"]
  2182  	uks1 := vs.Keyspaces["uks1"]
  2183  	uks2 := vs.Keyspaces["uks2"]
  2184  
  2185  	// sharded input route.
  2186  	sRoute := &Route{
  2187  		Query:             "dummy_select",
  2188  		FieldQuery:        "dummy_field_query",
  2189  		RoutingParameters: &RoutingParameters{Opcode: Scatter, Keyspace: sks2.Keyspace}}
  2190  
  2191  	// unsharded input route.
  2192  	uRoute := &Route{
  2193  		Query:             "dummy_select",
  2194  		FieldQuery:        "dummy_field_query",
  2195  		RoutingParameters: &RoutingParameters{Opcode: Unsharded, Keyspace: uks2.Keyspace}}
  2196  
  2197  	// sks1 and sks2
  2198  	ins := &Insert{
  2199  		Opcode:            InsertSelect,
  2200  		Keyspace:          sks1.Keyspace,
  2201  		Query:             "dummy_insert",
  2202  		Table:             sks1.Tables["s1"],
  2203  		Prefix:            "prefix ",
  2204  		Suffix:            " suffix",
  2205  		ColVindexes:       sks1.Tables["s1"].ColumnVindexes,
  2206  		VindexValueOffset: [][]int{{0}},
  2207  		Input:             sRoute,
  2208  	}
  2209  
  2210  	vc := &loggingVCursor{
  2211  		resolvedTargetTabletType: topodatapb.TabletType_PRIMARY,
  2212  		ksShardMap: map[string][]string{
  2213  			"sks1": {"-20", "20-"},
  2214  			"sks2": {"-20", "20-"},
  2215  			"uks1": {"0"},
  2216  			"uks2": {"0"},
  2217  		},
  2218  	}
  2219  	vc.results = []*sqltypes.Result{
  2220  		sqltypes.MakeTestResult(sqltypes.MakeTestFields("id", "int64"), "1")}
  2221  
  2222  	_, err := ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  2223  	require.NoError(t, err)
  2224  	vc.ExpectLog(t, []string{
  2225  		// the select query
  2226  		`ResolveDestinations sks2 [] Destinations:DestinationAllShards()`,
  2227  		`ExecuteMultiShard sks2.-20: dummy_select {} sks2.20-: dummy_select {} false false`,
  2228  
  2229  		// the query exec
  2230  		`ResolveDestinations sks1 [value:"0"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
  2231  		`ExecuteMultiShard sks1.-20: prefix values (:_c0_0) suffix {_c0_0: type:INT64 value:"1"} true true`})
  2232  
  2233  	vc.Rewind()
  2234  	err = ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  2235  		return nil
  2236  	})
  2237  	require.NoError(t, err)
  2238  	vc.ExpectLog(t, []string{
  2239  		// the select query
  2240  		`ResolveDestinations sks2 [] Destinations:DestinationAllShards()`,
  2241  		`StreamExecuteMulti dummy_select sks2.-20: {} sks2.20-: {} `,
  2242  
  2243  		// the query exec
  2244  		`ResolveDestinations sks1 [value:"0"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
  2245  		`ExecuteMultiShard sks1.-20: prefix values (:_c0_0) suffix {_c0_0: type:INT64 value:"1"} true true`})
  2246  
  2247  	// sks1 and uks2
  2248  	ins.Input = uRoute
  2249  
  2250  	vc.Rewind()
  2251  	_, err = ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  2252  	require.NoError(t, err)
  2253  	vc.ExpectLog(t, []string{
  2254  		// the select query
  2255  		`ResolveDestinations uks2 [] Destinations:DestinationAllShards()`,
  2256  		`ExecuteMultiShard uks2.0: dummy_select {} false false`,
  2257  
  2258  		// the query exec
  2259  		`ResolveDestinations sks1 [value:"0"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
  2260  		`ExecuteMultiShard sks1.-20: prefix values (:_c0_0) suffix {_c0_0: type:INT64 value:"1"} true true`})
  2261  
  2262  	vc.Rewind()
  2263  	err = ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  2264  		return nil
  2265  	})
  2266  	require.NoError(t, err)
  2267  	vc.ExpectLog(t, []string{
  2268  		// the select query
  2269  		`ResolveDestinations uks2 [] Destinations:DestinationAllShards()`,
  2270  		`StreamExecuteMulti dummy_select uks2.0: {} `,
  2271  
  2272  		// the query exec
  2273  		`ResolveDestinations sks1 [value:"0"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
  2274  		`ExecuteMultiShard sks1.-20: prefix values (:_c0_0) suffix {_c0_0: type:INT64 value:"1"} true true`})
  2275  
  2276  	// uks1 and sks2
  2277  	ins = &Insert{
  2278  		Opcode:   InsertUnsharded,
  2279  		Keyspace: uks1.Keyspace,
  2280  		Query:    "dummy_insert",
  2281  		Table:    uks1.Tables["s1"],
  2282  		Prefix:   "prefix ",
  2283  		Suffix:   " suffix",
  2284  		Input:    sRoute,
  2285  	}
  2286  
  2287  	vc.Rewind()
  2288  	_, err = ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  2289  	require.NoError(t, err)
  2290  	vc.ExpectLog(t, []string{
  2291  		// the select query
  2292  		`ResolveDestinations sks2 [] Destinations:DestinationAllShards()`,
  2293  		`ExecuteMultiShard sks2.-20: dummy_select {} sks2.20-: dummy_select {} false false`,
  2294  
  2295  		// the query exec
  2296  		`ResolveDestinations uks1 [] Destinations:DestinationAllShards()`,
  2297  		`ExecuteMultiShard uks1.0: prefix values (:_c0_0) suffix {_c0_0: type:INT64 value:"1"} true true`})
  2298  
  2299  	vc.Rewind()
  2300  	err = ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  2301  		return nil
  2302  	})
  2303  	require.NoError(t, err)
  2304  	vc.ExpectLog(t, []string{
  2305  		// the select query
  2306  		`ResolveDestinations sks2 [] Destinations:DestinationAllShards()`,
  2307  		`StreamExecuteMulti dummy_select sks2.-20: {} sks2.20-: {} `,
  2308  
  2309  		// the query exec
  2310  		`ResolveDestinations uks1 [] Destinations:DestinationAllShards()`,
  2311  		`ExecuteMultiShard uks1.0: prefix values (:_c0_0) suffix {_c0_0: type:INT64 value:"1"} true true`})
  2312  
  2313  	// uks1 and uks2
  2314  	ins.Input = uRoute
  2315  
  2316  	vc.Rewind()
  2317  	_, err = ins.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  2318  	require.NoError(t, err)
  2319  	vc.ExpectLog(t, []string{
  2320  		// the select query
  2321  		`ResolveDestinations uks2 [] Destinations:DestinationAllShards()`,
  2322  		`ExecuteMultiShard uks2.0: dummy_select {} false false`,
  2323  
  2324  		// the query exec
  2325  		`ResolveDestinations uks1 [] Destinations:DestinationAllShards()`,
  2326  		`ExecuteMultiShard uks1.0: prefix values (:_c0_0) suffix {_c0_0: type:INT64 value:"1"} true true`})
  2327  
  2328  	vc.Rewind()
  2329  	err = ins.TryStreamExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false, func(result *sqltypes.Result) error {
  2330  		return nil
  2331  	})
  2332  	require.NoError(t, err)
  2333  	vc.ExpectLog(t, []string{
  2334  		// the select query
  2335  		`ResolveDestinations uks2 [] Destinations:DestinationAllShards()`,
  2336  		`StreamExecuteMulti dummy_select uks2.0: {} `,
  2337  
  2338  		// the query exec
  2339  		`ResolveDestinations uks1 [] Destinations:DestinationAllShards()`,
  2340  		`ExecuteMultiShard uks1.0: prefix values (:_c0_0) suffix {_c0_0: type:INT64 value:"1"} true true`})
  2341  }