vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/route_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  	"fmt"
    23  	"strconv"
    24  	"testing"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  
    28  	"vitess.io/vitess/go/mysql/collations"
    29  	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
    30  	"vitess.io/vitess/go/vt/servenv"
    31  	"vitess.io/vitess/go/vt/vterrors"
    32  
    33  	"vitess.io/vitess/go/vt/sqlparser"
    34  
    35  	"vitess.io/vitess/go/vt/vtgate/evalengine"
    36  
    37  	"github.com/stretchr/testify/require"
    38  
    39  	"vitess.io/vitess/go/mysql"
    40  	"vitess.io/vitess/go/sqltypes"
    41  	querypb "vitess.io/vitess/go/vt/proto/query"
    42  	"vitess.io/vitess/go/vt/vtgate/vindexes"
    43  )
    44  
    45  var defaultSelectResult = sqltypes.MakeTestResult(
    46  	sqltypes.MakeTestFields(
    47  		"id",
    48  		"int64",
    49  	),
    50  	"1",
    51  )
    52  
    53  func init() {
    54  	// We require MySQL 8.0 collations for the comparisons in the tests
    55  	mySQLVersion := "8.0.0"
    56  	servenv.SetMySQLServerVersionForTest(mySQLVersion)
    57  	collationEnv = collations.NewEnvironment(mySQLVersion)
    58  }
    59  
    60  func TestSelectUnsharded(t *testing.T) {
    61  	sel := NewRoute(
    62  		Unsharded,
    63  		&vindexes.Keyspace{
    64  			Name:    "ks",
    65  			Sharded: false,
    66  		},
    67  		"dummy_select",
    68  		"dummy_select_field",
    69  	)
    70  
    71  	vc := &loggingVCursor{
    72  		shards:  []string{"0"},
    73  		results: []*sqltypes.Result{defaultSelectResult},
    74  	}
    75  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
    76  	require.NoError(t, err)
    77  	vc.ExpectLog(t, []string{
    78  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
    79  		`ExecuteMultiShard ks.0: dummy_select {} false false`,
    80  	})
    81  	expectResult(t, "sel.Execute", result, defaultSelectResult)
    82  
    83  	vc.Rewind()
    84  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
    85  	require.NoError(t, err)
    86  	vc.ExpectLog(t, []string{
    87  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
    88  		`StreamExecuteMulti dummy_select ks.0: {} `,
    89  	})
    90  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
    91  }
    92  
    93  func TestInformationSchemaWithTableAndSchemaWithRoutedTables(t *testing.T) {
    94  	stringListToExprList := func(in []string) []evalengine.Expr {
    95  		var schema []evalengine.Expr
    96  		for _, s := range in {
    97  			schema = append(schema, evalengine.NewLiteralString([]byte(s), collations.TypedCollation{}))
    98  		}
    99  		return schema
   100  	}
   101  
   102  	type testCase struct {
   103  		tableSchema []string
   104  		tableName   map[string]evalengine.Expr
   105  		testName    string
   106  		expectedLog []string
   107  		routed      bool
   108  	}
   109  	tests := []testCase{{
   110  		testName:    "both schema and table predicates - routed table",
   111  		tableSchema: []string{"schema"},
   112  		tableName:   map[string]evalengine.Expr{"table_name": evalengine.NewLiteralString([]byte("table"), collations.TypedCollation{})},
   113  		routed:      true,
   114  		expectedLog: []string{
   115  			"FindTable(`schema`.`table`)",
   116  			"ResolveDestinations routedKeyspace [] Destinations:DestinationAnyShard()",
   117  			"ExecuteMultiShard routedKeyspace.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\" table_name: type:VARCHAR value:\"routedTable\"} false false"},
   118  	}, {
   119  		testName:    "both schema and table predicates - not routed",
   120  		tableSchema: []string{"schema"},
   121  		tableName:   map[string]evalengine.Expr{"table_name": evalengine.NewLiteralString([]byte("table"), collations.TypedCollation{})},
   122  		routed:      false,
   123  		expectedLog: []string{
   124  			"FindTable(`schema`.`table`)",
   125  			"ResolveDestinations schema [] Destinations:DestinationAnyShard()",
   126  			"ExecuteMultiShard schema.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\" table_name: type:VARCHAR value:\"table\"} false false"},
   127  	}, {
   128  		testName:    "multiple schema and table predicates",
   129  		tableSchema: []string{"schema", "schema", "schema"},
   130  		tableName:   map[string]evalengine.Expr{"t1": evalengine.NewLiteralString([]byte("table"), collations.TypedCollation{}), "t2": evalengine.NewLiteralString([]byte("table"), collations.TypedCollation{}), "t3": evalengine.NewLiteralString([]byte("table"), collations.TypedCollation{})},
   131  		routed:      false,
   132  		expectedLog: []string{
   133  			"FindTable(`schema`.`table`)",
   134  			"FindTable(`schema`.`table`)",
   135  			"FindTable(`schema`.`table`)",
   136  			"ResolveDestinations schema [] Destinations:DestinationAnyShard()",
   137  			"ExecuteMultiShard schema.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\" t1: type:VARCHAR value:\"table\" t2: type:VARCHAR value:\"table\" t3: type:VARCHAR value:\"table\"} false false"},
   138  	}, {
   139  		testName:  "table name predicate - routed table",
   140  		tableName: map[string]evalengine.Expr{"table_name": evalengine.NewLiteralString([]byte("tableName"), collations.TypedCollation{})},
   141  		routed:    true,
   142  		expectedLog: []string{
   143  			"FindTable(tableName)",
   144  			"ResolveDestinations routedKeyspace [] Destinations:DestinationAnyShard()",
   145  			"ExecuteMultiShard routedKeyspace.1: dummy_select {table_name: type:VARCHAR value:\"routedTable\"} false false"},
   146  	}, {
   147  		testName:  "table name predicate - not routed",
   148  		tableName: map[string]evalengine.Expr{"table_name": evalengine.NewLiteralString([]byte("tableName"), collations.TypedCollation{})},
   149  		routed:    false,
   150  		expectedLog: []string{
   151  			"FindTable(tableName)",
   152  			"ResolveDestinations ks [] Destinations:DestinationAnyShard()",
   153  			"ExecuteMultiShard ks.1: dummy_select {table_name: type:VARCHAR value:\"tableName\"} false false"},
   154  	}, {
   155  		testName:    "schema predicate",
   156  		tableSchema: []string{"myKeyspace"},
   157  		expectedLog: []string{
   158  			"ResolveDestinations myKeyspace [] Destinations:DestinationAnyShard()",
   159  			"ExecuteMultiShard myKeyspace.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\"} false false"},
   160  	}, {
   161  		testName:    "multiple schema predicates",
   162  		tableSchema: []string{"myKeyspace", "myKeyspace", "myKeyspace", "myKeyspace"},
   163  		expectedLog: []string{
   164  			"ResolveDestinations myKeyspace [] Destinations:DestinationAnyShard()",
   165  			"ExecuteMultiShard myKeyspace.1: dummy_select {__replacevtschemaname: type:INT64 value:\"1\"} false false"},
   166  	}, {
   167  		testName: "no predicates",
   168  		expectedLog: []string{
   169  			"ResolveDestinations ks [] Destinations:DestinationAnyShard()",
   170  			"ExecuteMultiShard ks.1: dummy_select {} false false"},
   171  	}}
   172  	for _, tc := range tests {
   173  		t.Run(tc.testName, func(t *testing.T) {
   174  			sel := &Route{
   175  				RoutingParameters: &RoutingParameters{
   176  					Opcode: DBA,
   177  					Keyspace: &vindexes.Keyspace{
   178  						Name:    "ks",
   179  						Sharded: false,
   180  					},
   181  					SysTableTableSchema: stringListToExprList(tc.tableSchema),
   182  					SysTableTableName:   tc.tableName,
   183  				},
   184  				Query:      "dummy_select",
   185  				FieldQuery: "dummy_select_field",
   186  			}
   187  			vc := &loggingVCursor{
   188  				shards:  []string{"1"},
   189  				results: []*sqltypes.Result{defaultSelectResult},
   190  			}
   191  			if tc.routed {
   192  				vc.tableRoutes = tableRoutes{
   193  					tbl: &vindexes.Table{
   194  						Name:     sqlparser.NewIdentifierCS("routedTable"),
   195  						Keyspace: &vindexes.Keyspace{Name: "routedKeyspace"},
   196  					}}
   197  			}
   198  			_, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   199  			require.NoError(t, err)
   200  			vc.ExpectLog(t, tc.expectedLog)
   201  		})
   202  	}
   203  }
   204  
   205  func TestSelectScatter(t *testing.T) {
   206  	sel := NewRoute(
   207  		Scatter,
   208  		&vindexes.Keyspace{
   209  			Name:    "ks",
   210  			Sharded: true,
   211  		},
   212  		"dummy_select",
   213  		"dummy_select_field",
   214  	)
   215  
   216  	vc := &loggingVCursor{
   217  		shards:  []string{"-20", "20-"},
   218  		results: []*sqltypes.Result{defaultSelectResult},
   219  	}
   220  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   221  	require.NoError(t, err)
   222  	vc.ExpectLog(t, []string{
   223  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
   224  		`ExecuteMultiShard ks.-20: dummy_select {} ks.20-: dummy_select {} false false`,
   225  	})
   226  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   227  
   228  	vc.Rewind()
   229  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   230  	require.NoError(t, err)
   231  	vc.ExpectLog(t, []string{
   232  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
   233  		`StreamExecuteMulti dummy_select ks.-20: {} ks.20-: {} `,
   234  	})
   235  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   236  }
   237  
   238  func TestSelectEqualUnique(t *testing.T) {
   239  	vindex, _ := vindexes.NewHash("", nil)
   240  	sel := NewRoute(
   241  		EqualUnique,
   242  		&vindexes.Keyspace{
   243  			Name:    "ks",
   244  			Sharded: true,
   245  		},
   246  		"dummy_select",
   247  		"dummy_select_field",
   248  	)
   249  	sel.Vindex = vindex.(vindexes.SingleColumn)
   250  
   251  	sel.Values = []evalengine.Expr{
   252  		evalengine.NewLiteralInt(1),
   253  	}
   254  	vc := &loggingVCursor{
   255  		shards:  []string{"-20", "20-"},
   256  		results: []*sqltypes.Result{defaultSelectResult},
   257  	}
   258  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   259  	require.NoError(t, err)
   260  	vc.ExpectLog(t, []string{
   261  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
   262  		`ExecuteMultiShard ks.-20: dummy_select {} false false`,
   263  	})
   264  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   265  
   266  	vc.Rewind()
   267  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   268  	require.NoError(t, err)
   269  	vc.ExpectLog(t, []string{
   270  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`,
   271  		`StreamExecuteMulti dummy_select ks.-20: {} `,
   272  	})
   273  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   274  }
   275  
   276  func TestSelectNone(t *testing.T) {
   277  	vindex, _ := vindexes.NewHash("", nil)
   278  	sel := NewRoute(
   279  		None,
   280  		&vindexes.Keyspace{
   281  			Name:    "ks",
   282  			Sharded: true,
   283  		},
   284  		"dummy_select",
   285  		"dummy_select_field",
   286  	)
   287  	sel.Vindex = vindex.(vindexes.SingleColumn)
   288  	sel.Values = nil
   289  
   290  	vc := &loggingVCursor{
   291  		shards:  []string{"-20", "20-"},
   292  		results: []*sqltypes.Result{},
   293  	}
   294  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   295  	require.NoError(t, err)
   296  	require.Empty(t, vc.log)
   297  	expectResult(t, "sel.Execute", result, &sqltypes.Result{})
   298  
   299  	vc.Rewind()
   300  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   301  	require.NoError(t, err)
   302  	require.Empty(t, vc.log)
   303  	expectResult(t, "sel.StreamExecute", result, nil)
   304  
   305  	vc.Rewind()
   306  
   307  	// test with special no-routes handling
   308  	sel.NoRoutesSpecialHandling = true
   309  	result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   310  	require.NoError(t, err)
   311  	vc.ExpectLog(t, []string{
   312  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   313  		`ExecuteMultiShard ks.-20: dummy_select {} false false`,
   314  	})
   315  	expectResult(t, "sel.Execute", result, &sqltypes.Result{})
   316  
   317  	vc.Rewind()
   318  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   319  	require.NoError(t, err)
   320  	vc.ExpectLog(t, []string{
   321  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   322  		`StreamExecuteMulti dummy_select ks.-20: {} `,
   323  	})
   324  	expectResult(t, "sel.StreamExecute", result, &sqltypes.Result{})
   325  }
   326  
   327  func TestSelectEqualUniqueScatter(t *testing.T) {
   328  	vindex, _ := vindexes.NewLookupUnique("", map[string]string{
   329  		"table":      "lkp",
   330  		"from":       "from",
   331  		"to":         "toc",
   332  		"write_only": "true",
   333  	})
   334  	sel := NewRoute(
   335  		EqualUnique,
   336  		&vindexes.Keyspace{
   337  			Name:    "ks",
   338  			Sharded: true,
   339  		},
   340  		"dummy_select",
   341  		"dummy_select_field",
   342  	)
   343  	sel.Vindex = vindex.(vindexes.SingleColumn)
   344  	sel.Values = []evalengine.Expr{
   345  		evalengine.NewLiteralInt(1),
   346  	}
   347  	vc := &loggingVCursor{
   348  		shards:       []string{"-20", "20-"},
   349  		shardForKsid: []string{"-20", "20-"},
   350  		results:      []*sqltypes.Result{defaultSelectResult},
   351  	}
   352  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   353  	require.NoError(t, err)
   354  	vc.ExpectLog(t, []string{
   355  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationKeyRange(-)`,
   356  		`ExecuteMultiShard ks.-20: dummy_select {} ks.20-: dummy_select {} false false`,
   357  	})
   358  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   359  
   360  	vc.Rewind()
   361  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   362  	require.NoError(t, err)
   363  	vc.ExpectLog(t, []string{
   364  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationKeyRange(-)`,
   365  		`StreamExecuteMulti dummy_select ks.-20: {} ks.20-: {} `,
   366  	})
   367  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   368  }
   369  
   370  func TestSelectEqual(t *testing.T) {
   371  	vindex, _ := vindexes.NewLookup("", map[string]string{
   372  		"table": "lkp",
   373  		"from":  "from",
   374  		"to":    "toc",
   375  	})
   376  	sel := NewRoute(
   377  		Equal,
   378  		&vindexes.Keyspace{
   379  			Name:    "ks",
   380  			Sharded: true,
   381  		},
   382  		"dummy_select",
   383  		"dummy_select_field",
   384  	)
   385  	sel.Vindex = vindex.(vindexes.SingleColumn)
   386  	sel.Values = []evalengine.Expr{
   387  		evalengine.NewLiteralInt(1),
   388  	}
   389  	vc := &loggingVCursor{
   390  		shards: []string{"-20", "20-"},
   391  		results: []*sqltypes.Result{
   392  			sqltypes.MakeTestResult(
   393  				sqltypes.MakeTestFields(
   394  					"fromc|toc",
   395  					"int64|varbinary",
   396  				),
   397  				"1|\x00",
   398  				"1|\x80",
   399  			),
   400  			defaultSelectResult,
   401  		},
   402  	}
   403  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   404  	require.NoError(t, err)
   405  	vc.ExpectLog(t, []string{
   406  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   407  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationKeyspaceIDs(00,80)`,
   408  		`ExecuteMultiShard ks.-20: dummy_select {} ks.20-: dummy_select {} false false`,
   409  	})
   410  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   411  
   412  	vc.Rewind()
   413  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   414  	require.NoError(t, err)
   415  	vc.ExpectLog(t, []string{
   416  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   417  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationKeyspaceIDs(00,80)`,
   418  		`StreamExecuteMulti dummy_select ks.-20: {} ks.20-: {} `,
   419  	})
   420  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   421  }
   422  
   423  func TestSelectEqualNoRoute(t *testing.T) {
   424  	vindex, _ := vindexes.NewLookupUnique("", map[string]string{
   425  		"table": "lkp",
   426  		"from":  "from",
   427  		"to":    "toc",
   428  	})
   429  	sel := NewRoute(
   430  		Equal,
   431  		&vindexes.Keyspace{
   432  			Name:    "ks",
   433  			Sharded: true,
   434  		},
   435  		"dummy_select",
   436  		"dummy_select_field",
   437  	)
   438  	sel.Vindex = vindex.(vindexes.SingleColumn)
   439  	sel.Values = []evalengine.Expr{
   440  		evalengine.NewLiteralInt(1),
   441  	}
   442  
   443  	vc := &loggingVCursor{shards: []string{"-20", "20-"}}
   444  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   445  	require.NoError(t, err)
   446  	vc.ExpectLog(t, []string{
   447  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   448  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   449  	})
   450  	expectResult(t, "sel.Execute", result, &sqltypes.Result{})
   451  
   452  	vc.Rewind()
   453  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   454  	require.NoError(t, err)
   455  	vc.ExpectLog(t, []string{
   456  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   457  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   458  	})
   459  	expectResult(t, "sel.StreamExecute", result, nil)
   460  
   461  	// test with special no-routes handling
   462  	sel.NoRoutesSpecialHandling = true
   463  	vc.Rewind()
   464  
   465  	result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   466  	require.NoError(t, err)
   467  	vc.ExpectLog(t, []string{
   468  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   469  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   470  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   471  		`ExecuteMultiShard ks.-20: dummy_select {} false false`,
   472  	})
   473  	expectResult(t, "sel.Execute", result, &sqltypes.Result{})
   474  
   475  	vc.Rewind()
   476  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   477  	require.NoError(t, err)
   478  	vc.ExpectLog(t, []string{
   479  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   480  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   481  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   482  		`StreamExecuteMulti dummy_select ks.-20: {} `,
   483  	})
   484  	expectResult(t, "sel.StreamExecute", result, &sqltypes.Result{})
   485  }
   486  
   487  func TestINUnique(t *testing.T) {
   488  	vindex, _ := vindexes.NewHash("", nil)
   489  	sel := NewRoute(
   490  		IN,
   491  		&vindexes.Keyspace{
   492  			Name:    "ks",
   493  			Sharded: true,
   494  		},
   495  		"dummy_select",
   496  		"dummy_select_field",
   497  	)
   498  	sel.Vindex = vindex.(vindexes.SingleColumn)
   499  	sel.Values = []evalengine.Expr{
   500  		evalengine.TupleExpr{
   501  			evalengine.NewLiteralInt(1),
   502  			evalengine.NewLiteralInt(2),
   503  			evalengine.NewLiteralInt(4),
   504  		},
   505  	}
   506  	vc := &loggingVCursor{
   507  		shards:       []string{"-20", "20-"},
   508  		shardForKsid: []string{"-20", "-20", "20-"},
   509  		results:      []*sqltypes.Result{defaultSelectResult},
   510  	}
   511  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   512  	require.NoError(t, err)
   513  	vc.ExpectLog(t, []string{
   514  		`ResolveDestinations ks [type:INT64 value:"1" type:INT64 value:"2" type:INT64 value:"4"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(d2fd8867d50d2dfe)`,
   515  		`ExecuteMultiShard ` +
   516  			`ks.-20: dummy_select {__vals: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"}} ` +
   517  			`ks.20-: dummy_select {__vals: type:TUPLE values:{type:INT64 value:"4"}} ` +
   518  			`false false`,
   519  	})
   520  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   521  
   522  	vc.Rewind()
   523  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   524  	require.NoError(t, err)
   525  	vc.ExpectLog(t, []string{
   526  		`ResolveDestinations ks [type:INT64 value:"1" type:INT64 value:"2" type:INT64 value:"4"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(d2fd8867d50d2dfe)`,
   527  		`StreamExecuteMulti dummy_select ks.-20: {__vals: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"}} ks.20-: {__vals: type:TUPLE values:{type:INT64 value:"4"}} `,
   528  	})
   529  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   530  }
   531  
   532  func TestINNonUnique(t *testing.T) {
   533  	vindex, _ := vindexes.NewLookup("", map[string]string{
   534  		"table": "lkp",
   535  		"from":  "from",
   536  		"to":    "toc",
   537  	})
   538  	sel := NewRoute(
   539  		IN,
   540  		&vindexes.Keyspace{
   541  			Name:    "ks",
   542  			Sharded: true,
   543  		},
   544  		"dummy_select",
   545  		"dummy_select_field",
   546  	)
   547  	sel.Vindex = vindex.(vindexes.SingleColumn)
   548  	sel.Values = []evalengine.Expr{
   549  		evalengine.TupleExpr{
   550  			evalengine.NewLiteralInt(1),
   551  			evalengine.NewLiteralInt(2),
   552  			evalengine.NewLiteralInt(4),
   553  		},
   554  	}
   555  
   556  	fields := sqltypes.MakeTestFields(
   557  		"fromc|toc",
   558  		"int64|varbinary",
   559  	)
   560  	vc := &loggingVCursor{
   561  		shards: []string{"-20", "20-"},
   562  		results: []*sqltypes.Result{
   563  			// 1 will be sent to both shards.
   564  			// 2 will go to -20.
   565  			// 4 will go to 20-.
   566  			sqltypes.MakeTestResult(
   567  				fields,
   568  				"1|\x00",
   569  				"1|\x80",
   570  				"2|\x00",
   571  				"4|\x80",
   572  			),
   573  			defaultSelectResult,
   574  		},
   575  	}
   576  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   577  	require.NoError(t, err)
   578  	vc.ExpectLog(t, []string{
   579  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"} values:{type:INT64 value:"4"} false`,
   580  		`ResolveDestinations ks [type:INT64 value:"1" type:INT64 value:"2" type:INT64 value:"4"] Destinations:DestinationKeyspaceIDs(00,80),DestinationKeyspaceIDs(00),DestinationKeyspaceIDs(80)`,
   581  		`ExecuteMultiShard ` +
   582  			`ks.-20: dummy_select {__vals: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"}} ` +
   583  			`ks.20-: dummy_select {__vals: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"4"}} ` +
   584  			`false false`,
   585  	})
   586  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   587  
   588  	vc.Rewind()
   589  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   590  	require.NoError(t, err)
   591  	vc.ExpectLog(t, []string{
   592  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"} values:{type:INT64 value:"4"} false`,
   593  		`ResolveDestinations ks [type:INT64 value:"1" type:INT64 value:"2" type:INT64 value:"4"] Destinations:DestinationKeyspaceIDs(00,80),DestinationKeyspaceIDs(00),DestinationKeyspaceIDs(80)`,
   594  		`StreamExecuteMulti dummy_select ks.-20: {__vals: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"}} ks.20-: {__vals: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"4"}} `,
   595  	})
   596  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   597  }
   598  
   599  func TestMultiEqual(t *testing.T) {
   600  	vindex, _ := vindexes.NewHash("", nil)
   601  	sel := NewRoute(
   602  		MultiEqual,
   603  		&vindexes.Keyspace{
   604  			Name:    "ks",
   605  			Sharded: true,
   606  		},
   607  		"dummy_select",
   608  		"dummy_select_field",
   609  	)
   610  	sel.Vindex = vindex.(vindexes.SingleColumn)
   611  	sel.Values = []evalengine.Expr{
   612  		evalengine.TupleExpr{
   613  			evalengine.NewLiteralInt(1),
   614  			evalengine.NewLiteralInt(2),
   615  			evalengine.NewLiteralInt(4),
   616  		},
   617  	}
   618  
   619  	vc := &loggingVCursor{
   620  		shards:       []string{"-20", "20-"},
   621  		shardForKsid: []string{"-20", "-20", "20-"},
   622  		results:      []*sqltypes.Result{defaultSelectResult},
   623  	}
   624  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   625  	require.NoError(t, err)
   626  	vc.ExpectLog(t, []string{
   627  		`ResolveDestinations ks [type:INT64 value:"1" type:INT64 value:"2" type:INT64 value:"4"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(d2fd8867d50d2dfe)`,
   628  		`ExecuteMultiShard ks.-20: dummy_select {} ks.20-: dummy_select {} false false`,
   629  	})
   630  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   631  
   632  	vc.Rewind()
   633  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   634  	require.NoError(t, err)
   635  	vc.ExpectLog(t, []string{
   636  		`ResolveDestinations ks [type:INT64 value:"1" type:INT64 value:"2" type:INT64 value:"4"] Destinations:DestinationKeyspaceID(166b40b44aba4bd6),DestinationKeyspaceID(06e7ea22ce92708f),DestinationKeyspaceID(d2fd8867d50d2dfe)`,
   637  		`StreamExecuteMulti dummy_select ks.-20: {} ks.20-: {} `,
   638  	})
   639  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   640  }
   641  
   642  func TestSelectLike(t *testing.T) {
   643  	subshard, _ := vindexes.NewCFC("cfc", map[string]string{"hash": "md5", "offsets": "[1,2]"})
   644  	vindex := subshard.(*vindexes.CFC).PrefixVindex()
   645  	vc := &loggingVCursor{
   646  		// we have shards '-0c80', '0c80-0d', '0d-40', '40-80', '80-'
   647  		shards:  []string{"\x0c\x80", "\x0d", "\x40", "\x80"},
   648  		results: []*sqltypes.Result{defaultSelectResult},
   649  	}
   650  
   651  	sel := NewRoute(
   652  		Equal,
   653  		&vindexes.Keyspace{
   654  			Name:    "ks",
   655  			Sharded: true,
   656  		},
   657  		"dummy_select",
   658  		"dummy_select_field",
   659  	)
   660  
   661  	sel.Vindex = vindex
   662  	sel.Values = []evalengine.Expr{
   663  		evalengine.NewLiteralString([]byte("a%"), collations.TypedCollation{}),
   664  	}
   665  	// md5("a") = 0cc175b9c0f1b6a831c399e269772661
   666  	// keyspace id prefix for "a" is 0x0c
   667  	vc.shardForKsid = []string{"-0c80", "0c80-0d"}
   668  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   669  	require.NoError(t, err)
   670  
   671  	// range 0c-0d hits 2 shards ks.-0c80 ks.0c80-0d;
   672  	// note that 0c-0d should not hit ks.0d-40
   673  	vc.ExpectLog(t, []string{
   674  		`ResolveDestinations ks [type:VARCHAR value:"a%"] Destinations:DestinationKeyRange(0c-0d)`,
   675  		`ExecuteMultiShard ks.-0c80: dummy_select {} ks.0c80-0d: dummy_select {} false false`,
   676  	})
   677  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   678  
   679  	vc.Rewind()
   680  
   681  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   682  	require.NoError(t, err)
   683  
   684  	vc.ExpectLog(t, []string{
   685  		`ResolveDestinations ks [type:VARCHAR value:"a%"] Destinations:DestinationKeyRange(0c-0d)`,
   686  		`StreamExecuteMulti dummy_select ks.-0c80: {} ks.0c80-0d: {} `,
   687  	})
   688  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   689  
   690  	vc.Rewind()
   691  
   692  	sel.Values = []evalengine.Expr{
   693  		evalengine.NewLiteralString([]byte("ab%"), collations.TypedCollation{}),
   694  	}
   695  	// md5("b") = 92eb5ffee6ae2fec3ad71c777531578f
   696  	// keyspace id prefix for "ab" is 0x0c92
   697  	// adding one byte to the prefix just hit one shard
   698  	vc.shardForKsid = []string{"0c80-0d"}
   699  	result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   700  	if err != nil {
   701  		t.Fatal(err)
   702  	}
   703  	vc.ExpectLog(t, []string{
   704  		`ResolveDestinations ks [type:VARCHAR value:"ab%"] Destinations:DestinationKeyRange(0c92-0c93)`,
   705  		`ExecuteMultiShard ks.0c80-0d: dummy_select {} false false`,
   706  	})
   707  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   708  
   709  	vc.Rewind()
   710  
   711  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   712  	require.NoError(t, err)
   713  
   714  	vc.ExpectLog(t, []string{
   715  		`ResolveDestinations ks [type:VARCHAR value:"ab%"] Destinations:DestinationKeyRange(0c92-0c93)`,
   716  		`StreamExecuteMulti dummy_select ks.0c80-0d: {} `,
   717  	})
   718  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   719  
   720  }
   721  
   722  func TestSelectNext(t *testing.T) {
   723  	sel := NewRoute(
   724  		Next,
   725  		&vindexes.Keyspace{
   726  			Name:    "ks",
   727  			Sharded: false,
   728  		},
   729  		"dummy_select",
   730  		"dummy_select_field",
   731  	)
   732  
   733  	vc := &loggingVCursor{
   734  		shards:  []string{"-"},
   735  		results: []*sqltypes.Result{defaultSelectResult},
   736  	}
   737  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   738  	require.NoError(t, err)
   739  	vc.ExpectLog(t, []string{
   740  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
   741  		`ExecuteMultiShard ks.-: dummy_select {} false false`,
   742  	})
   743  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   744  
   745  	vc.Rewind()
   746  	result, _ = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   747  	vc.ExpectLog(t, []string{
   748  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
   749  		`StreamExecuteMulti dummy_select ks.-: {} `,
   750  	})
   751  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   752  }
   753  
   754  func TestSelectDBA(t *testing.T) {
   755  	sel := NewRoute(
   756  		DBA,
   757  		&vindexes.Keyspace{
   758  			Name:    "ks",
   759  			Sharded: true,
   760  		},
   761  		"dummy_select",
   762  		"dummy_select_field",
   763  	)
   764  
   765  	vc := &loggingVCursor{
   766  		shards:  []string{"-20", "20-"},
   767  		results: []*sqltypes.Result{defaultSelectResult},
   768  	}
   769  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   770  	require.NoError(t, err)
   771  	vc.ExpectLog(t, []string{
   772  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   773  		`ExecuteMultiShard ks.-20: dummy_select {} false false`,
   774  	})
   775  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   776  
   777  	vc.Rewind()
   778  	result, _ = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   779  	vc.ExpectLog(t, []string{
   780  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   781  		`StreamExecuteMulti dummy_select ks.-20: {} `,
   782  	})
   783  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   784  }
   785  
   786  func TestSelectReference(t *testing.T) {
   787  	sel := NewRoute(
   788  		Reference,
   789  		&vindexes.Keyspace{
   790  			Name:    "ks",
   791  			Sharded: true,
   792  		},
   793  		"dummy_select",
   794  		"dummy_select_field",
   795  	)
   796  
   797  	vc := &loggingVCursor{
   798  		shards:  []string{"-20", "20-"},
   799  		results: []*sqltypes.Result{defaultSelectResult},
   800  	}
   801  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   802  	require.NoError(t, err)
   803  	vc.ExpectLog(t, []string{
   804  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   805  		`ExecuteMultiShard ks.-20: dummy_select {} false false`,
   806  	})
   807  	expectResult(t, "sel.Execute", result, defaultSelectResult)
   808  
   809  	vc.Rewind()
   810  	result, _ = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
   811  	vc.ExpectLog(t, []string{
   812  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   813  		`StreamExecuteMulti dummy_select ks.-20: {} `,
   814  	})
   815  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
   816  }
   817  
   818  func TestRouteGetFields(t *testing.T) {
   819  	vindex, _ := vindexes.NewLookupUnique("", map[string]string{
   820  		"table": "lkp",
   821  		"from":  "from",
   822  		"to":    "toc",
   823  	})
   824  	sel := NewRoute(
   825  		Equal,
   826  		&vindexes.Keyspace{
   827  			Name:    "ks",
   828  			Sharded: true,
   829  		},
   830  		"dummy_select",
   831  		"dummy_select_field",
   832  	)
   833  	sel.Vindex = vindex.(vindexes.SingleColumn)
   834  	sel.Values = []evalengine.Expr{
   835  		evalengine.NewLiteralInt(1),
   836  	}
   837  
   838  	vc := &loggingVCursor{shards: []string{"-20", "20-"}}
   839  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, true)
   840  	require.NoError(t, err)
   841  	vc.ExpectLog(t, []string{
   842  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   843  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   844  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   845  		`ExecuteMultiShard ks.-20: dummy_select_field {} false false`,
   846  	})
   847  	expectResult(t, "sel.Execute", result, &sqltypes.Result{})
   848  
   849  	vc.Rewind()
   850  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, true)
   851  	require.NoError(t, err)
   852  	vc.ExpectLog(t, []string{
   853  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   854  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   855  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   856  		`ExecuteMultiShard ks.-20: dummy_select_field {} false false`,
   857  	})
   858  	expectResult(t, "sel.StreamExecute", result, &sqltypes.Result{})
   859  	vc.Rewind()
   860  
   861  	// test with special no-routes handling
   862  	sel.NoRoutesSpecialHandling = true
   863  	result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, true)
   864  	require.NoError(t, err)
   865  	vc.ExpectLog(t, []string{
   866  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   867  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   868  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   869  		`ExecuteMultiShard ks.-20: dummy_select {} false false`,
   870  	})
   871  	expectResult(t, "sel.Execute", result, &sqltypes.Result{})
   872  
   873  	vc.Rewind()
   874  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, true)
   875  	require.NoError(t, err)
   876  	vc.ExpectLog(t, []string{
   877  		`Execute select from, toc from lkp where from in ::from from: type:TUPLE values:{type:INT64 value:"1"} false`,
   878  		`ResolveDestinations ks [type:INT64 value:"1"] Destinations:DestinationNone()`,
   879  		`ResolveDestinations ks [] Destinations:DestinationAnyShard()`,
   880  		`StreamExecuteMulti dummy_select ks.-20: {} `,
   881  	})
   882  	expectResult(t, "sel.StreamExecute", result, &sqltypes.Result{})
   883  }
   884  
   885  func TestRouteSort(t *testing.T) {
   886  	sel := NewRoute(
   887  		Unsharded,
   888  		&vindexes.Keyspace{
   889  			Name:    "ks",
   890  			Sharded: false,
   891  		},
   892  		"dummy_select",
   893  		"dummy_select_field",
   894  	)
   895  	sel.OrderBy = []OrderByParams{{
   896  		Col:             0,
   897  		WeightStringCol: -1,
   898  	}}
   899  
   900  	vc := &loggingVCursor{
   901  		shards: []string{"0"},
   902  		results: []*sqltypes.Result{
   903  			sqltypes.MakeTestResult(
   904  				sqltypes.MakeTestFields(
   905  					"id",
   906  					"int64",
   907  				),
   908  				"1",
   909  				"1",
   910  				"3",
   911  				"2",
   912  			),
   913  		},
   914  	}
   915  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   916  	require.NoError(t, err)
   917  	vc.ExpectLog(t, []string{
   918  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
   919  		`ExecuteMultiShard ks.0: dummy_select {} false false`,
   920  	})
   921  	wantResult := sqltypes.MakeTestResult(
   922  		sqltypes.MakeTestFields(
   923  			"id",
   924  			"int64",
   925  		),
   926  		"1",
   927  		"1",
   928  		"2",
   929  		"3",
   930  	)
   931  	expectResult(t, "sel.Execute", result, wantResult)
   932  
   933  	sel.OrderBy[0].Desc = true
   934  	vc.Rewind()
   935  	result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   936  	require.NoError(t, err)
   937  	wantResult = sqltypes.MakeTestResult(
   938  		sqltypes.MakeTestFields(
   939  			"id",
   940  			"int64",
   941  		),
   942  		"3",
   943  		"2",
   944  		"1",
   945  		"1",
   946  	)
   947  	expectResult(t, "sel.Execute", result, wantResult)
   948  
   949  	vc = &loggingVCursor{
   950  		shards: []string{"0"},
   951  		results: []*sqltypes.Result{
   952  			sqltypes.MakeTestResult(
   953  				sqltypes.MakeTestFields(
   954  					"id",
   955  					"varchar",
   956  				),
   957  				"1",
   958  				"2",
   959  				"3",
   960  			),
   961  		},
   962  	}
   963  	_, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
   964  	require.EqualError(t, err, `cannot compare strings, collation is unknown or unsupported (collation ID: 0)`)
   965  }
   966  
   967  func TestRouteSortWeightStrings(t *testing.T) {
   968  	sel := NewRoute(
   969  		Unsharded,
   970  		&vindexes.Keyspace{
   971  			Name:    "ks",
   972  			Sharded: false,
   973  		},
   974  		"dummy_select",
   975  		"dummy_select_field",
   976  	)
   977  	sel.OrderBy = []OrderByParams{{
   978  		Col:             1,
   979  		WeightStringCol: 0,
   980  	}}
   981  
   982  	vc := &loggingVCursor{
   983  		shards: []string{"0"},
   984  		results: []*sqltypes.Result{
   985  			sqltypes.MakeTestResult(
   986  				sqltypes.MakeTestFields(
   987  					"weightString|normal",
   988  					"varbinary|varchar",
   989  				),
   990  				"v|x",
   991  				"g|d",
   992  				"a|a",
   993  				"c|t",
   994  				"f|p",
   995  			),
   996  		},
   997  	}
   998  
   999  	var result *sqltypes.Result
  1000  	var wantResult *sqltypes.Result
  1001  	var err error
  1002  	t.Run("Sort using Weight Strings", func(t *testing.T) {
  1003  		result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1004  		require.NoError(t, err)
  1005  		vc.ExpectLog(t, []string{
  1006  			`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
  1007  			`ExecuteMultiShard ks.0: dummy_select {} false false`,
  1008  		})
  1009  		wantResult = sqltypes.MakeTestResult(
  1010  			sqltypes.MakeTestFields(
  1011  				"weightString|normal",
  1012  				"varbinary|varchar",
  1013  			),
  1014  			"a|a",
  1015  			"c|t",
  1016  			"f|p",
  1017  			"g|d",
  1018  			"v|x",
  1019  		)
  1020  		expectResult(t, "sel.Execute", result, wantResult)
  1021  	})
  1022  
  1023  	t.Run("Descending ordering using weighted strings", func(t *testing.T) {
  1024  		sel.OrderBy[0].Desc = true
  1025  		vc.Rewind()
  1026  		result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1027  		require.NoError(t, err)
  1028  		wantResult = sqltypes.MakeTestResult(
  1029  			sqltypes.MakeTestFields(
  1030  				"weightString|normal",
  1031  				"varbinary|varchar",
  1032  			),
  1033  			"v|x",
  1034  			"g|d",
  1035  			"f|p",
  1036  			"c|t",
  1037  			"a|a",
  1038  		)
  1039  		expectResult(t, "sel.Execute", result, wantResult)
  1040  	})
  1041  
  1042  	t.Run("Error when no weight string set", func(t *testing.T) {
  1043  		sel.OrderBy = []OrderByParams{{
  1044  			Col:             1,
  1045  			WeightStringCol: -1,
  1046  		}}
  1047  
  1048  		vc = &loggingVCursor{
  1049  			shards: []string{"0"},
  1050  			results: []*sqltypes.Result{
  1051  				sqltypes.MakeTestResult(
  1052  					sqltypes.MakeTestFields(
  1053  						"weightString|normal",
  1054  						"varbinary|varchar",
  1055  					),
  1056  					"v|x",
  1057  					"g|d",
  1058  					"a|a",
  1059  					"c|t",
  1060  					"f|p",
  1061  				),
  1062  			},
  1063  		}
  1064  		_, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1065  		require.EqualError(t, err, `cannot compare strings, collation is unknown or unsupported (collation ID: 0)`)
  1066  	})
  1067  }
  1068  
  1069  func TestRouteSortCollation(t *testing.T) {
  1070  	sel := NewRoute(
  1071  		Unsharded,
  1072  		&vindexes.Keyspace{
  1073  			Name:    "ks",
  1074  			Sharded: false,
  1075  		},
  1076  		"dummy_select",
  1077  		"dummy_select_field",
  1078  	)
  1079  
  1080  	collationID, _ := collations.Local().LookupID("utf8mb4_hu_0900_ai_ci")
  1081  
  1082  	sel.OrderBy = []OrderByParams{{
  1083  		Col:         0,
  1084  		CollationID: collationID,
  1085  	}}
  1086  
  1087  	vc := &loggingVCursor{
  1088  		shards: []string{"0"},
  1089  		results: []*sqltypes.Result{
  1090  			sqltypes.MakeTestResult(
  1091  				sqltypes.MakeTestFields(
  1092  					"normal",
  1093  					"varchar",
  1094  				),
  1095  				"c",
  1096  				"d",
  1097  				"cs",
  1098  				"cs",
  1099  				"c",
  1100  			),
  1101  		},
  1102  	}
  1103  
  1104  	var result *sqltypes.Result
  1105  	var wantResult *sqltypes.Result
  1106  	var err error
  1107  	t.Run("Sort using Collation", func(t *testing.T) {
  1108  		result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1109  		require.NoError(t, err)
  1110  		vc.ExpectLog(t, []string{
  1111  			`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
  1112  			`ExecuteMultiShard ks.0: dummy_select {} false false`,
  1113  		})
  1114  		wantResult = sqltypes.MakeTestResult(
  1115  			sqltypes.MakeTestFields(
  1116  				"normal",
  1117  				"varchar",
  1118  			),
  1119  			"c",
  1120  			"c",
  1121  			"cs",
  1122  			"cs",
  1123  			"d",
  1124  		)
  1125  		expectResult(t, "sel.Execute", result, wantResult)
  1126  	})
  1127  
  1128  	t.Run("Descending ordering using Collation", func(t *testing.T) {
  1129  		sel.OrderBy[0].Desc = true
  1130  		vc.Rewind()
  1131  		result, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1132  		require.NoError(t, err)
  1133  		wantResult = sqltypes.MakeTestResult(
  1134  			sqltypes.MakeTestFields(
  1135  				"normal",
  1136  				"varchar",
  1137  			),
  1138  			"d",
  1139  			"cs",
  1140  			"cs",
  1141  			"c",
  1142  			"c",
  1143  		)
  1144  		expectResult(t, "sel.Execute", result, wantResult)
  1145  	})
  1146  
  1147  	t.Run("Error when Unknown Collation", func(t *testing.T) {
  1148  		sel.OrderBy = []OrderByParams{{
  1149  			Col:         0,
  1150  			CollationID: collations.Unknown,
  1151  		}}
  1152  
  1153  		vc := &loggingVCursor{
  1154  			shards: []string{"0"},
  1155  			results: []*sqltypes.Result{
  1156  				sqltypes.MakeTestResult(
  1157  					sqltypes.MakeTestFields(
  1158  						"normal",
  1159  						"varchar",
  1160  					),
  1161  					"c",
  1162  					"d",
  1163  					"cs",
  1164  					"cs",
  1165  					"c",
  1166  				),
  1167  			},
  1168  		}
  1169  		_, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1170  		require.EqualError(t, err, "cannot compare strings, collation is unknown or unsupported (collation ID: 0)")
  1171  	})
  1172  
  1173  	t.Run("Error when Unsupported Collation", func(t *testing.T) {
  1174  		sel.OrderBy = []OrderByParams{{
  1175  			Col:         0,
  1176  			CollationID: 1111,
  1177  		}}
  1178  
  1179  		vc := &loggingVCursor{
  1180  			shards: []string{"0"},
  1181  			results: []*sqltypes.Result{
  1182  				sqltypes.MakeTestResult(
  1183  					sqltypes.MakeTestFields(
  1184  						"normal",
  1185  						"varchar",
  1186  					),
  1187  					"c",
  1188  					"d",
  1189  					"cs",
  1190  					"cs",
  1191  					"c",
  1192  				),
  1193  			},
  1194  		}
  1195  		_, err = sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1196  		require.EqualError(t, err, "cannot compare strings, collation is unknown or unsupported (collation ID: 1111)")
  1197  	})
  1198  }
  1199  
  1200  func TestRouteSortTruncate(t *testing.T) {
  1201  	sel := NewRoute(
  1202  		Unsharded,
  1203  		&vindexes.Keyspace{
  1204  			Name:    "ks",
  1205  			Sharded: false,
  1206  		},
  1207  		"dummy_select",
  1208  		"dummy_select_field",
  1209  	)
  1210  	sel.OrderBy = []OrderByParams{{
  1211  		Col: 0,
  1212  	}}
  1213  	sel.TruncateColumnCount = 1
  1214  
  1215  	vc := &loggingVCursor{
  1216  		shards: []string{"0"},
  1217  		results: []*sqltypes.Result{
  1218  			sqltypes.MakeTestResult(
  1219  				sqltypes.MakeTestFields(
  1220  					"id|col",
  1221  					"int64|int64",
  1222  				),
  1223  				"1|1",
  1224  				"1|1",
  1225  				"3|1",
  1226  				"2|1",
  1227  			),
  1228  		},
  1229  	}
  1230  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1231  	require.NoError(t, err)
  1232  	vc.ExpectLog(t, []string{
  1233  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
  1234  		`ExecuteMultiShard ks.0: dummy_select {} false false`,
  1235  	})
  1236  	wantResult := sqltypes.MakeTestResult(
  1237  		sqltypes.MakeTestFields(
  1238  			"id",
  1239  			"int64",
  1240  		),
  1241  		"1",
  1242  		"1",
  1243  		"2",
  1244  		"3",
  1245  	)
  1246  	expectResult(t, "sel.Execute", result, wantResult)
  1247  }
  1248  
  1249  func TestRouteStreamTruncate(t *testing.T) {
  1250  	sel := NewRoute(
  1251  		Unsharded,
  1252  		&vindexes.Keyspace{
  1253  			Name:    "ks",
  1254  			Sharded: false,
  1255  		},
  1256  		"dummy_select",
  1257  		"dummy_select_field",
  1258  	)
  1259  	sel.TruncateColumnCount = 1
  1260  
  1261  	vc := &loggingVCursor{
  1262  		shards: []string{"0"},
  1263  		results: []*sqltypes.Result{
  1264  			sqltypes.MakeTestResult(
  1265  				sqltypes.MakeTestFields(
  1266  					"id|col",
  1267  					"int64|int64",
  1268  				),
  1269  				"1|1",
  1270  				"2|1",
  1271  			),
  1272  		},
  1273  	}
  1274  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1275  	require.NoError(t, err)
  1276  	vc.ExpectLog(t, []string{
  1277  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
  1278  		`ExecuteMultiShard ks.0: dummy_select {} false false`,
  1279  	})
  1280  	wantResult := sqltypes.MakeTestResult(
  1281  		sqltypes.MakeTestFields(
  1282  			"id",
  1283  			"int64",
  1284  		),
  1285  		"1",
  1286  		"2",
  1287  	)
  1288  	expectResult(t, "sel.Execute", result, wantResult)
  1289  }
  1290  
  1291  func TestRouteStreamSortTruncate(t *testing.T) {
  1292  	sel := NewRoute(
  1293  		Unsharded,
  1294  		&vindexes.Keyspace{
  1295  			Name:    "ks",
  1296  			Sharded: false,
  1297  		},
  1298  		"dummy_select",
  1299  		"dummy_select_field",
  1300  	)
  1301  	sel.OrderBy = []OrderByParams{{
  1302  		Col: 0,
  1303  	}}
  1304  	sel.TruncateColumnCount = 1
  1305  
  1306  	vc := &loggingVCursor{
  1307  		shards: []string{"0"},
  1308  		results: []*sqltypes.Result{
  1309  			sqltypes.MakeTestResult(
  1310  				sqltypes.MakeTestFields(
  1311  					"id|col",
  1312  					"int64|int64",
  1313  				),
  1314  				"1|1",
  1315  				"2|1",
  1316  			),
  1317  		},
  1318  	}
  1319  	result, err := wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, true)
  1320  	require.NoError(t, err)
  1321  	vc.ExpectLog(t, []string{
  1322  		`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
  1323  		`StreamExecuteMulti dummy_select ks.0: {} `,
  1324  	})
  1325  
  1326  	// We're not really testing sort functionality here because that part is tested
  1327  	// in merge_sort_test. We're only testing that truncation happens even if sort
  1328  	// is enabled, which is a different code path from unsorted truncate.
  1329  	wantResult := sqltypes.MakeTestResult(
  1330  		sqltypes.MakeTestFields(
  1331  			"id",
  1332  			"int64",
  1333  		),
  1334  		"1",
  1335  		"2",
  1336  	)
  1337  	expectResult(t, "sel.Execute", result, wantResult)
  1338  }
  1339  
  1340  func TestParamsFail(t *testing.T) {
  1341  	sel := NewRoute(
  1342  		Unsharded,
  1343  		&vindexes.Keyspace{
  1344  			Name:    "ks",
  1345  			Sharded: false,
  1346  		},
  1347  		"dummy_select",
  1348  		"dummy_select_field",
  1349  	)
  1350  
  1351  	vc := &loggingVCursor{shardErr: errors.New("shard error")}
  1352  	_, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1353  	require.EqualError(t, err, `shard error`)
  1354  
  1355  	vc.Rewind()
  1356  	_, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
  1357  	require.EqualError(t, err, `shard error`)
  1358  }
  1359  
  1360  func TestExecFail(t *testing.T) {
  1361  
  1362  	t.Run("unsharded", func(t *testing.T) {
  1363  		// Unsharded error
  1364  		sel := NewRoute(
  1365  			Unsharded,
  1366  			&vindexes.Keyspace{
  1367  				Name:    "ks",
  1368  				Sharded: false,
  1369  			},
  1370  			"dummy_select",
  1371  			"dummy_select_field",
  1372  		)
  1373  
  1374  		vc := &loggingVCursor{shards: []string{"0"}, resultErr: vterrors.NewErrorf(vtrpcpb.Code_CANCELED, vterrors.QueryInterrupted, "query timeout")}
  1375  		_, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1376  		require.EqualError(t, err, `query timeout`)
  1377  		assert.Empty(t, vc.warnings)
  1378  
  1379  		vc.Rewind()
  1380  		_, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
  1381  		require.EqualError(t, err, `query timeout`)
  1382  	})
  1383  
  1384  	t.Run("normal route with no scatter errors as warnings", func(t *testing.T) {
  1385  		// Scatter fails if one of N fails without ScatterErrorsAsWarnings
  1386  		sel := NewRoute(
  1387  			Scatter,
  1388  			&vindexes.Keyspace{
  1389  				Name:    "ks",
  1390  				Sharded: true,
  1391  			},
  1392  			"dummy_select",
  1393  			"dummy_select_field",
  1394  		)
  1395  
  1396  		vc := &loggingVCursor{
  1397  			shards:  []string{"-20", "20-"},
  1398  			results: []*sqltypes.Result{defaultSelectResult},
  1399  			multiShardErrs: []error{
  1400  				errors.New("result error -20"),
  1401  			},
  1402  		}
  1403  		_, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1404  		require.EqualError(t, err, `result error -20`)
  1405  		vc.ExpectWarnings(t, nil)
  1406  		vc.ExpectLog(t, []string{
  1407  			`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
  1408  			`ExecuteMultiShard ks.-20: dummy_select {} ks.20-: dummy_select {} false false`,
  1409  		})
  1410  	})
  1411  
  1412  	t.Run("ScatterErrorsAsWarnings", func(t *testing.T) {
  1413  		// Scatter succeeds if one of N fails with ScatterErrorsAsWarnings
  1414  		sel := NewRoute(
  1415  			Scatter,
  1416  			&vindexes.Keyspace{
  1417  				Name:    "ks",
  1418  				Sharded: true,
  1419  			},
  1420  			"dummy_select",
  1421  			"dummy_select_field",
  1422  		)
  1423  		sel.ScatterErrorsAsWarnings = true
  1424  
  1425  		vc := &loggingVCursor{
  1426  			shards:  []string{"-20", "20-"},
  1427  			results: []*sqltypes.Result{defaultSelectResult},
  1428  			multiShardErrs: []error{
  1429  				errors.New("result error -20"),
  1430  				nil,
  1431  			},
  1432  		}
  1433  		result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1434  		require.NoError(t, err, "unexpected ScatterErrorsAsWarnings error %v", err)
  1435  		vc.ExpectLog(t, []string{
  1436  			`ResolveDestinations ks [] Destinations:DestinationAllShards()`,
  1437  			`ExecuteMultiShard ks.-20: dummy_select {} ks.20-: dummy_select {} false false`,
  1438  		})
  1439  		expectResult(t, "sel.Execute", result, defaultSelectResult)
  1440  
  1441  		vc.Rewind()
  1442  		vc.resultErr = mysql.NewSQLError(mysql.ERQueryInterrupted, "", "query timeout -20")
  1443  		// test when there is order by column
  1444  		sel.OrderBy = []OrderByParams{{
  1445  			WeightStringCol: -1,
  1446  			Col:             0,
  1447  		}}
  1448  		_, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
  1449  		require.NoError(t, err, "unexpected ScatterErrorsAsWarnings error %v", err)
  1450  		vc.ExpectWarnings(t, []*querypb.QueryWarning{{Code: mysql.ERQueryInterrupted, Message: "query timeout -20 (errno 1317) (sqlstate HY000)"}})
  1451  	})
  1452  }
  1453  
  1454  func TestSelectEqualUniqueMultiColumnVindex(t *testing.T) {
  1455  	vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"})
  1456  	sel := NewRoute(
  1457  		EqualUnique,
  1458  		&vindexes.Keyspace{
  1459  			Name:    "ks",
  1460  			Sharded: true,
  1461  		},
  1462  		"dummy_select",
  1463  		"dummy_select_field",
  1464  	)
  1465  	sel.Vindex = vindex
  1466  	sel.Values = []evalengine.Expr{
  1467  		evalengine.NewLiteralInt(1),
  1468  		evalengine.NewLiteralInt(2),
  1469  	}
  1470  
  1471  	vc := &loggingVCursor{
  1472  		shards:  []string{"-20", "20-"},
  1473  		results: []*sqltypes.Result{defaultSelectResult},
  1474  	}
  1475  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1476  	require.NoError(t, err)
  1477  	vc.ExpectLog(t, []string{
  1478  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`,
  1479  		`ExecuteMultiShard ks.-20: dummy_select {} false false`,
  1480  	})
  1481  	expectResult(t, "sel.Execute", result, defaultSelectResult)
  1482  
  1483  	vc.Rewind()
  1484  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
  1485  	require.NoError(t, err)
  1486  	vc.ExpectLog(t, []string{
  1487  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(2)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f)`,
  1488  		`StreamExecuteMulti dummy_select ks.-20: {} `,
  1489  	})
  1490  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
  1491  }
  1492  
  1493  func TestSelectEqualMultiColumnVindex(t *testing.T) {
  1494  	vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"})
  1495  	vc := &loggingVCursor{
  1496  		shards:       []string{"-20", "20-"},
  1497  		shardForKsid: []string{"-20", "20-"},
  1498  		results:      []*sqltypes.Result{defaultSelectResult},
  1499  	}
  1500  	sel := NewRoute(
  1501  		Equal,
  1502  		&vindexes.Keyspace{
  1503  			Name:    "ks",
  1504  			Sharded: true,
  1505  		},
  1506  		"dummy_select",
  1507  		"dummy_select_field",
  1508  	)
  1509  	sel.Vindex = vindex
  1510  	sel.Values = []evalengine.Expr{evalengine.NewLiteralInt(32)}
  1511  
  1512  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1513  	require.NoError(t, err)
  1514  	vc.ExpectLog(t, []string{
  1515  		`ResolveDestinationsMultiCol ks [[INT64(32)]] Destinations:DestinationKeyRange(20-21)`,
  1516  		`ExecuteMultiShard ks.-20: dummy_select {} ks.20-: dummy_select {} false false`,
  1517  	})
  1518  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
  1519  
  1520  	vc.Rewind()
  1521  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
  1522  	require.NoError(t, err)
  1523  	vc.ExpectLog(t, []string{
  1524  		`ResolveDestinationsMultiCol ks [[INT64(32)]] Destinations:DestinationKeyRange(20-21)`,
  1525  		`StreamExecuteMulti dummy_select ks.-20: {} ks.20-: {} `,
  1526  	})
  1527  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
  1528  }
  1529  
  1530  func TestINMultiColumnVindex(t *testing.T) {
  1531  	vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"})
  1532  	sel := NewRoute(
  1533  		IN,
  1534  		&vindexes.Keyspace{
  1535  			Name:    "ks",
  1536  			Sharded: true,
  1537  		},
  1538  		"dummy_select",
  1539  		"dummy_select_field",
  1540  	)
  1541  	sel.Vindex = vindex
  1542  	sel.Values = []evalengine.Expr{
  1543  		evalengine.NewTupleExpr(
  1544  			evalengine.NewLiteralInt(1),
  1545  			evalengine.NewLiteralInt(2),
  1546  		),
  1547  		evalengine.NewTupleExpr(
  1548  			evalengine.NewLiteralInt(3),
  1549  			evalengine.NewLiteralInt(4),
  1550  		),
  1551  	}
  1552  
  1553  	vc := &loggingVCursor{
  1554  		shards:       []string{"-20", "20-"},
  1555  		shardForKsid: []string{"-20", "20-", "20-", "20-"},
  1556  		results:      []*sqltypes.Result{defaultSelectResult},
  1557  	}
  1558  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1559  	require.NoError(t, err)
  1560  	vc.ExpectLog(t, []string{
  1561  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(3)] [INT64(1) INT64(4)] [INT64(2) INT64(3)] [INT64(2) INT64(4)]] Destinations:DestinationKeyspaceID(014eb190c9a2fa169c),DestinationKeyspaceID(01d2fd8867d50d2dfe),DestinationKeyspaceID(024eb190c9a2fa169c),DestinationKeyspaceID(02d2fd8867d50d2dfe)`,
  1562  		`ExecuteMultiShard ks.-20: dummy_select {__vals0: type:TUPLE values:{type:INT64 value:"1"} __vals1: type:TUPLE values:{type:INT64 value:"3"}} ks.20-: dummy_select {__vals0: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"} __vals1: type:TUPLE values:{type:INT64 value:"4"} values:{type:INT64 value:"3"}} false false`,
  1563  	})
  1564  	expectResult(t, "sel.Execute", result, defaultSelectResult)
  1565  
  1566  	vc.Rewind()
  1567  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
  1568  	require.NoError(t, err)
  1569  	vc.ExpectLog(t, []string{
  1570  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(3)] [INT64(1) INT64(4)] [INT64(2) INT64(3)] [INT64(2) INT64(4)]] Destinations:DestinationKeyspaceID(014eb190c9a2fa169c),DestinationKeyspaceID(01d2fd8867d50d2dfe),DestinationKeyspaceID(024eb190c9a2fa169c),DestinationKeyspaceID(02d2fd8867d50d2dfe)`,
  1571  		`StreamExecuteMulti dummy_select ks.-20: {__vals0: type:TUPLE values:{type:INT64 value:"1"} __vals1: type:TUPLE values:{type:INT64 value:"3"}} ks.20-: {__vals0: type:TUPLE values:{type:INT64 value:"1"} values:{type:INT64 value:"2"} __vals1: type:TUPLE values:{type:INT64 value:"4"} values:{type:INT64 value:"3"}} `,
  1572  	})
  1573  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
  1574  }
  1575  
  1576  func TestINMixedMultiColumnComparision(t *testing.T) {
  1577  	vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"})
  1578  	sel := NewRoute(
  1579  		IN,
  1580  		&vindexes.Keyspace{
  1581  			Name:    "ks",
  1582  			Sharded: true,
  1583  		},
  1584  		"dummy_select",
  1585  		"dummy_select_field",
  1586  	)
  1587  	sel.Vindex = vindex
  1588  	sel.Values = []evalengine.Expr{
  1589  		evalengine.NewLiteralInt(1),
  1590  		evalengine.NewTupleExpr(
  1591  			evalengine.NewLiteralInt(3),
  1592  			evalengine.NewLiteralInt(4),
  1593  		),
  1594  	}
  1595  
  1596  	vc := &loggingVCursor{
  1597  		shards:       []string{"-20", "20-"},
  1598  		shardForKsid: []string{"-20", "20-"},
  1599  		results:      []*sqltypes.Result{defaultSelectResult},
  1600  	}
  1601  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1602  	require.NoError(t, err)
  1603  	vc.ExpectLog(t, []string{
  1604  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(3)] [INT64(1) INT64(4)]] Destinations:DestinationKeyspaceID(014eb190c9a2fa169c),DestinationKeyspaceID(01d2fd8867d50d2dfe)`,
  1605  		`ExecuteMultiShard ks.-20: dummy_select {__vals1: type:TUPLE values:{type:INT64 value:"3"}} ks.20-: dummy_select {__vals1: type:TUPLE values:{type:INT64 value:"4"}} false false`,
  1606  	})
  1607  	expectResult(t, "sel.Execute", result, defaultSelectResult)
  1608  
  1609  	vc.Rewind()
  1610  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
  1611  	require.NoError(t, err)
  1612  	vc.ExpectLog(t, []string{
  1613  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(3)] [INT64(1) INT64(4)]] Destinations:DestinationKeyspaceID(014eb190c9a2fa169c),DestinationKeyspaceID(01d2fd8867d50d2dfe)`,
  1614  		`StreamExecuteMulti dummy_select ks.-20: {__vals1: type:TUPLE values:{type:INT64 value:"3"}} ks.20-: {__vals1: type:TUPLE values:{type:INT64 value:"4"}} `,
  1615  	})
  1616  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
  1617  }
  1618  
  1619  func TestMultiEqualMultiCol(t *testing.T) {
  1620  	vindex, _ := vindexes.NewRegionExperimental("", map[string]string{"region_bytes": "1"})
  1621  	sel := NewRoute(
  1622  		MultiEqual,
  1623  		&vindexes.Keyspace{Name: "ks", Sharded: true},
  1624  		"dummy_select",
  1625  		"dummy_select_field",
  1626  	)
  1627  	sel.Vindex = vindex
  1628  	sel.Values = []evalengine.Expr{
  1629  		evalengine.NewTupleExpr(
  1630  			evalengine.NewLiteralInt(1),
  1631  			evalengine.NewLiteralInt(3),
  1632  		),
  1633  		evalengine.NewTupleExpr(
  1634  			evalengine.NewLiteralInt(2),
  1635  			evalengine.NewLiteralInt(4),
  1636  		),
  1637  	}
  1638  
  1639  	vc := &loggingVCursor{
  1640  		shards:       []string{"-20", "20-40", "40-"},
  1641  		shardForKsid: []string{"-20", "40-"},
  1642  		results:      []*sqltypes.Result{defaultSelectResult},
  1643  	}
  1644  	result, err := sel.TryExecute(context.Background(), vc, map[string]*querypb.BindVariable{}, false)
  1645  	require.NoError(t, err)
  1646  	vc.ExpectLog(t, []string{
  1647  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(2)] [INT64(3) INT64(4)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f),DestinationKeyspaceID(03d2fd8867d50d2dfe)`,
  1648  		`ExecuteMultiShard ks.-20: dummy_select {} ks.40-: dummy_select {} false false`,
  1649  	})
  1650  	expectResult(t, "sel.Execute", result, defaultSelectResult)
  1651  
  1652  	vc.Rewind()
  1653  	result, err = wrapStreamExecute(sel, vc, map[string]*querypb.BindVariable{}, false)
  1654  	require.NoError(t, err)
  1655  	vc.ExpectLog(t, []string{
  1656  		`ResolveDestinationsMultiCol ks [[INT64(1) INT64(2)] [INT64(3) INT64(4)]] Destinations:DestinationKeyspaceID(0106e7ea22ce92708f),DestinationKeyspaceID(03d2fd8867d50d2dfe)`,
  1657  		`StreamExecuteMulti dummy_select ks.-20: {} ks.40-: {} `,
  1658  	})
  1659  	expectResult(t, "sel.StreamExecute", result, defaultSelectResult)
  1660  }
  1661  
  1662  func TestBuildRowColValues(t *testing.T) {
  1663  	out := buildRowColValues([][]sqltypes.Value{
  1664  		{sqltypes.NewInt64(1), sqltypes.NewInt64(10)},
  1665  		{sqltypes.NewInt64(2), sqltypes.NewInt64(20)},
  1666  	}, []sqltypes.Value{
  1667  		sqltypes.NewInt64(3),
  1668  		sqltypes.NewInt64(4),
  1669  	})
  1670  
  1671  	require.Len(t, out, 4)
  1672  	require.EqualValues(t, "[INT64(1) INT64(10) INT64(3)]", fmt.Sprintf("%s", out[0]))
  1673  	require.EqualValues(t, "[INT64(1) INT64(10) INT64(4)]", fmt.Sprintf("%s", out[1]))
  1674  	require.EqualValues(t, "[INT64(2) INT64(20) INT64(3)]", fmt.Sprintf("%s", out[2]))
  1675  	require.EqualValues(t, "[INT64(2) INT64(20) INT64(4)]", fmt.Sprintf("%s", out[3]))
  1676  }
  1677  
  1678  func TestBuildMultiColumnVindexValues(t *testing.T) {
  1679  	testcases := []struct {
  1680  		input  [][][]sqltypes.Value
  1681  		output [][][]*querypb.Value
  1682  	}{
  1683  		{
  1684  			input: [][][]sqltypes.Value{
  1685  				{
  1686  					{sqltypes.NewInt64(1), sqltypes.NewInt64(10)},
  1687  					{sqltypes.NewInt64(2), sqltypes.NewInt64(20)},
  1688  				}, {
  1689  					{sqltypes.NewInt64(10), sqltypes.NewInt64(10)},
  1690  					{sqltypes.NewInt64(20), sqltypes.NewInt64(20)},
  1691  				},
  1692  			},
  1693  			output: [][][]*querypb.Value{
  1694  				{
  1695  					{sqltypes.ValueToProto(sqltypes.NewInt64(1)), sqltypes.ValueToProto(sqltypes.NewInt64(2))},
  1696  					{sqltypes.ValueToProto(sqltypes.NewInt64(10)), sqltypes.ValueToProto(sqltypes.NewInt64(20))},
  1697  				}, {
  1698  					{sqltypes.ValueToProto(sqltypes.NewInt64(10)), sqltypes.ValueToProto(sqltypes.NewInt64(20))},
  1699  					{sqltypes.ValueToProto(sqltypes.NewInt64(10)), sqltypes.ValueToProto(sqltypes.NewInt64(20))},
  1700  				},
  1701  			},
  1702  		}, {
  1703  			input: [][][]sqltypes.Value{{
  1704  				{sqltypes.NewInt64(10), sqltypes.NewInt64(10), sqltypes.NewInt64(1)},
  1705  				{sqltypes.NewInt64(20), sqltypes.NewInt64(20), sqltypes.NewInt64(1)},
  1706  			},
  1707  			},
  1708  			output: [][][]*querypb.Value{{
  1709  				{sqltypes.ValueToProto(sqltypes.NewInt64(10)), sqltypes.ValueToProto(sqltypes.NewInt64(20))},
  1710  				{sqltypes.ValueToProto(sqltypes.NewInt64(10)), sqltypes.ValueToProto(sqltypes.NewInt64(20))},
  1711  				{sqltypes.ValueToProto(sqltypes.NewInt64(1))},
  1712  			},
  1713  			},
  1714  		},
  1715  	}
  1716  
  1717  	for idx, testcase := range testcases {
  1718  		t.Run(strconv.Itoa(idx), func(t *testing.T) {
  1719  			out := buildMultiColumnVindexValues(testcase.input)
  1720  			require.EqualValues(t, testcase.output, out)
  1721  		})
  1722  	}
  1723  }