vitess.io/vitess@v0.16.2/go/vt/vtgate/executor_select_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 vtgate
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"os"
    23  	"runtime"
    24  	"strconv"
    25  	"strings"
    26  	"testing"
    27  	"time"
    28  
    29  	_flag "vitess.io/vitess/go/internal/flag"
    30  
    31  	"vitess.io/vitess/go/vt/sqlparser"
    32  
    33  	"github.com/google/go-cmp/cmp"
    34  	"github.com/stretchr/testify/assert"
    35  	"github.com/stretchr/testify/require"
    36  	"google.golang.org/protobuf/proto"
    37  
    38  	"vitess.io/vitess/go/cache"
    39  	"vitess.io/vitess/go/sqltypes"
    40  	"vitess.io/vitess/go/test/utils"
    41  	"vitess.io/vitess/go/vt/discovery"
    42  	"vitess.io/vitess/go/vt/vterrors"
    43  	_ "vitess.io/vitess/go/vt/vtgate/vindexes"
    44  	"vitess.io/vitess/go/vt/vttablet/sandboxconn"
    45  
    46  	querypb "vitess.io/vitess/go/vt/proto/query"
    47  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    48  	vtgatepb "vitess.io/vitess/go/vt/proto/vtgate"
    49  	vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc"
    50  )
    51  
    52  func TestSelectNext(t *testing.T) {
    53  	executor, _, _, sbclookup := createExecutorEnv()
    54  
    55  	query := "select next :n values from user_seq"
    56  	bv := map[string]*querypb.BindVariable{"n": sqltypes.Int64BindVariable(2)}
    57  	wantQueries := []*querypb.BoundQuery{{
    58  		Sql:           query,
    59  		BindVariables: map[string]*querypb.BindVariable{"n": sqltypes.Int64BindVariable(2)},
    60  	}}
    61  
    62  	// Autocommit
    63  	session := NewAutocommitSession(&vtgatepb.Session{})
    64  	_, err := executor.Execute(context.Background(), "TestSelectNext", session, query, bv)
    65  	require.NoError(t, err)
    66  
    67  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
    68  	assert.Zero(t, sbclookup.BeginCount.Get())
    69  	assert.Zero(t, sbclookup.ReserveCount.Get())
    70  	sbclookup.Queries = nil
    71  
    72  	// Txn
    73  	session = NewAutocommitSession(&vtgatepb.Session{})
    74  	session.Session.InTransaction = true
    75  	_, err = executor.Execute(context.Background(), "TestSelectNext", session, query, bv)
    76  	require.NoError(t, err)
    77  
    78  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
    79  	assert.Zero(t, sbclookup.BeginCount.Get())
    80  	assert.Zero(t, sbclookup.ReserveCount.Get())
    81  	sbclookup.Queries = nil
    82  
    83  	// Reserve
    84  	session = NewAutocommitSession(&vtgatepb.Session{})
    85  	session.Session.InReservedConn = true
    86  	_, err = executor.Execute(context.Background(), "TestSelectNext", session, query, bv)
    87  	require.NoError(t, err)
    88  
    89  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
    90  	assert.Zero(t, sbclookup.BeginCount.Get())
    91  	assert.Zero(t, sbclookup.ReserveCount.Get())
    92  	sbclookup.Queries = nil
    93  
    94  	// Reserve and Txn
    95  	session = NewAutocommitSession(&vtgatepb.Session{})
    96  	session.Session.InReservedConn = true
    97  	session.Session.InTransaction = true
    98  	_, err = executor.Execute(context.Background(), "TestSelectNext", session, query, bv)
    99  	require.NoError(t, err)
   100  
   101  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
   102  	assert.Zero(t, sbclookup.BeginCount.Get())
   103  	assert.Zero(t, sbclookup.ReserveCount.Get())
   104  }
   105  
   106  func TestSelectDBA(t *testing.T) {
   107  	executor, sbc1, _, _ := createExecutorEnv()
   108  
   109  	query := "select * from INFORMATION_SCHEMA.foo"
   110  	_, err := executor.Execute(context.Background(), "TestSelectDBA",
   111  		NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}),
   112  		query, map[string]*querypb.BindVariable{},
   113  	)
   114  	require.NoError(t, err)
   115  	wantQueries := []*querypb.BoundQuery{{Sql: query, BindVariables: map[string]*querypb.BindVariable{}}}
   116  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   117  
   118  	sbc1.Queries = nil
   119  	query = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES ist WHERE ist.table_schema = 'performance_schema' AND ist.table_name = 'foo'"
   120  	_, err = executor.Execute(context.Background(), "TestSelectDBA",
   121  		NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}),
   122  		query, map[string]*querypb.BindVariable{},
   123  	)
   124  	require.NoError(t, err)
   125  	wantQueries = []*querypb.BoundQuery{{Sql: "select count(*) from INFORMATION_SCHEMA.`TABLES` as ist where ist.table_schema = :__vtschemaname and ist.table_name = :ist_table_name",
   126  		BindVariables: map[string]*querypb.BindVariable{
   127  			"__vtschemaname": sqltypes.StringBindVariable("performance_schema"),
   128  			"ist_table_name": sqltypes.StringBindVariable("foo"),
   129  		}}}
   130  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   131  
   132  	sbc1.Queries = nil
   133  	query = "select 1 from information_schema.table_constraints where constraint_schema = 'vt_ks' and table_name = 'user'"
   134  	_, err = executor.Execute(context.Background(), "TestSelectDBA",
   135  		NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}),
   136  		query, map[string]*querypb.BindVariable{},
   137  	)
   138  	require.NoError(t, err)
   139  	wantQueries = []*querypb.BoundQuery{{Sql: "select 1 from information_schema.table_constraints where constraint_schema = :__vtschemaname and table_name = :table_name",
   140  		BindVariables: map[string]*querypb.BindVariable{
   141  			"__vtschemaname": sqltypes.StringBindVariable("vt_ks"),
   142  			"table_name":     sqltypes.StringBindVariable("user"),
   143  		}}}
   144  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   145  
   146  	sbc1.Queries = nil
   147  	query = "select 1 from information_schema.table_constraints where constraint_schema = 'vt_ks'"
   148  	_, err = executor.Execute(context.Background(), "TestSelectDBA",
   149  		NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}),
   150  		query, map[string]*querypb.BindVariable{},
   151  	)
   152  	require.NoError(t, err)
   153  	wantQueries = []*querypb.BoundQuery{{Sql: "select 1 from information_schema.table_constraints where constraint_schema = :__vtschemaname",
   154  		BindVariables: map[string]*querypb.BindVariable{
   155  			"__vtschemaname": sqltypes.StringBindVariable("vt_ks"),
   156  		}}}
   157  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   158  }
   159  
   160  func TestSystemVariablesMySQLBelow80(t *testing.T) {
   161  	executor, sbc1, _, _ := createExecutorEnv()
   162  	executor.normalize = true
   163  
   164  	sqlparser.SetParserVersion("57000")
   165  	setVarEnabled = true
   166  
   167  	session := NewAutocommitSession(&vtgatepb.Session{EnableSystemSettings: true, TargetString: "TestExecutor"})
   168  
   169  	sbc1.SetResults([]*sqltypes.Result{{
   170  		Fields: []*querypb.Field{
   171  			{Name: "orig", Type: sqltypes.VarChar},
   172  			{Name: "new", Type: sqltypes.VarChar},
   173  		},
   174  		Rows: [][]sqltypes.Value{{
   175  			sqltypes.NewVarChar(""),
   176  			sqltypes.NewVarChar("only_full_group_by"),
   177  		}},
   178  	}})
   179  
   180  	_, err := executor.Execute(context.Background(), "TestSetStmt", session, "set @@sql_mode = only_full_group_by", map[string]*querypb.BindVariable{})
   181  	require.NoError(t, err)
   182  
   183  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select 1 from information_schema.table", map[string]*querypb.BindVariable{})
   184  	require.NoError(t, err)
   185  	require.True(t, session.InReservedConn())
   186  
   187  	wantQueries := []*querypb.BoundQuery{
   188  		{Sql: "select @@sql_mode orig, 'only_full_group_by' new"},
   189  		{Sql: "set sql_mode = 'only_full_group_by'", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   190  		{Sql: "select :vtg1 from information_schema.`table`", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   191  	}
   192  
   193  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   194  }
   195  
   196  func TestSystemVariablesWithSetVarDisabled(t *testing.T) {
   197  	executor, sbc1, _, _ := createExecutorEnv()
   198  	executor.normalize = true
   199  
   200  	sqlparser.SetParserVersion("80000")
   201  	setVarEnabled = false
   202  	defer func() {
   203  		setVarEnabled = true
   204  	}()
   205  	session := NewAutocommitSession(&vtgatepb.Session{EnableSystemSettings: true, TargetString: "TestExecutor"})
   206  
   207  	sbc1.SetResults([]*sqltypes.Result{{
   208  		Fields: []*querypb.Field{
   209  			{Name: "orig", Type: sqltypes.VarChar},
   210  			{Name: "new", Type: sqltypes.VarChar},
   211  		},
   212  		Rows: [][]sqltypes.Value{{
   213  			sqltypes.NewVarChar(""),
   214  			sqltypes.NewVarChar("only_full_group_by"),
   215  		}},
   216  	}})
   217  
   218  	_, err := executor.Execute(context.Background(), "TestSetStmt", session, "set @@sql_mode = only_full_group_by", map[string]*querypb.BindVariable{})
   219  	require.NoError(t, err)
   220  
   221  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select 1 from information_schema.table", map[string]*querypb.BindVariable{})
   222  	require.NoError(t, err)
   223  	require.True(t, session.InReservedConn())
   224  
   225  	wantQueries := []*querypb.BoundQuery{
   226  		{Sql: "select @@sql_mode orig, 'only_full_group_by' new"},
   227  		{Sql: "set sql_mode = 'only_full_group_by'", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   228  		{Sql: "select :vtg1 from information_schema.`table`", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   229  	}
   230  
   231  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   232  }
   233  
   234  func TestSetSystemVariablesTx(t *testing.T) {
   235  	executor, sbc1, _, _ := createExecutorEnv()
   236  	executor.normalize = true
   237  
   238  	sqlparser.SetParserVersion("80001")
   239  
   240  	session := NewAutocommitSession(&vtgatepb.Session{EnableSystemSettings: true, TargetString: "TestExecutor"})
   241  
   242  	_, err := executor.Execute(context.Background(), "TestBegin", session, "begin", map[string]*querypb.BindVariable{})
   243  	require.NoError(t, err)
   244  
   245  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select 1 from information_schema.table", map[string]*querypb.BindVariable{})
   246  	require.NoError(t, err)
   247  	require.NotZero(t, session.ShardSessions)
   248  
   249  	sbc1.SetResults([]*sqltypes.Result{{
   250  		Fields: []*querypb.Field{
   251  			{Name: "orig", Type: sqltypes.VarChar},
   252  			{Name: "new", Type: sqltypes.VarChar},
   253  		},
   254  		Rows: [][]sqltypes.Value{{
   255  			sqltypes.NewVarChar(""),
   256  			sqltypes.NewVarChar("only_full_group_by"),
   257  		}},
   258  	}})
   259  
   260  	_, err = executor.Execute(context.Background(), "TestSetStmt", session, "set @@sql_mode = only_full_group_by", map[string]*querypb.BindVariable{})
   261  	require.NoError(t, err)
   262  	require.False(t, session.InReservedConn())
   263  
   264  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select 1 from information_schema.table", map[string]*querypb.BindVariable{})
   265  	require.NoError(t, err)
   266  
   267  	_, err = executor.Execute(context.Background(), "TestCommit", session, "commit", map[string]*querypb.BindVariable{})
   268  	require.NoError(t, err)
   269  	require.False(t, session.InReservedConn())
   270  
   271  	require.Zero(t, session.ShardSessions)
   272  
   273  	wantQueries := []*querypb.BoundQuery{
   274  		{Sql: "select :vtg1 from information_schema.`table`", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   275  		{Sql: "select @@sql_mode orig, 'only_full_group_by' new"},
   276  		{Sql: "select /*+ SET_VAR(sql_mode = 'only_full_group_by') */ :vtg1 from information_schema.`table`", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   277  	}
   278  
   279  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   280  }
   281  
   282  func TestSetSystemVariables(t *testing.T) {
   283  	executor, _, _, lookup := createExecutorEnv()
   284  	executor.normalize = true
   285  
   286  	sqlparser.SetParserVersion("80001")
   287  
   288  	session := NewAutocommitSession(&vtgatepb.Session{EnableSystemSettings: true, TargetString: KsTestUnsharded, SystemVariables: map[string]string{}})
   289  
   290  	// Set @@sql_mode and execute a select statement. We should have SET_VAR in the select statement
   291  
   292  	lookup.SetResults([]*sqltypes.Result{{
   293  		Fields: []*querypb.Field{
   294  			{Name: "orig", Type: sqltypes.VarChar},
   295  			{Name: "new", Type: sqltypes.VarChar},
   296  		},
   297  		Rows: [][]sqltypes.Value{{
   298  			sqltypes.NewVarChar(""),
   299  			sqltypes.NewVarChar("only_full_group_by"),
   300  		}},
   301  	}})
   302  	_, err := executor.Execute(context.Background(), "TestSetStmt", session, "set @@sql_mode = only_full_group_by", map[string]*querypb.BindVariable{})
   303  	require.NoError(t, err)
   304  
   305  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select 1 from information_schema.table", map[string]*querypb.BindVariable{})
   306  	require.NoError(t, err)
   307  	require.False(t, session.InReservedConn())
   308  	wantQueries := []*querypb.BoundQuery{
   309  		{Sql: "select @@sql_mode orig, 'only_full_group_by' new"},
   310  		{Sql: "select /*+ SET_VAR(sql_mode = 'only_full_group_by') */ :vtg1 from information_schema.`table`", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   311  	}
   312  	utils.MustMatch(t, wantQueries, lookup.Queries)
   313  	lookup.Queries = nil
   314  
   315  	// Execute a select with a comment that needs a query hint
   316  
   317  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select /* comment */ 1 from information_schema.table", map[string]*querypb.BindVariable{})
   318  	require.NoError(t, err)
   319  	require.False(t, session.InReservedConn())
   320  	wantQueries = []*querypb.BoundQuery{
   321  		{Sql: "select /*+ SET_VAR(sql_mode = 'only_full_group_by') */ /* comment */ :vtg1 from information_schema.`table`", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   322  	}
   323  	utils.MustMatch(t, wantQueries, lookup.Queries)
   324  	lookup.Queries = nil
   325  
   326  	lookup.SetResults([]*sqltypes.Result{{
   327  		Fields: []*querypb.Field{
   328  			{Name: "sql_safe_updates", Type: sqltypes.VarChar},
   329  		},
   330  		Rows: [][]sqltypes.Value{{
   331  			sqltypes.NewVarChar("0"),
   332  		}},
   333  	}})
   334  	_, err = executor.Execute(context.Background(), "TestSetStmt", session, "set @@sql_safe_updates = 0", map[string]*querypb.BindVariable{})
   335  	require.NoError(t, err)
   336  	require.False(t, session.InReservedConn())
   337  	wantQueries = []*querypb.BoundQuery{
   338  		{Sql: "select 0 from dual where @@sql_safe_updates != 0"},
   339  	}
   340  	utils.MustMatch(t, wantQueries, lookup.Queries)
   341  	lookup.Queries = nil
   342  
   343  	_, err = executor.Execute(context.Background(), "TestSetStmt", session, "set @var = @@sql_mode", map[string]*querypb.BindVariable{})
   344  	require.NoError(t, err)
   345  	require.False(t, session.InReservedConn())
   346  	require.Nil(t, lookup.Queries)
   347  	require.Equal(t, "only_full_group_by", string(session.UserDefinedVariables["var"].GetValue()))
   348  
   349  	lookup.SetResults([]*sqltypes.Result{{
   350  		Fields: []*querypb.Field{
   351  			{Name: "max_tmp_tables", Type: sqltypes.VarChar},
   352  		},
   353  		Rows: [][]sqltypes.Value{{
   354  			sqltypes.NewVarChar("4"),
   355  		}},
   356  	}})
   357  	_, err = executor.Execute(context.Background(), "TestSetStmt", session, "set @x = @@sql_mode, @y = @@max_tmp_tables", map[string]*querypb.BindVariable{})
   358  	require.NoError(t, err)
   359  	require.False(t, session.InReservedConn())
   360  	wantQueries = []*querypb.BoundQuery{
   361  		{Sql: "select @@max_tmp_tables from dual", BindVariables: map[string]*querypb.BindVariable{"__vtsql_mode": sqltypes.StringBindVariable("only_full_group_by")}},
   362  	}
   363  	utils.MustMatch(t, wantQueries, lookup.Queries)
   364  	require.Equal(t, "only_full_group_by", string(session.UserDefinedVariables["var"].GetValue()))
   365  	require.Equal(t, "only_full_group_by", string(session.UserDefinedVariables["x"].GetValue()))
   366  	require.Equal(t, "4", string(session.UserDefinedVariables["y"].GetValue()))
   367  	lookup.Queries = nil
   368  
   369  	// Set system variable that is not supported by SET_VAR
   370  	// We expect the next select to not have any SET_VAR query hint, instead it will use set statements
   371  
   372  	lookup.SetResults([]*sqltypes.Result{{
   373  		Fields: []*querypb.Field{
   374  			{Name: "max_tmp_tables", Type: sqltypes.VarChar},
   375  		},
   376  		Rows: [][]sqltypes.Value{{
   377  			sqltypes.NewVarChar("1"),
   378  		}},
   379  	}})
   380  	_, err = executor.Execute(context.Background(), "TestSetStmt", session, "set @@max_tmp_tables = 1", map[string]*querypb.BindVariable{})
   381  	require.NoError(t, err)
   382  	require.True(t, session.InReservedConn())
   383  
   384  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select 1 from information_schema.table", map[string]*querypb.BindVariable{})
   385  	require.NoError(t, err)
   386  
   387  	wantQueries = []*querypb.BoundQuery{
   388  		{Sql: "select 1 from dual where @@max_tmp_tables != 1"},
   389  		{Sql: "set max_tmp_tables = '1', sql_mode = 'only_full_group_by', sql_safe_updates = '0'", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   390  		{Sql: "select :vtg1 from information_schema.`table`", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   391  	}
   392  	utils.MustMatch(t, wantQueries, lookup.Queries)
   393  }
   394  
   395  func TestSetSystemVariablesWithReservedConnection(t *testing.T) {
   396  	executor, sbc1, _, _ := createExecutorEnv()
   397  	executor.normalize = true
   398  
   399  	session := NewAutocommitSession(&vtgatepb.Session{EnableSystemSettings: true, SystemVariables: map[string]string{}})
   400  
   401  	sbc1.SetResults([]*sqltypes.Result{{
   402  		Fields: []*querypb.Field{
   403  			{Name: "orig", Type: sqltypes.VarChar},
   404  			{Name: "new", Type: sqltypes.VarChar},
   405  		},
   406  		Rows: [][]sqltypes.Value{{
   407  			sqltypes.NewVarChar("only_full_group_by"),
   408  			sqltypes.NewVarChar(""),
   409  		}},
   410  	}})
   411  	_, err := executor.Execute(context.Background(), "TestSetStmt", session, "set @@sql_mode = ''", map[string]*querypb.BindVariable{})
   412  	require.NoError(t, err)
   413  
   414  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select age, city from user group by age", map[string]*querypb.BindVariable{})
   415  	require.NoError(t, err)
   416  	require.True(t, session.InReservedConn())
   417  	wantQueries := []*querypb.BoundQuery{
   418  		{Sql: "select @@sql_mode orig, '' new"},
   419  		{Sql: "set sql_mode = ''"},
   420  		{Sql: "select age, city, weight_string(age) from `user` group by age, weight_string(age) order by age asc"},
   421  	}
   422  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   423  
   424  	_, err = executor.Execute(context.Background(), "TestSelect", session, "select age, city+1 from user group by age", map[string]*querypb.BindVariable{})
   425  	require.NoError(t, err)
   426  	require.True(t, session.InReservedConn())
   427  	wantQueries = []*querypb.BoundQuery{
   428  		{Sql: "select @@sql_mode orig, '' new"},
   429  		{Sql: "set sql_mode = ''"},
   430  		{Sql: "select age, city, weight_string(age) from `user` group by age, weight_string(age) order by age asc"},
   431  		{Sql: "select age, city + :vtg1, weight_string(age) from `user` group by age, weight_string(age) order by age asc", BindVariables: map[string]*querypb.BindVariable{"vtg1": {Type: sqltypes.Int64, Value: []byte("1")}}},
   432  	}
   433  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   434  	require.Equal(t, "''", session.SystemVariables["sql_mode"])
   435  	sbc1.Queries = nil
   436  }
   437  
   438  func TestCreateTableValidTimestamp(t *testing.T) {
   439  	executor, sbc1, _, _ := createExecutorEnv()
   440  	executor.normalize = true
   441  
   442  	session := NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor", SystemVariables: map[string]string{"sql_mode": "ALLOW_INVALID_DATES"}})
   443  
   444  	query := "create table aa(t timestamp default 0)"
   445  	_, err := executor.Execute(context.Background(), "TestSelect", session, query, map[string]*querypb.BindVariable{})
   446  	require.NoError(t, err)
   447  	require.True(t, session.InReservedConn())
   448  
   449  	wantQueries := []*querypb.BoundQuery{
   450  		{Sql: "set sql_mode = ALLOW_INVALID_DATES", BindVariables: map[string]*querypb.BindVariable{}},
   451  		{Sql: "create table aa (\n\tt timestamp default 0\n)", BindVariables: map[string]*querypb.BindVariable{}},
   452  	}
   453  
   454  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   455  }
   456  
   457  func TestGen4SelectDBA(t *testing.T) {
   458  	executor, sbc1, _, _ := createExecutorEnv()
   459  	executor.normalize = true
   460  	executor.pv = querypb.ExecuteOptions_Gen4
   461  
   462  	query := "select * from INFORMATION_SCHEMA.TABLE_CONSTRAINTS"
   463  	_, err := executor.Execute(context.Background(), "TestSelectDBA",
   464  		NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}),
   465  		query, map[string]*querypb.BindVariable{},
   466  	)
   467  	require.NoError(t, err)
   468  	expected := "select CONSTRAINT_CATALOG, CONSTRAINT_SCHEMA, CONSTRAINT_NAME, TABLE_SCHEMA, TABLE_NAME, CONSTRAINT_TYPE, `ENFORCED` from INFORMATION_SCHEMA.TABLE_CONSTRAINTS"
   469  	wantQueries := []*querypb.BoundQuery{{Sql: expected, BindVariables: map[string]*querypb.BindVariable{}}}
   470  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   471  
   472  	sbc1.Queries = nil
   473  	query = "SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES ist WHERE ist.table_schema = 'performance_schema' AND ist.table_name = 'foo'"
   474  	_, err = executor.Execute(context.Background(), "TestSelectDBA",
   475  		NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}),
   476  		query, map[string]*querypb.BindVariable{},
   477  	)
   478  	require.NoError(t, err)
   479  	wantQueries = []*querypb.BoundQuery{{Sql: "select count(*) from INFORMATION_SCHEMA.`TABLES` as ist where ist.table_schema = :__vtschemaname and ist.table_name = :ist_table_name1",
   480  		BindVariables: map[string]*querypb.BindVariable{
   481  			"ist_table_schema": sqltypes.StringBindVariable("performance_schema"),
   482  			"__vtschemaname":   sqltypes.StringBindVariable("performance_schema"),
   483  			"ist_table_name":   sqltypes.StringBindVariable("foo"),
   484  			"ist_table_name1":  sqltypes.StringBindVariable("foo"),
   485  		}}}
   486  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   487  
   488  	sbc1.Queries = nil
   489  	query = "select 1 from information_schema.table_constraints where constraint_schema = 'vt_ks' and table_name = 'user'"
   490  	_, err = executor.Execute(context.Background(), "TestSelectDBA",
   491  		NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}),
   492  		query, map[string]*querypb.BindVariable{},
   493  	)
   494  	require.NoError(t, err)
   495  	wantQueries = []*querypb.BoundQuery{{Sql: "select :vtg1 from information_schema.table_constraints where constraint_schema = :__vtschemaname and table_name = :table_name1",
   496  		BindVariables: map[string]*querypb.BindVariable{
   497  			"vtg1":              sqltypes.Int64BindVariable(1),
   498  			"constraint_schema": sqltypes.StringBindVariable("vt_ks"),
   499  			"table_name":        sqltypes.StringBindVariable("user"),
   500  			"__vtschemaname":    sqltypes.StringBindVariable("vt_ks"),
   501  			"table_name1":       sqltypes.StringBindVariable("user"),
   502  		}}}
   503  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   504  
   505  	sbc1.Queries = nil
   506  	query = "select 1 from information_schema.table_constraints where constraint_schema = 'vt_ks'"
   507  	_, err = executor.Execute(context.Background(), "TestSelectDBA",
   508  		NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}),
   509  		query, map[string]*querypb.BindVariable{},
   510  	)
   511  	require.NoError(t, err)
   512  	wantQueries = []*querypb.BoundQuery{{Sql: "select :vtg1 from information_schema.table_constraints where constraint_schema = :__vtschemaname",
   513  		BindVariables: map[string]*querypb.BindVariable{
   514  			"vtg1":              sqltypes.Int64BindVariable(1),
   515  			"constraint_schema": sqltypes.StringBindVariable("vt_ks"),
   516  			"__vtschemaname":    sqltypes.StringBindVariable("vt_ks"),
   517  		}}}
   518  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   519  
   520  	sbc1.Queries = nil
   521  	query = "select t.table_schema,t.table_name,c.column_name,c.column_type from tables t join columns c on c.table_schema = t.table_schema and c.table_name = t.table_name where t.table_schema = 'TestExecutor' and c.table_schema = 'TestExecutor' order by t.table_schema,t.table_name,c.column_name"
   522  	_, err = executor.Execute(context.Background(), "TestSelectDBA",
   523  		NewSafeSession(&vtgatepb.Session{TargetString: "information_schema"}),
   524  		query, map[string]*querypb.BindVariable{},
   525  	)
   526  	require.NoError(t, err)
   527  	wantQueries = []*querypb.BoundQuery{{Sql: "select t.table_schema, t.table_name, c.column_name, c.column_type from information_schema.`tables` as t, information_schema.`columns` as c where t.table_schema = :__vtschemaname and c.table_schema = :__vtschemaname and c.table_schema = t.table_schema and c.table_name = t.table_name order by t.table_schema asc, t.table_name asc, c.column_name asc",
   528  		BindVariables: map[string]*querypb.BindVariable{
   529  			"t_table_schema":        sqltypes.StringBindVariable("TestExecutor"),
   530  			"__replacevtschemaname": sqltypes.Int64BindVariable(1),
   531  		}}}
   532  	utils.MustMatch(t, wantQueries, sbc1.Queries)
   533  }
   534  
   535  func TestUnsharded(t *testing.T) {
   536  	executor, _, _, sbclookup := createExecutorEnv()
   537  
   538  	_, err := executorExec(executor, "select id from music_user_map where id = 1", nil)
   539  	require.NoError(t, err)
   540  	wantQueries := []*querypb.BoundQuery{{
   541  		Sql:           "select id from music_user_map where id = 1",
   542  		BindVariables: map[string]*querypb.BindVariable{},
   543  	}}
   544  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
   545  }
   546  
   547  func TestUnshardedComments(t *testing.T) {
   548  	executor, _, _, sbclookup := createExecutorEnv()
   549  
   550  	_, err := executorExec(executor, "/* leading */ select id from music_user_map where id = 1 /* trailing */", nil)
   551  	require.NoError(t, err)
   552  	wantQueries := []*querypb.BoundQuery{{
   553  		Sql:           "/* leading */ select id from music_user_map where id = 1 /* trailing */",
   554  		BindVariables: map[string]*querypb.BindVariable{},
   555  	}}
   556  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
   557  
   558  	_, err = executorExec(executor, "update music_user_map set id = 1 /* trailing */", nil)
   559  	require.NoError(t, err)
   560  	wantQueries = []*querypb.BoundQuery{{
   561  		Sql:           "/* leading */ select id from music_user_map where id = 1 /* trailing */",
   562  		BindVariables: map[string]*querypb.BindVariable{},
   563  	}, {
   564  		Sql:           "update music_user_map set id = 1 /* trailing */",
   565  		BindVariables: map[string]*querypb.BindVariable{},
   566  	}}
   567  	assertQueries(t, sbclookup, wantQueries)
   568  
   569  	sbclookup.Queries = nil
   570  	_, err = executorExec(executor, "delete from music_user_map /* trailing */", nil)
   571  	require.NoError(t, err)
   572  	wantQueries = []*querypb.BoundQuery{{
   573  		Sql:           "delete from music_user_map /* trailing */",
   574  		BindVariables: map[string]*querypb.BindVariable{},
   575  	}}
   576  	assertQueries(t, sbclookup, wantQueries)
   577  
   578  	sbclookup.Queries = nil
   579  	_, err = executorExec(executor, "insert into music_user_map values (1) /* trailing */", nil)
   580  	require.NoError(t, err)
   581  	wantQueries = []*querypb.BoundQuery{{
   582  		Sql:           "insert into music_user_map values (1) /* trailing */",
   583  		BindVariables: map[string]*querypb.BindVariable{},
   584  	}}
   585  	assertQueries(t, sbclookup, wantQueries)
   586  }
   587  
   588  func TestStreamUnsharded(t *testing.T) {
   589  	executor, _, _, _ := createExecutorEnv()
   590  	logChan := QueryLogger.Subscribe("Test")
   591  	defer QueryLogger.Unsubscribe(logChan)
   592  
   593  	sql := "select id from music_user_map where id = 1"
   594  	result, err := executorStream(executor, sql)
   595  	require.NoError(t, err)
   596  	wantResult := sandboxconn.StreamRowResult
   597  	if !result.Equal(wantResult) {
   598  		diff := cmp.Diff(wantResult, result)
   599  		t.Errorf("result: %+v, want %+v\ndiff: %s", result, wantResult, diff)
   600  	}
   601  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", sql, 1)
   602  }
   603  
   604  func TestStreamBuffering(t *testing.T) {
   605  	executor, _, _, sbclookup := createExecutorEnv()
   606  
   607  	// This test is similar to TestStreamUnsharded except that it returns a Result > 10 bytes,
   608  	// such that the splitting of the Result into multiple Result responses gets tested.
   609  	sbclookup.SetResults([]*sqltypes.Result{{
   610  		Fields: []*querypb.Field{
   611  			{Name: "id", Type: sqltypes.Int32},
   612  			{Name: "col", Type: sqltypes.VarChar},
   613  		},
   614  		Rows: [][]sqltypes.Value{{
   615  			sqltypes.NewInt32(1),
   616  			sqltypes.NewVarChar("01234567890123456789"),
   617  		}, {
   618  			sqltypes.NewInt32(2),
   619  			sqltypes.NewVarChar("12345678901234567890"),
   620  		}},
   621  	}})
   622  
   623  	var results []*sqltypes.Result
   624  	err := executor.StreamExecute(
   625  		context.Background(),
   626  		"TestStreamBuffering",
   627  		NewSafeSession(primarySession),
   628  		"select id from music_user_map where id = 1",
   629  		nil,
   630  		func(qr *sqltypes.Result) error {
   631  			results = append(results, qr)
   632  			return nil
   633  		},
   634  	)
   635  	require.NoError(t, err)
   636  	wantResults := []*sqltypes.Result{{
   637  		Fields: []*querypb.Field{
   638  			{Name: "id", Type: sqltypes.Int32},
   639  			{Name: "col", Type: sqltypes.VarChar},
   640  		},
   641  	}, {
   642  		Rows: [][]sqltypes.Value{{
   643  			sqltypes.NewInt32(1),
   644  			sqltypes.NewVarChar("01234567890123456789"),
   645  		}},
   646  	}, {
   647  		Rows: [][]sqltypes.Value{{
   648  			sqltypes.NewInt32(2),
   649  			sqltypes.NewVarChar("12345678901234567890"),
   650  		}},
   651  	}}
   652  	utils.MustMatch(t, wantResults, results)
   653  }
   654  
   655  func TestStreamLimitOffset(t *testing.T) {
   656  	executor, sbc1, sbc2, _ := createExecutorEnv()
   657  
   658  	// This test is similar to TestStreamUnsharded except that it returns a Result > 10 bytes,
   659  	// such that the splitting of the Result into multiple Result responses gets tested.
   660  	sbc1.SetResults([]*sqltypes.Result{{
   661  		Fields: []*querypb.Field{
   662  			{Name: "id", Type: sqltypes.Int32},
   663  			{Name: "textcol", Type: sqltypes.VarChar},
   664  			{Name: "weight_string(id)", Type: sqltypes.VarBinary},
   665  		},
   666  		Rows: [][]sqltypes.Value{{
   667  			sqltypes.NewInt32(1),
   668  			sqltypes.NewVarChar("1234"),
   669  			sqltypes.NULL,
   670  		}, {
   671  			sqltypes.NewInt32(4),
   672  			sqltypes.NewVarChar("4567"),
   673  			sqltypes.NULL,
   674  		}},
   675  	}})
   676  
   677  	sbc2.SetResults([]*sqltypes.Result{{
   678  		Fields: []*querypb.Field{
   679  			{Name: "id", Type: sqltypes.Int32},
   680  			{Name: "textcol", Type: sqltypes.VarChar},
   681  			{Name: "weight_string(id)", Type: sqltypes.VarBinary},
   682  		},
   683  		Rows: [][]sqltypes.Value{{
   684  			sqltypes.NewInt32(2),
   685  			sqltypes.NewVarChar("2345"),
   686  			sqltypes.NULL,
   687  		}},
   688  	}})
   689  
   690  	results := make(chan *sqltypes.Result, 10)
   691  	err := executor.StreamExecute(
   692  		context.Background(),
   693  		"TestStreamLimitOffset",
   694  		NewSafeSession(primarySession),
   695  		"select id, textcol from user order by id limit 2 offset 2",
   696  		nil,
   697  		func(qr *sqltypes.Result) error {
   698  			results <- qr
   699  			return nil
   700  		},
   701  	)
   702  	close(results)
   703  	require.NoError(t, err)
   704  	wantResult := &sqltypes.Result{
   705  		Fields: []*querypb.Field{
   706  			{Name: "id", Type: sqltypes.Int32},
   707  			{Name: "textcol", Type: sqltypes.VarChar},
   708  		},
   709  
   710  		Rows: [][]sqltypes.Value{{
   711  			sqltypes.NewInt32(1),
   712  			sqltypes.NewVarChar("1234"),
   713  		}, {
   714  			sqltypes.NewInt32(1),
   715  			sqltypes.NewVarChar("foo"),
   716  		}},
   717  	}
   718  	var gotResults []*sqltypes.Result
   719  	for r := range results {
   720  		gotResults = append(gotResults, r)
   721  	}
   722  	res := gotResults[0]
   723  	for i := 1; i < len(gotResults); i++ {
   724  		res.Rows = append(res.Rows, gotResults[i].Rows...)
   725  	}
   726  	utils.MustMatch(t, wantResult, res, "")
   727  }
   728  
   729  func TestSelectLastInsertId(t *testing.T) {
   730  	executor, _, _, _ := createExecutorEnv()
   731  	primarySession.LastInsertId = 52
   732  	executor.normalize = true
   733  	logChan := QueryLogger.Subscribe("Test")
   734  	defer QueryLogger.Unsubscribe(logChan)
   735  
   736  	sql := "select last_insert_id()"
   737  	result, err := executorExec(executor, sql, map[string]*querypb.BindVariable{})
   738  	wantResult := &sqltypes.Result{
   739  		Fields: []*querypb.Field{
   740  			{Name: "last_insert_id()", Type: sqltypes.Uint64},
   741  		},
   742  		Rows: [][]sqltypes.Value{{
   743  			sqltypes.NewUint64(52),
   744  		}},
   745  	}
   746  	require.NoError(t, err)
   747  	utils.MustMatch(t, wantResult, result, "Mismatch")
   748  }
   749  
   750  func TestSelectSystemVariables(t *testing.T) {
   751  	executor, _, _, _ := createExecutorEnv()
   752  	primarySession.ReadAfterWrite = &vtgatepb.ReadAfterWrite{
   753  		ReadAfterWriteGtid:    "a fine gtid",
   754  		ReadAfterWriteTimeout: 13,
   755  		SessionTrackGtids:     true,
   756  	}
   757  	executor.normalize = true
   758  	logChan := QueryLogger.Subscribe("Test")
   759  	defer QueryLogger.Unsubscribe(logChan)
   760  
   761  	sql := "select @@autocommit, @@client_found_rows, @@skip_query_plan_cache, @@enable_system_settings, " +
   762  		"@@sql_select_limit, @@transaction_mode, @@workload, @@read_after_write_gtid, " +
   763  		"@@read_after_write_timeout, @@session_track_gtids, @@ddl_strategy, @@socket, @@query_timeout"
   764  
   765  	result, err := executorExec(executor, sql, map[string]*querypb.BindVariable{})
   766  	wantResult := &sqltypes.Result{
   767  		Fields: []*querypb.Field{
   768  			{Name: "@@autocommit", Type: sqltypes.Int64},
   769  			{Name: "@@client_found_rows", Type: sqltypes.Int64},
   770  			{Name: "@@skip_query_plan_cache", Type: sqltypes.Int64},
   771  			{Name: "@@enable_system_settings", Type: sqltypes.Int64},
   772  			{Name: "@@sql_select_limit", Type: sqltypes.Int64},
   773  			{Name: "@@transaction_mode", Type: sqltypes.VarChar},
   774  			{Name: "@@workload", Type: sqltypes.VarChar},
   775  			{Name: "@@read_after_write_gtid", Type: sqltypes.VarChar},
   776  			{Name: "@@read_after_write_timeout", Type: sqltypes.Float64},
   777  			{Name: "@@session_track_gtids", Type: sqltypes.VarChar},
   778  			{Name: "@@ddl_strategy", Type: sqltypes.VarChar},
   779  			{Name: "@@socket", Type: sqltypes.VarChar},
   780  			{Name: "@@query_timeout", Type: sqltypes.Int64},
   781  		},
   782  		Rows: [][]sqltypes.Value{{
   783  			// the following are the uninitialised session values
   784  			sqltypes.NewInt64(0),
   785  			sqltypes.NewInt64(0),
   786  			sqltypes.NewInt64(0),
   787  			sqltypes.NewInt64(0),
   788  			sqltypes.NewInt64(0),
   789  			sqltypes.NewVarChar("UNSPECIFIED"),
   790  			sqltypes.NewVarChar(""),
   791  			// these have been set at the beginning of the test
   792  			sqltypes.NewVarChar("a fine gtid"),
   793  			sqltypes.NewFloat64(13),
   794  			sqltypes.NewVarChar("own_gtid"),
   795  			sqltypes.NewVarChar(""),
   796  			sqltypes.NewVarChar(""),
   797  			sqltypes.NewInt64(0),
   798  		}},
   799  	}
   800  	require.NoError(t, err)
   801  	utils.MustMatch(t, wantResult, result, "Mismatch")
   802  }
   803  
   804  func TestSelectInitializedVitessAwareVariable(t *testing.T) {
   805  	executor, _, _, _ := createExecutorEnv()
   806  	executor.normalize = true
   807  	logChan := QueryLogger.Subscribe("Test")
   808  	defer QueryLogger.Unsubscribe(logChan)
   809  
   810  	primarySession.Autocommit = true
   811  	primarySession.EnableSystemSettings = true
   812  	primarySession.QueryTimeout = 75
   813  
   814  	defer func() {
   815  		primarySession.Autocommit = false
   816  		primarySession.EnableSystemSettings = false
   817  		primarySession.QueryTimeout = 0
   818  	}()
   819  
   820  	sql := "select @@autocommit, @@enable_system_settings, @@query_timeout"
   821  
   822  	result, err := executorExec(executor, sql, nil)
   823  	wantResult := &sqltypes.Result{
   824  		Fields: []*querypb.Field{
   825  			{Name: "@@autocommit", Type: sqltypes.Int64},
   826  			{Name: "@@enable_system_settings", Type: sqltypes.Int64},
   827  			{Name: "@@query_timeout", Type: sqltypes.Int64},
   828  		},
   829  		Rows: [][]sqltypes.Value{{
   830  			sqltypes.NewInt64(1),
   831  			sqltypes.NewInt64(1),
   832  			sqltypes.NewInt64(75),
   833  		}},
   834  	}
   835  	require.NoError(t, err)
   836  	utils.MustMatch(t, wantResult, result, "Mismatch")
   837  }
   838  
   839  func TestSelectUserDefinedVariable(t *testing.T) {
   840  	executor, _, _, _ := createExecutorEnv()
   841  	executor.normalize = true
   842  	logChan := QueryLogger.Subscribe("Test")
   843  	defer QueryLogger.Unsubscribe(logChan)
   844  
   845  	sql := "select @foo"
   846  	result, err := executorExec(executor, sql, map[string]*querypb.BindVariable{})
   847  	require.NoError(t, err)
   848  	wantResult := &sqltypes.Result{
   849  		Fields: []*querypb.Field{
   850  			{Name: "@foo", Type: sqltypes.Null},
   851  		},
   852  		Rows: [][]sqltypes.Value{{
   853  			sqltypes.NULL,
   854  		}},
   855  	}
   856  	utils.MustMatch(t, wantResult, result, "Mismatch")
   857  
   858  	primarySession = &vtgatepb.Session{UserDefinedVariables: createMap([]string{"foo"}, []any{"bar"})}
   859  	result, err = executorExec(executor, sql, map[string]*querypb.BindVariable{})
   860  	require.NoError(t, err)
   861  	wantResult = &sqltypes.Result{
   862  		Fields: []*querypb.Field{
   863  			{Name: "@foo", Type: sqltypes.VarChar},
   864  		},
   865  		Rows: [][]sqltypes.Value{{
   866  			sqltypes.NewVarChar("bar"),
   867  		}},
   868  	}
   869  	utils.MustMatch(t, wantResult, result, "Mismatch")
   870  }
   871  
   872  func TestFoundRows(t *testing.T) {
   873  	executor, _, _, _ := createExecutorEnv()
   874  	executor.normalize = true
   875  	logChan := QueryLogger.Subscribe("Test")
   876  	defer QueryLogger.Unsubscribe(logChan)
   877  
   878  	// run this extra query so we can assert on the number of rows found
   879  	_, err := executorExec(executor, "select 42", map[string]*querypb.BindVariable{})
   880  	require.NoError(t, err)
   881  
   882  	sql := "select found_rows()"
   883  	result, err := executorExec(executor, sql, map[string]*querypb.BindVariable{})
   884  	wantResult := &sqltypes.Result{
   885  		Fields: []*querypb.Field{
   886  			{Name: "found_rows()", Type: sqltypes.Int64},
   887  		},
   888  		Rows: [][]sqltypes.Value{{
   889  			sqltypes.NewInt64(1),
   890  		}},
   891  	}
   892  	require.NoError(t, err)
   893  	utils.MustMatch(t, wantResult, result, "Mismatch")
   894  }
   895  
   896  func TestRowCount(t *testing.T) {
   897  	executor, _, _, _ := createExecutorEnv()
   898  	executor.normalize = true
   899  	logChan := QueryLogger.Subscribe("Test")
   900  	defer QueryLogger.Unsubscribe(logChan)
   901  
   902  	_, err := executorExec(executor, "select 42", map[string]*querypb.BindVariable{})
   903  	require.NoError(t, err)
   904  	testRowCount(t, executor, -1)
   905  
   906  	_, err = executorExec(executor, "delete from user where id in (42, 24)", map[string]*querypb.BindVariable{})
   907  	require.NoError(t, err)
   908  	testRowCount(t, executor, 2)
   909  }
   910  
   911  func testRowCount(t *testing.T, executor *Executor, wantRowCount int64) {
   912  	t.Helper()
   913  	result, err := executorExec(executor, "select row_count()", map[string]*querypb.BindVariable{})
   914  	wantResult := &sqltypes.Result{
   915  		Fields: []*querypb.Field{
   916  			{Name: "row_count()", Type: sqltypes.Int64},
   917  		},
   918  		Rows: [][]sqltypes.Value{{
   919  			sqltypes.NewInt64(wantRowCount),
   920  		}},
   921  	}
   922  	require.NoError(t, err)
   923  	utils.MustMatch(t, wantResult, result, "Mismatch")
   924  }
   925  
   926  func TestSelectLastInsertIdInUnion(t *testing.T) {
   927  	executor, sbc1, _, _ := createExecutorEnv()
   928  	executor.normalize = true
   929  	primarySession.LastInsertId = 52
   930  
   931  	result1 := []*sqltypes.Result{{
   932  		Fields: []*querypb.Field{
   933  			{Name: "id", Type: sqltypes.Int32},
   934  		},
   935  		InsertID: 0,
   936  		Rows: [][]sqltypes.Value{{
   937  			sqltypes.NewInt32(52),
   938  		}},
   939  	}}
   940  	sbc1.SetResults(result1)
   941  
   942  	sql := "select last_insert_id() as id union select last_insert_id() as id"
   943  	got, err := executorExec(executor, sql, map[string]*querypb.BindVariable{})
   944  	require.NoError(t, err)
   945  	wantResult := &sqltypes.Result{
   946  		Fields: []*querypb.Field{
   947  			{Name: "id", Type: sqltypes.Int32},
   948  		},
   949  		Rows: [][]sqltypes.Value{{
   950  			sqltypes.NewInt32(52),
   951  		}},
   952  	}
   953  	utils.MustMatch(t, wantResult, got, "mismatch")
   954  }
   955  
   956  func TestSelectLastInsertIdInWhere(t *testing.T) {
   957  	executor, _, _, lookup := createExecutorEnv()
   958  	executor.normalize = true
   959  	logChan := QueryLogger.Subscribe("Test")
   960  	defer QueryLogger.Unsubscribe(logChan)
   961  
   962  	sql := "select id from music_user_map where id = last_insert_id()"
   963  	_, err := executorExec(executor, sql, map[string]*querypb.BindVariable{})
   964  	require.NoError(t, err)
   965  	wantQueries := []*querypb.BoundQuery{{
   966  		Sql:           "select id from music_user_map where id = :__lastInsertId",
   967  		BindVariables: map[string]*querypb.BindVariable{"__lastInsertId": sqltypes.Uint64BindVariable(0)},
   968  	}}
   969  
   970  	assert.Equal(t, wantQueries, lookup.Queries)
   971  }
   972  
   973  func TestLastInsertIDInVirtualTable(t *testing.T) {
   974  	executor, sbc1, _, _ := createExecutorEnv()
   975  	executor.normalize = true
   976  	result1 := []*sqltypes.Result{{
   977  		Fields: []*querypb.Field{
   978  			{Name: "id", Type: sqltypes.Int32},
   979  			{Name: "col", Type: sqltypes.Int32},
   980  		},
   981  		InsertID: 0,
   982  		Rows: [][]sqltypes.Value{{
   983  			sqltypes.NewInt32(1),
   984  			sqltypes.NewInt32(3),
   985  		}},
   986  	}}
   987  	sbc1.SetResults(result1)
   988  	_, err := executorExec(executor, "select * from (select last_insert_id()) as t", nil)
   989  	require.NoError(t, err)
   990  	wantQueries := []*querypb.BoundQuery{{
   991  		Sql:           "select * from (select :__lastInsertId as `last_insert_id()` from dual) as t",
   992  		BindVariables: map[string]*querypb.BindVariable{"__lastInsertId": sqltypes.Uint64BindVariable(0)},
   993  	}}
   994  
   995  	assert.Equal(t, wantQueries, sbc1.Queries)
   996  }
   997  
   998  func TestLastInsertIDInSubQueryExpression(t *testing.T) {
   999  	executor, sbc1, sbc2, _ := createExecutorEnv()
  1000  	executor.normalize = true
  1001  	primarySession.LastInsertId = 12345
  1002  	defer func() {
  1003  		// clean up global state
  1004  		primarySession.LastInsertId = 0
  1005  	}()
  1006  	rs, err := executorExec(executor, "select (select last_insert_id()) as x", nil)
  1007  	require.NoError(t, err)
  1008  	wantResult := &sqltypes.Result{
  1009  		Fields: []*querypb.Field{
  1010  			{Name: "x", Type: sqltypes.Uint64},
  1011  		},
  1012  		Rows: [][]sqltypes.Value{{
  1013  			sqltypes.NewUint64(12345),
  1014  		}},
  1015  	}
  1016  	utils.MustMatch(t, rs, wantResult, "Mismatch")
  1017  
  1018  	// the query will get rewritten into a simpler query that can be run entirely on the vtgate
  1019  	assert.Empty(t, sbc1.Queries)
  1020  	assert.Empty(t, sbc2.Queries)
  1021  }
  1022  
  1023  func TestSelectDatabase(t *testing.T) {
  1024  	executor, _, _, _ := createExecutorEnv()
  1025  	executor.normalize = true
  1026  	sql := "select database()"
  1027  	newSession := proto.Clone(primarySession).(*vtgatepb.Session)
  1028  	session := NewSafeSession(newSession)
  1029  	session.TargetString = "TestExecutor@primary"
  1030  	result, err := executor.Execute(
  1031  		context.Background(),
  1032  		"TestExecute",
  1033  		session,
  1034  		sql,
  1035  		map[string]*querypb.BindVariable{})
  1036  	wantResult := &sqltypes.Result{
  1037  		Fields: []*querypb.Field{
  1038  			{Name: "database()", Type: sqltypes.VarChar},
  1039  		},
  1040  		Rows: [][]sqltypes.Value{{
  1041  			sqltypes.NewVarChar("TestExecutor@primary"),
  1042  		}},
  1043  	}
  1044  	require.NoError(t, err)
  1045  	utils.MustMatch(t, wantResult, result, "Mismatch")
  1046  
  1047  }
  1048  
  1049  func TestSelectBindvars(t *testing.T) {
  1050  	executor, sbc1, sbc2, lookup := createExecutorEnv()
  1051  	logChan := QueryLogger.Subscribe("Test")
  1052  	defer QueryLogger.Unsubscribe(logChan)
  1053  
  1054  	lookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult(
  1055  		sqltypes.MakeTestFields("b|a", "varbinary|varbinary"),
  1056  		"foo1|1",
  1057  	), sqltypes.MakeTestResult(
  1058  		sqltypes.MakeTestFields("b|a", "varbinary|varbinary"),
  1059  		"foo2|1",
  1060  	)})
  1061  
  1062  	sql := "select id from user where id = :id"
  1063  	_, err := executorExec(executor, sql, map[string]*querypb.BindVariable{
  1064  		"id": sqltypes.Int64BindVariable(1),
  1065  	})
  1066  	require.NoError(t, err)
  1067  	wantQueries := []*querypb.BoundQuery{{
  1068  		Sql:           "select id from `user` where id = :id",
  1069  		BindVariables: map[string]*querypb.BindVariable{"id": sqltypes.Int64BindVariable(1)},
  1070  	}}
  1071  	utils.MustMatch(t, sbc1.Queries, wantQueries)
  1072  	assert.Empty(t, sbc2.Queries)
  1073  	sbc1.Queries = nil
  1074  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 1)
  1075  
  1076  	// Test with StringBindVariable
  1077  	sql = "select id from user where name in (:name1, :name2)"
  1078  	_, err = executorExec(executor, sql, map[string]*querypb.BindVariable{
  1079  		"name1": sqltypes.StringBindVariable("foo1"),
  1080  		"name2": sqltypes.StringBindVariable("foo2"),
  1081  	})
  1082  	require.NoError(t, err)
  1083  	wantQueries = []*querypb.BoundQuery{{
  1084  		Sql: "select id from `user` where `name` in ::__vals",
  1085  		BindVariables: map[string]*querypb.BindVariable{
  1086  			"name1":  sqltypes.StringBindVariable("foo1"),
  1087  			"name2":  sqltypes.StringBindVariable("foo2"),
  1088  			"__vals": sqltypes.TestBindVariable([]any{"foo1", "foo2"}),
  1089  		},
  1090  	}}
  1091  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1092  	sbc1.Queries = nil
  1093  	testQueryLog(t, logChan, "VindexLookup", "SELECT", "select name, user_id from name_user_map where name in ::name", 1)
  1094  	testQueryLog(t, logChan, "VindexLookup", "SELECT", "select name, user_id from name_user_map where name in ::name", 1)
  1095  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 1)
  1096  
  1097  	// Test with BytesBindVariable
  1098  	sql = "select id from user where name in (:name1, :name2)"
  1099  	_, err = executorExec(executor, sql, map[string]*querypb.BindVariable{
  1100  		"name1": sqltypes.BytesBindVariable([]byte("foo1")),
  1101  		"name2": sqltypes.BytesBindVariable([]byte("foo2")),
  1102  	})
  1103  	require.NoError(t, err)
  1104  	wantQueries = []*querypb.BoundQuery{{
  1105  		Sql: "select id from `user` where 1 != 1",
  1106  		BindVariables: map[string]*querypb.BindVariable{
  1107  			"name1": sqltypes.BytesBindVariable([]byte("foo1")),
  1108  			"name2": sqltypes.BytesBindVariable([]byte("foo2")),
  1109  		},
  1110  	}}
  1111  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1112  	testQueryLog(t, logChan, "VindexLookup", "SELECT", "select name, user_id from name_user_map where name in ::name", 1)
  1113  	testQueryLog(t, logChan, "VindexLookup", "SELECT", "select name, user_id from name_user_map where name in ::name", 1)
  1114  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 1)
  1115  
  1116  	// Test no match in the lookup vindex
  1117  	sbc1.Queries = nil
  1118  	lookup.Queries = nil
  1119  	lookup.SetResults([]*sqltypes.Result{{
  1120  		Fields: []*querypb.Field{
  1121  			{Name: "user_id", Type: sqltypes.Int32},
  1122  		},
  1123  		RowsAffected: 0,
  1124  		InsertID:     0,
  1125  		Rows:         [][]sqltypes.Value{},
  1126  	}})
  1127  
  1128  	sql = "select id from user where name = :name"
  1129  	_, err = executorExec(executor, sql, map[string]*querypb.BindVariable{
  1130  		"name": sqltypes.StringBindVariable("nonexistent"),
  1131  	})
  1132  	require.NoError(t, err)
  1133  
  1134  	// When there are no matching rows in the vindex, vtgate still needs the field info
  1135  	wantQueries = []*querypb.BoundQuery{{
  1136  		Sql: "select id from `user` where 1 != 1",
  1137  		BindVariables: map[string]*querypb.BindVariable{
  1138  			"name": sqltypes.StringBindVariable("nonexistent"),
  1139  		},
  1140  	}}
  1141  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1142  
  1143  	vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewVarChar("nonexistent")})
  1144  	require.NoError(t, err)
  1145  	wantLookupQueries := []*querypb.BoundQuery{{
  1146  		Sql: "select `name`, user_id from name_user_map where `name` in ::name",
  1147  		BindVariables: map[string]*querypb.BindVariable{
  1148  			"name": vars,
  1149  		},
  1150  	}}
  1151  
  1152  	utils.MustMatch(t, wantLookupQueries, lookup.Queries)
  1153  
  1154  	testQueryLog(t, logChan, "VindexLookup", "SELECT", "select name, user_id from name_user_map where name in ::name", 1)
  1155  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 1)
  1156  
  1157  }
  1158  
  1159  func TestSelectEqual(t *testing.T) {
  1160  	executor, sbc1, sbc2, sbclookup := createExecutorEnv()
  1161  
  1162  	_, err := executorExec(executor, "select id from user where id = 1", nil)
  1163  	require.NoError(t, err)
  1164  	wantQueries := []*querypb.BoundQuery{{
  1165  		Sql:           "select id from `user` where id = 1",
  1166  		BindVariables: map[string]*querypb.BindVariable{},
  1167  	}}
  1168  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1169  	if sbc2.Queries != nil {
  1170  		t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries)
  1171  	}
  1172  	sbc1.Queries = nil
  1173  
  1174  	_, err = executorExec(executor, "select id from user where id = 3", nil)
  1175  	require.NoError(t, err)
  1176  	wantQueries = []*querypb.BoundQuery{{
  1177  		Sql:           "select id from `user` where id = 3",
  1178  		BindVariables: map[string]*querypb.BindVariable{},
  1179  	}}
  1180  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  1181  	if execCount := sbc1.ExecCount.Get(); execCount != 1 {
  1182  		t.Errorf("sbc1.ExecCount: %v, want 1\n", execCount)
  1183  	}
  1184  	if sbc1.Queries != nil {
  1185  		t.Errorf("sbc1.Queries: %+v, want nil\n", sbc1.Queries)
  1186  	}
  1187  	sbc2.Queries = nil
  1188  
  1189  	_, err = executorExec(executor, "select id from user where id = '3'", nil)
  1190  	require.NoError(t, err)
  1191  	wantQueries = []*querypb.BoundQuery{{
  1192  		Sql:           "select id from `user` where id = '3'",
  1193  		BindVariables: map[string]*querypb.BindVariable{},
  1194  	}}
  1195  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  1196  	if execCount := sbc1.ExecCount.Get(); execCount != 1 {
  1197  		t.Errorf("sbc1.ExecCount: %v, want 1\n", execCount)
  1198  	}
  1199  	if sbc1.Queries != nil {
  1200  		t.Errorf("sbc1.Queries: %+v, want nil\n", sbc1.Queries)
  1201  	}
  1202  	sbc2.Queries = nil
  1203  
  1204  	sbclookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult(
  1205  		sqltypes.MakeTestFields("b|a", "varbinary|varbinary"),
  1206  		"foo|1",
  1207  	)})
  1208  	_, err = executorExec(executor, "select id from user where name = 'foo'", nil)
  1209  	require.NoError(t, err)
  1210  	wantQueries = []*querypb.BoundQuery{{
  1211  		Sql:           "select id from `user` where `name` = 'foo'",
  1212  		BindVariables: map[string]*querypb.BindVariable{},
  1213  	}}
  1214  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1215  	vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewVarChar("foo")})
  1216  	require.NoError(t, err)
  1217  	wantQueries = []*querypb.BoundQuery{{
  1218  		Sql: "select `name`, user_id from name_user_map where `name` in ::name",
  1219  		BindVariables: map[string]*querypb.BindVariable{
  1220  			"name": vars,
  1221  		},
  1222  	}}
  1223  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
  1224  }
  1225  
  1226  func TestSelectINFromOR(t *testing.T) {
  1227  	executor, sbc1, _, _ := createExecutorEnv()
  1228  	executor.pv = querypb.ExecuteOptions_Gen4
  1229  
  1230  	_, err := executorExec(executor, "select 1 from user where id = 1 and name = 'apa' or id = 2 and name = 'toto'", nil)
  1231  	require.NoError(t, err)
  1232  	wantQueries := []*querypb.BoundQuery{{
  1233  		Sql: "select 1 from `user` where id = 1 and `name` = 'apa' or id = 2 and `name` = 'toto'",
  1234  		BindVariables: map[string]*querypb.BindVariable{
  1235  			"__vals": sqltypes.TestBindVariable([]any{int64(1), int64(2)}),
  1236  		},
  1237  	}}
  1238  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1239  }
  1240  
  1241  func TestSelectDual(t *testing.T) {
  1242  	executor, sbc1, _, lookup := createExecutorEnv()
  1243  
  1244  	_, err := executorExec(executor, "select @@aa.bb from dual", nil)
  1245  	require.NoError(t, err)
  1246  	wantQueries := []*querypb.BoundQuery{{
  1247  		Sql:           "select @@`aa.bb` from dual",
  1248  		BindVariables: map[string]*querypb.BindVariable{},
  1249  	}}
  1250  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1251  
  1252  	_, err = executorExec(executor, "select @@aa.bb from TestUnsharded.dual", nil)
  1253  	require.NoError(t, err)
  1254  	utils.MustMatch(t, wantQueries, lookup.Queries)
  1255  }
  1256  
  1257  func TestSelectComments(t *testing.T) {
  1258  	executor, sbc1, sbc2, _ := createExecutorEnv()
  1259  
  1260  	_, err := executorExec(executor, "/* leading */ select id from user where id = 1 /* trailing */", nil)
  1261  	require.NoError(t, err)
  1262  	wantQueries := []*querypb.BoundQuery{{
  1263  		Sql:           "/* leading */ select id from `user` where id = 1 /* trailing */",
  1264  		BindVariables: map[string]*querypb.BindVariable{},
  1265  	}}
  1266  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1267  	if sbc2.Queries != nil {
  1268  		t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries)
  1269  	}
  1270  	sbc1.Queries = nil
  1271  }
  1272  
  1273  func TestSelectNormalize(t *testing.T) {
  1274  	executor, sbc1, sbc2, _ := createExecutorEnv()
  1275  	executor.normalize = true
  1276  
  1277  	_, err := executorExec(executor, "/* leading */ select id from user where id = 1 /* trailing */", nil)
  1278  	require.NoError(t, err)
  1279  	wantQueries := []*querypb.BoundQuery{{
  1280  		Sql: "/* leading */ select id from `user` where id = :id /* trailing */",
  1281  		BindVariables: map[string]*querypb.BindVariable{
  1282  			"id": sqltypes.TestBindVariable(int64(1)),
  1283  		},
  1284  	}}
  1285  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1286  	if sbc2.Queries != nil {
  1287  		t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries)
  1288  	}
  1289  	sbc1.Queries = nil
  1290  
  1291  	// Force the query to go to the "wrong" shard and ensure that normalization still happens
  1292  	primarySession.TargetString = "TestExecutor/40-60"
  1293  	_, err = executorExec(executor, "/* leading */ select id from user where id = 1 /* trailing */", nil)
  1294  	require.NoError(t, err)
  1295  	wantQueries = []*querypb.BoundQuery{{
  1296  		Sql: "/* leading */ select id from `user` where id = :id /* trailing */",
  1297  		BindVariables: map[string]*querypb.BindVariable{
  1298  			"id": sqltypes.TestBindVariable(int64(1)),
  1299  		},
  1300  	}}
  1301  	require.Empty(t, sbc1.Queries)
  1302  	utils.MustMatch(t, wantQueries, sbc2.Queries, "sbc2.Queries")
  1303  	sbc2.Queries = nil
  1304  	primarySession.TargetString = ""
  1305  }
  1306  
  1307  func TestSelectCaseSensitivity(t *testing.T) {
  1308  	executor, sbc1, sbc2, _ := createExecutorEnv()
  1309  
  1310  	_, err := executorExec(executor, "select Id from user where iD = 1", nil)
  1311  	require.NoError(t, err)
  1312  	wantQueries := []*querypb.BoundQuery{{
  1313  		Sql:           "select Id from `user` where iD = 1",
  1314  		BindVariables: map[string]*querypb.BindVariable{},
  1315  	}}
  1316  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1317  	if sbc2.Queries != nil {
  1318  		t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries)
  1319  	}
  1320  	sbc1.Queries = nil
  1321  }
  1322  
  1323  func TestStreamSelectEqual(t *testing.T) {
  1324  	executor, _, _, _ := createExecutorEnv()
  1325  
  1326  	sql := "select id from user where id = 1"
  1327  	result, err := executorStream(executor, sql)
  1328  	require.NoError(t, err)
  1329  	wantResult := sandboxconn.StreamRowResult
  1330  	if !result.Equal(wantResult) {
  1331  		t.Errorf("result: %+v, want %+v", result, wantResult)
  1332  	}
  1333  }
  1334  
  1335  func TestSelectKeyRange(t *testing.T) {
  1336  	executor, sbc1, sbc2, _ := createExecutorEnv()
  1337  
  1338  	_, err := executorExec(executor, "select krcol_unique, krcol from keyrange_table where krcol = 1", nil)
  1339  	require.NoError(t, err)
  1340  	wantQueries := []*querypb.BoundQuery{{
  1341  		Sql:           "select krcol_unique, krcol from keyrange_table where krcol = 1",
  1342  		BindVariables: map[string]*querypb.BindVariable{},
  1343  	}}
  1344  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1345  	if sbc2.Queries != nil {
  1346  		t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries)
  1347  	}
  1348  	sbc1.Queries = nil
  1349  }
  1350  
  1351  func TestSelectKeyRangeUnique(t *testing.T) {
  1352  	executor, sbc1, sbc2, _ := createExecutorEnv()
  1353  
  1354  	_, err := executorExec(executor, "select krcol_unique, krcol from keyrange_table where krcol_unique = 1", nil)
  1355  	require.NoError(t, err)
  1356  	wantQueries := []*querypb.BoundQuery{{
  1357  		Sql:           "select krcol_unique, krcol from keyrange_table where krcol_unique = 1",
  1358  		BindVariables: map[string]*querypb.BindVariable{},
  1359  	}}
  1360  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1361  	if sbc2.Queries != nil {
  1362  		t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries)
  1363  	}
  1364  	sbc1.Queries = nil
  1365  }
  1366  
  1367  func TestSelectIN(t *testing.T) {
  1368  	executor, sbc1, sbc2, sbclookup := createExecutorEnv()
  1369  
  1370  	// Constant in IN clause is just a number, not a bind variable.
  1371  	_, err := executorExec(executor, "select id from user where id in (1)", nil)
  1372  	require.NoError(t, err)
  1373  	wantQueries := []*querypb.BoundQuery{{
  1374  		Sql: "select id from `user` where id in ::__vals",
  1375  		BindVariables: map[string]*querypb.BindVariable{
  1376  			"__vals": sqltypes.TestBindVariable([]any{int64(1)}),
  1377  		},
  1378  	}}
  1379  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1380  	if sbc2.Queries != nil {
  1381  		t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries)
  1382  	}
  1383  
  1384  	// Constants in IN clause are just numbers, not bind variables.
  1385  	// They result in two different queries on two shards.
  1386  	sbc1.Queries = nil
  1387  	sbc2.Queries = nil
  1388  	_, err = executorExec(executor, "select id from user where id in (1, 3)", nil)
  1389  	require.NoError(t, err)
  1390  	wantQueries = []*querypb.BoundQuery{{
  1391  		Sql: "select id from `user` where id in ::__vals",
  1392  		BindVariables: map[string]*querypb.BindVariable{
  1393  			"__vals": sqltypes.TestBindVariable([]any{int64(1)}),
  1394  		},
  1395  	}}
  1396  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1397  	wantQueries = []*querypb.BoundQuery{{
  1398  		Sql: "select id from `user` where id in ::__vals",
  1399  		BindVariables: map[string]*querypb.BindVariable{
  1400  			"__vals": sqltypes.TestBindVariable([]any{int64(3)}),
  1401  		},
  1402  	}}
  1403  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  1404  
  1405  	// In is a bind variable list, that will end up on two shards.
  1406  	// This is using []any for the bind variable list.
  1407  	sbc1.Queries = nil
  1408  	sbc2.Queries = nil
  1409  	_, err = executorExec(executor, "select id from user where id in ::vals", map[string]*querypb.BindVariable{
  1410  		"vals": sqltypes.TestBindVariable([]any{int64(1), int64(3)}),
  1411  	})
  1412  	require.NoError(t, err)
  1413  	wantQueries = []*querypb.BoundQuery{{
  1414  		Sql: "select id from `user` where id in ::__vals",
  1415  		BindVariables: map[string]*querypb.BindVariable{
  1416  			"__vals": sqltypes.TestBindVariable([]any{int64(1)}),
  1417  			"vals":   sqltypes.TestBindVariable([]any{int64(1), int64(3)}),
  1418  		},
  1419  	}}
  1420  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1421  	wantQueries = []*querypb.BoundQuery{{
  1422  		Sql: "select id from `user` where id in ::__vals",
  1423  		BindVariables: map[string]*querypb.BindVariable{
  1424  			"__vals": sqltypes.TestBindVariable([]any{int64(3)}),
  1425  			"vals":   sqltypes.TestBindVariable([]any{int64(1), int64(3)}),
  1426  		},
  1427  	}}
  1428  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  1429  
  1430  	// Convert a non-list bind variable.
  1431  	sbc1.Queries = nil
  1432  	sbc2.Queries = nil
  1433  	sbclookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult(
  1434  		sqltypes.MakeTestFields("b|a", "varbinary|varbinary"),
  1435  		"foo|1",
  1436  	)})
  1437  	_, err = executorExec(executor, "select id from user where name = 'foo'", nil)
  1438  	require.NoError(t, err)
  1439  	wantQueries = []*querypb.BoundQuery{{
  1440  		Sql:           "select id from `user` where `name` = 'foo'",
  1441  		BindVariables: map[string]*querypb.BindVariable{},
  1442  	}}
  1443  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  1444  	vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewVarChar("foo")})
  1445  	require.NoError(t, err)
  1446  	wantQueries = []*querypb.BoundQuery{{
  1447  		Sql: "select `name`, user_id from name_user_map where `name` in ::name",
  1448  		BindVariables: map[string]*querypb.BindVariable{
  1449  			"name": vars,
  1450  		},
  1451  	}}
  1452  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
  1453  }
  1454  
  1455  func TestStreamSelectIN(t *testing.T) {
  1456  	executor, _, _, sbclookup := createExecutorEnv()
  1457  
  1458  	sql := "select id from user where id in (1)"
  1459  	result, err := executorStream(executor, sql)
  1460  	require.NoError(t, err)
  1461  	wantResult := sandboxconn.StreamRowResult
  1462  	if !result.Equal(wantResult) {
  1463  		t.Errorf("result: %+v, want %+v", result, wantResult)
  1464  	}
  1465  
  1466  	sql = "select id from user where id in (1, 3)"
  1467  	result, err = executorStream(executor, sql)
  1468  	require.NoError(t, err)
  1469  	wantResult = &sqltypes.Result{
  1470  		Fields: sandboxconn.StreamRowResult.Fields,
  1471  		Rows: [][]sqltypes.Value{
  1472  			sandboxconn.StreamRowResult.Rows[0],
  1473  			sandboxconn.StreamRowResult.Rows[0],
  1474  		},
  1475  		RowsAffected: 0,
  1476  	}
  1477  	if !result.Equal(wantResult) {
  1478  		t.Errorf("result: %+v, want %+v", result, wantResult)
  1479  	}
  1480  
  1481  	sql = "select id from user where name = 'foo'"
  1482  	result, err = executorStream(executor, sql)
  1483  	require.NoError(t, err)
  1484  	wantResult = sandboxconn.StreamRowResult
  1485  	if !result.Equal(wantResult) {
  1486  		t.Errorf("result: %+v, want %+v", result, wantResult)
  1487  	}
  1488  
  1489  	vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewVarChar("foo")})
  1490  	require.NoError(t, err)
  1491  	wantQueries := []*querypb.BoundQuery{{
  1492  		Sql: "select `name`, user_id from name_user_map where `name` in ::name",
  1493  		BindVariables: map[string]*querypb.BindVariable{
  1494  			"name": vars,
  1495  		},
  1496  	}}
  1497  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
  1498  }
  1499  
  1500  func createExecutor(serv *sandboxTopo, cell string, resolver *Resolver) *Executor {
  1501  	return NewExecutor(context.Background(), serv, cell, resolver, false, false, testBufferSize, cache.DefaultConfig, nil, false, querypb.ExecuteOptions_V3)
  1502  }
  1503  
  1504  func TestSelectScatter(t *testing.T) {
  1505  	// Special setup: Don't use createExecutorEnv.
  1506  	cell := "aa"
  1507  	hc := discovery.NewFakeHealthCheck(nil)
  1508  	s := createSandbox(KsTestSharded)
  1509  	s.VSchema = executorVSchema
  1510  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1511  	serv := newSandboxForCells([]string{cell})
  1512  	resolver := newTestResolver(hc, serv, cell)
  1513  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1514  	var conns []*sandboxconn.SandboxConn
  1515  	for _, shard := range shards {
  1516  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1517  		conns = append(conns, sbc)
  1518  	}
  1519  	executor := createExecutor(serv, cell, resolver)
  1520  	logChan := QueryLogger.Subscribe("Test")
  1521  	defer QueryLogger.Unsubscribe(logChan)
  1522  
  1523  	sql := "select id from user"
  1524  	_, err := executorExec(executor, sql, nil)
  1525  	require.NoError(t, err)
  1526  	wantQueries := []*querypb.BoundQuery{{
  1527  		Sql:           "select id from `user`",
  1528  		BindVariables: map[string]*querypb.BindVariable{},
  1529  	}}
  1530  	for _, conn := range conns {
  1531  		utils.MustMatch(t, wantQueries, conn.Queries)
  1532  	}
  1533  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 8)
  1534  }
  1535  
  1536  func TestSelectScatterPartial(t *testing.T) {
  1537  	// Special setup: Don't use createExecutorEnv.
  1538  	primarySession = &vtgatepb.Session{
  1539  		TargetString: "@primary",
  1540  	}
  1541  	cell := "aa"
  1542  	hc := discovery.NewFakeHealthCheck(nil)
  1543  	s := createSandbox(KsTestSharded)
  1544  	s.VSchema = executorVSchema
  1545  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1546  	serv := newSandboxForCells([]string{cell})
  1547  	resolver := newTestResolver(hc, serv, cell)
  1548  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1549  	var conns []*sandboxconn.SandboxConn
  1550  	for _, shard := range shards {
  1551  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1552  		conns = append(conns, sbc)
  1553  	}
  1554  
  1555  	executor := createExecutor(serv, cell, resolver)
  1556  	logChan := QueryLogger.Subscribe("Test")
  1557  	defer QueryLogger.Unsubscribe(logChan)
  1558  
  1559  	// Fail 1 of N without the directive fails the whole operation
  1560  	conns[2].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1561  	results, err := executorExec(executor, "select id from user", nil)
  1562  	wantErr := "TestExecutor.40-60.primary"
  1563  	if err == nil || !strings.Contains(err.Error(), wantErr) {
  1564  		t.Errorf("want error %v, got %v", wantErr, err)
  1565  	}
  1566  	if vterrors.Code(err) != vtrpcpb.Code_RESOURCE_EXHAUSTED {
  1567  		t.Errorf("want error code Code_RESOURCE_EXHAUSTED, but got %v", vterrors.Code(err))
  1568  	}
  1569  	if results != nil {
  1570  		t.Errorf("want nil results, got %v", results)
  1571  	}
  1572  	testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from user", 8)
  1573  
  1574  	// Fail 1 of N with the directive succeeds with 7 rows
  1575  	results, err = executorExec(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user", nil)
  1576  	require.NoError(t, err)
  1577  	if results == nil || len(results.Rows) != 7 {
  1578  		t.Errorf("want 7 results, got %v", results)
  1579  	}
  1580  	testQueryLog(t, logChan, "TestExecute", "SELECT", "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user", 8)
  1581  
  1582  	// When all shards fail, the execution should also fail
  1583  	conns[0].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1584  	conns[1].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1585  	conns[3].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1586  	conns[4].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1587  	conns[5].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1588  	conns[6].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1589  	conns[7].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1590  
  1591  	_, err = executorExec(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user", nil)
  1592  	require.Error(t, err)
  1593  	testQueryLog(t, logChan, "TestExecute", "SELECT", "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user", 8)
  1594  
  1595  	_, err = executorExec(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user order by id", nil)
  1596  	require.Error(t, err)
  1597  }
  1598  
  1599  func TestSelectScatterPartialOLAP(t *testing.T) {
  1600  	// Special setup: Don't use createExecutorEnv.
  1601  	cell := "aa"
  1602  	hc := discovery.NewFakeHealthCheck(nil)
  1603  	s := createSandbox(KsTestSharded)
  1604  	s.VSchema = executorVSchema
  1605  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1606  	serv := newSandboxForCells([]string{cell})
  1607  	resolver := newTestResolver(hc, serv, cell)
  1608  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1609  	var conns []*sandboxconn.SandboxConn
  1610  	for _, shard := range shards {
  1611  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1612  		conns = append(conns, sbc)
  1613  	}
  1614  
  1615  	executor := createExecutor(serv, cell, resolver)
  1616  	logChan := QueryLogger.Subscribe("Test")
  1617  	defer QueryLogger.Unsubscribe(logChan)
  1618  
  1619  	// Fail 1 of N without the directive fails the whole operation
  1620  	conns[2].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1621  	results, err := executorStream(executor, "select id from user")
  1622  	assert.EqualError(t, err, "target: TestExecutor.40-60.primary: RESOURCE_EXHAUSTED error")
  1623  	assert.Equal(t, vtrpcpb.Code_RESOURCE_EXHAUSTED, vterrors.Code(err))
  1624  	assert.Nil(t, results)
  1625  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", "select id from user", 8)
  1626  
  1627  	// Fail 1 of N with the directive succeeds with 7 rows
  1628  	results, err = executorStream(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user")
  1629  	require.NoError(t, err)
  1630  	assert.EqualValues(t, 7, len(results.Rows))
  1631  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user", 8)
  1632  
  1633  	// If all shards fail, the operation should also fail
  1634  	conns[0].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1635  	conns[1].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1636  	conns[3].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1637  	conns[4].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1638  	conns[5].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1639  	conns[6].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1640  	conns[7].MustFailCodes[vtrpcpb.Code_RESOURCE_EXHAUSTED] = 1000
  1641  
  1642  	_, err = executorStream(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user")
  1643  	require.Error(t, err)
  1644  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user", 8)
  1645  
  1646  	_, err = executorStream(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user order by id")
  1647  	require.Error(t, err)
  1648  }
  1649  
  1650  func TestSelectScatterPartialOLAP2(t *testing.T) {
  1651  	// Special setup: Don't use createExecutorEnv.
  1652  	cell := "aa"
  1653  	hc := discovery.NewFakeHealthCheck(nil)
  1654  	s := createSandbox(KsTestSharded)
  1655  	s.VSchema = executorVSchema
  1656  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1657  	serv := newSandboxForCells([]string{cell})
  1658  	resolver := newTestResolver(hc, serv, cell)
  1659  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1660  	var conns []*sandboxconn.SandboxConn
  1661  	for _, shard := range shards {
  1662  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1663  		conns = append(conns, sbc)
  1664  	}
  1665  
  1666  	executor := createExecutor(serv, cell, resolver)
  1667  	logChan := QueryLogger.Subscribe("Test")
  1668  	defer QueryLogger.Unsubscribe(logChan)
  1669  
  1670  	// Fail 1 of N without the directive fails the whole operation
  1671  	tablet0 := conns[2].Tablet()
  1672  	ths := hc.GetHealthyTabletStats(&querypb.Target{
  1673  		Keyspace:   tablet0.GetKeyspace(),
  1674  		Shard:      tablet0.GetShard(),
  1675  		TabletType: tablet0.GetType(),
  1676  	})
  1677  	sbc0Th := ths[0]
  1678  	sbc0Th.Serving = false
  1679  
  1680  	results, err := executorStream(executor, "select id from user")
  1681  	require.Error(t, err)
  1682  	assert.Contains(t, err.Error(), `no healthy tablet available for 'keyspace:"TestExecutor" shard:"40-60"`)
  1683  	assert.Equal(t, vtrpcpb.Code_UNAVAILABLE, vterrors.Code(err))
  1684  	assert.Nil(t, results)
  1685  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", "select id from user", 8)
  1686  
  1687  	// Fail 1 of N with the directive succeeds with 7 rows
  1688  	results, err = executorStream(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user")
  1689  	require.NoError(t, err)
  1690  	assert.EqualValues(t, 7, len(results.Rows))
  1691  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user", 8)
  1692  
  1693  	// order by
  1694  	results, err = executorStream(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user order by id")
  1695  	require.NoError(t, err)
  1696  	assert.EqualValues(t, 7, len(results.Rows))
  1697  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user order by id", 8)
  1698  
  1699  	// order by and limit
  1700  	results, err = executorStream(executor, "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user order by id limit 5")
  1701  	require.NoError(t, err)
  1702  	assert.EqualValues(t, 5, len(results.Rows))
  1703  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", "select /*vt+ SCATTER_ERRORS_AS_WARNINGS=1 */ id from user order by id limit 5", 8)
  1704  }
  1705  
  1706  func TestStreamSelectScatter(t *testing.T) {
  1707  	// Special setup: Don't use createExecutorEnv.
  1708  	cell := "aa"
  1709  	hc := discovery.NewFakeHealthCheck(nil)
  1710  	s := createSandbox(KsTestSharded)
  1711  	s.VSchema = executorVSchema
  1712  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1713  	serv := newSandboxForCells([]string{cell})
  1714  	resolver := newTestResolver(hc, serv, cell)
  1715  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1716  	for _, shard := range shards {
  1717  		_ = hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1718  	}
  1719  	executor := createExecutor(serv, cell, resolver)
  1720  
  1721  	sql := "select id from user"
  1722  	result, err := executorStream(executor, sql)
  1723  	require.NoError(t, err)
  1724  	wantResult := &sqltypes.Result{
  1725  		Fields: sandboxconn.SingleRowResult.Fields,
  1726  		Rows: [][]sqltypes.Value{
  1727  			sandboxconn.StreamRowResult.Rows[0],
  1728  			sandboxconn.StreamRowResult.Rows[0],
  1729  			sandboxconn.StreamRowResult.Rows[0],
  1730  			sandboxconn.StreamRowResult.Rows[0],
  1731  			sandboxconn.StreamRowResult.Rows[0],
  1732  			sandboxconn.StreamRowResult.Rows[0],
  1733  			sandboxconn.StreamRowResult.Rows[0],
  1734  			sandboxconn.StreamRowResult.Rows[0],
  1735  		},
  1736  	}
  1737  	utils.MustMatch(t, wantResult, result)
  1738  }
  1739  
  1740  // TestSelectScatterOrderBy will run an ORDER BY query that will scatter out to 8 shards and return the 8 rows (one per shard) sorted.
  1741  func TestSelectScatterOrderBy(t *testing.T) {
  1742  	// Special setup: Don't use createExecutorEnv.
  1743  	cell := "aa"
  1744  	hc := discovery.NewFakeHealthCheck(nil)
  1745  	s := createSandbox(KsTestSharded)
  1746  	s.VSchema = executorVSchema
  1747  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1748  	serv := newSandboxForCells([]string{cell})
  1749  	resolver := newTestResolver(hc, serv, cell)
  1750  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1751  	var conns []*sandboxconn.SandboxConn
  1752  	for i, shard := range shards {
  1753  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1754  		sbc.SetResults([]*sqltypes.Result{{
  1755  			Fields: []*querypb.Field{
  1756  				{Name: "col1", Type: sqltypes.Int32},
  1757  				{Name: "col2", Type: sqltypes.Int32},
  1758  				{Name: "weight_string(col2)", Type: sqltypes.VarBinary},
  1759  			},
  1760  			InsertID: 0,
  1761  			Rows: [][]sqltypes.Value{{
  1762  				sqltypes.NewInt32(1),
  1763  				// i%4 ensures that there are duplicates across shards.
  1764  				// This will allow us to test that cross-shard ordering
  1765  				// still works correctly.
  1766  				sqltypes.NewInt32(int32(i % 4)),
  1767  				sqltypes.NULL,
  1768  			}},
  1769  		}})
  1770  		conns = append(conns, sbc)
  1771  	}
  1772  	executor := createExecutor(serv, cell, resolver)
  1773  
  1774  	query := "select col1, col2 from user order by col2 desc"
  1775  	gotResult, err := executorExec(executor, query, nil)
  1776  	require.NoError(t, err)
  1777  
  1778  	wantQueries := []*querypb.BoundQuery{{
  1779  		Sql:           "select col1, col2, weight_string(col2) from `user` order by col2 desc",
  1780  		BindVariables: map[string]*querypb.BindVariable{},
  1781  	}}
  1782  	for _, conn := range conns {
  1783  		utils.MustMatch(t, wantQueries, conn.Queries)
  1784  	}
  1785  
  1786  	wantResult := &sqltypes.Result{
  1787  		Fields: []*querypb.Field{
  1788  			{Name: "col1", Type: sqltypes.Int32},
  1789  			{Name: "col2", Type: sqltypes.Int32},
  1790  		},
  1791  		InsertID: 0,
  1792  	}
  1793  	for i := 0; i < 4; i++ {
  1794  		// There should be a duplicate for each row returned.
  1795  		for j := 0; j < 2; j++ {
  1796  			row := []sqltypes.Value{
  1797  				sqltypes.NewInt32(1),
  1798  				sqltypes.NewInt32(int32(3 - i)),
  1799  			}
  1800  			wantResult.Rows = append(wantResult.Rows, row)
  1801  		}
  1802  	}
  1803  	utils.MustMatch(t, wantResult, gotResult)
  1804  }
  1805  
  1806  // TestSelectScatterOrderByVarChar will run an ORDER BY query that will scatter out to 8 shards and return the 8 rows (one per shard) sorted.
  1807  func TestSelectScatterOrderByVarChar(t *testing.T) {
  1808  	// Special setup: Don't use createExecutorEnv.
  1809  	cell := "aa"
  1810  	hc := discovery.NewFakeHealthCheck(nil)
  1811  	s := createSandbox(KsTestSharded)
  1812  	s.VSchema = executorVSchema
  1813  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1814  	serv := newSandboxForCells([]string{cell})
  1815  	resolver := newTestResolver(hc, serv, cell)
  1816  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1817  	var conns []*sandboxconn.SandboxConn
  1818  	for i, shard := range shards {
  1819  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1820  		sbc.SetResults([]*sqltypes.Result{{
  1821  			Fields: []*querypb.Field{
  1822  				{Name: "col1", Type: sqltypes.Int32},
  1823  				{Name: "textcol", Type: sqltypes.VarChar},
  1824  			},
  1825  			InsertID: 0,
  1826  			Rows: [][]sqltypes.Value{{
  1827  				sqltypes.NewInt32(1),
  1828  				// i%4 ensures that there are duplicates across shards.
  1829  				// This will allow us to test that cross-shard ordering
  1830  				// still works correctly.
  1831  				sqltypes.NewVarChar(fmt.Sprintf("%d", i%4)),
  1832  				sqltypes.NewVarBinary(fmt.Sprintf("%d", i%4)),
  1833  			}},
  1834  		}})
  1835  		conns = append(conns, sbc)
  1836  	}
  1837  	executor := createExecutor(serv, cell, resolver)
  1838  
  1839  	query := "select col1, textcol from user order by textcol desc"
  1840  	gotResult, err := executorExec(executor, query, nil)
  1841  	require.NoError(t, err)
  1842  
  1843  	wantQueries := []*querypb.BoundQuery{{
  1844  		Sql:           "select col1, textcol, weight_string(textcol) from `user` order by textcol desc",
  1845  		BindVariables: map[string]*querypb.BindVariable{},
  1846  	}}
  1847  	for _, conn := range conns {
  1848  		utils.MustMatch(t, wantQueries, conn.Queries)
  1849  	}
  1850  
  1851  	wantResult := &sqltypes.Result{
  1852  		Fields: []*querypb.Field{
  1853  			{Name: "col1", Type: sqltypes.Int32},
  1854  			{Name: "textcol", Type: sqltypes.VarChar},
  1855  		},
  1856  		InsertID: 0,
  1857  	}
  1858  	for i := 0; i < 4; i++ {
  1859  		// There should be a duplicate for each row returned.
  1860  		for j := 0; j < 2; j++ {
  1861  			row := []sqltypes.Value{
  1862  				sqltypes.NewInt32(1),
  1863  				sqltypes.NewVarChar(fmt.Sprintf("%d", 3-i)),
  1864  			}
  1865  			wantResult.Rows = append(wantResult.Rows, row)
  1866  		}
  1867  	}
  1868  	utils.MustMatch(t, wantResult, gotResult)
  1869  }
  1870  
  1871  func TestStreamSelectScatterOrderBy(t *testing.T) {
  1872  	// Special setup: Don't use createExecutorEnv.
  1873  	cell := "aa"
  1874  	hc := discovery.NewFakeHealthCheck(nil)
  1875  	s := createSandbox(KsTestSharded)
  1876  	s.VSchema = executorVSchema
  1877  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1878  	serv := newSandboxForCells([]string{cell})
  1879  	resolver := newTestResolver(hc, serv, cell)
  1880  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1881  	var conns []*sandboxconn.SandboxConn
  1882  	for i, shard := range shards {
  1883  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1884  		sbc.SetResults([]*sqltypes.Result{{
  1885  			Fields: []*querypb.Field{
  1886  				{Name: "id", Type: sqltypes.Int32},
  1887  				{Name: "col", Type: sqltypes.Int32},
  1888  				{Name: "weight_string(col)", Type: sqltypes.VarBinary},
  1889  			},
  1890  			InsertID: 0,
  1891  			Rows: [][]sqltypes.Value{{
  1892  				sqltypes.NewInt32(1),
  1893  				sqltypes.NewInt32(int32(i % 4)),
  1894  				sqltypes.NULL,
  1895  			}},
  1896  		}})
  1897  		conns = append(conns, sbc)
  1898  	}
  1899  	executor := createExecutor(serv, cell, resolver)
  1900  
  1901  	query := "select id, col from user order by col desc"
  1902  	gotResult, err := executorStream(executor, query)
  1903  	require.NoError(t, err)
  1904  
  1905  	wantQueries := []*querypb.BoundQuery{{
  1906  		Sql:           "select id, col, weight_string(col) from `user` order by col desc",
  1907  		BindVariables: map[string]*querypb.BindVariable{},
  1908  	}}
  1909  	for _, conn := range conns {
  1910  		utils.MustMatch(t, wantQueries, conn.Queries)
  1911  	}
  1912  
  1913  	wantResult := &sqltypes.Result{
  1914  		Fields: []*querypb.Field{
  1915  			{Name: "id", Type: sqltypes.Int32},
  1916  			{Name: "col", Type: sqltypes.Int32},
  1917  		},
  1918  	}
  1919  	for i := 0; i < 4; i++ {
  1920  		row := []sqltypes.Value{
  1921  			sqltypes.NewInt32(1),
  1922  			sqltypes.NewInt32(int32(3 - i)),
  1923  		}
  1924  		wantResult.Rows = append(wantResult.Rows, row, row)
  1925  	}
  1926  	utils.MustMatch(t, wantResult, gotResult)
  1927  }
  1928  
  1929  func TestStreamSelectScatterOrderByVarChar(t *testing.T) {
  1930  	// Special setup: Don't use createExecutorEnv.
  1931  	cell := "aa"
  1932  	hc := discovery.NewFakeHealthCheck(nil)
  1933  	s := createSandbox(KsTestSharded)
  1934  	s.VSchema = executorVSchema
  1935  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1936  	serv := newSandboxForCells([]string{cell})
  1937  	resolver := newTestResolver(hc, serv, cell)
  1938  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1939  	var conns []*sandboxconn.SandboxConn
  1940  	for i, shard := range shards {
  1941  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  1942  		sbc.SetResults([]*sqltypes.Result{{
  1943  			Fields: []*querypb.Field{
  1944  				{Name: "id", Type: sqltypes.Int32},
  1945  				{Name: "textcol", Type: sqltypes.VarChar},
  1946  			},
  1947  			InsertID: 0,
  1948  			Rows: [][]sqltypes.Value{{
  1949  				sqltypes.NewInt32(1),
  1950  				sqltypes.NewVarChar(fmt.Sprintf("%d", i%4)),
  1951  				sqltypes.NewVarBinary(fmt.Sprintf("%d", i%4)),
  1952  			}},
  1953  		}})
  1954  		conns = append(conns, sbc)
  1955  	}
  1956  	executor := createExecutor(serv, cell, resolver)
  1957  
  1958  	query := "select id, textcol from user order by textcol desc"
  1959  	gotResult, err := executorStream(executor, query)
  1960  	require.NoError(t, err)
  1961  
  1962  	wantQueries := []*querypb.BoundQuery{{
  1963  		Sql:           "select id, textcol, weight_string(textcol) from `user` order by textcol desc",
  1964  		BindVariables: map[string]*querypb.BindVariable{},
  1965  	}}
  1966  	for _, conn := range conns {
  1967  		utils.MustMatch(t, wantQueries, conn.Queries)
  1968  	}
  1969  
  1970  	wantResult := &sqltypes.Result{
  1971  		Fields: []*querypb.Field{
  1972  			{Name: "id", Type: sqltypes.Int32},
  1973  			{Name: "textcol", Type: sqltypes.VarChar},
  1974  		},
  1975  	}
  1976  	for i := 0; i < 4; i++ {
  1977  		row := []sqltypes.Value{
  1978  			sqltypes.NewInt32(1),
  1979  			sqltypes.NewVarChar(fmt.Sprintf("%d", 3-i)),
  1980  		}
  1981  		wantResult.Rows = append(wantResult.Rows, row, row)
  1982  	}
  1983  	utils.MustMatch(t, wantResult, gotResult)
  1984  }
  1985  
  1986  // TestSelectScatterAggregate will run an aggregate query that will scatter out to 8 shards and return 4 aggregated rows.
  1987  func TestSelectScatterAggregate(t *testing.T) {
  1988  	// Special setup: Don't use createExecutorEnv.
  1989  	cell := "aa"
  1990  	hc := discovery.NewFakeHealthCheck(nil)
  1991  	s := createSandbox(KsTestSharded)
  1992  	s.VSchema = executorVSchema
  1993  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  1994  	serv := newSandboxForCells([]string{cell})
  1995  	resolver := newTestResolver(hc, serv, cell)
  1996  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  1997  	var conns []*sandboxconn.SandboxConn
  1998  	for i, shard := range shards {
  1999  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  2000  		sbc.SetResults([]*sqltypes.Result{{
  2001  			Fields: []*querypb.Field{
  2002  				{Name: "col", Type: sqltypes.Int32},
  2003  				{Name: "sum(foo)", Type: sqltypes.Int32},
  2004  				{Name: "weight_string(col)", Type: sqltypes.VarBinary},
  2005  			},
  2006  			InsertID: 0,
  2007  			Rows: [][]sqltypes.Value{{
  2008  				sqltypes.NewInt32(int32(i % 4)),
  2009  				sqltypes.NewInt32(int32(i)),
  2010  				sqltypes.NULL,
  2011  			}},
  2012  		}})
  2013  		conns = append(conns, sbc)
  2014  	}
  2015  	executor := createExecutor(serv, cell, resolver)
  2016  
  2017  	query := "select col, sum(foo) from user group by col"
  2018  	gotResult, err := executorExec(executor, query, nil)
  2019  	require.NoError(t, err)
  2020  
  2021  	wantQueries := []*querypb.BoundQuery{{
  2022  		Sql:           "select col, sum(foo), weight_string(col) from `user` group by col, weight_string(col) order by col asc",
  2023  		BindVariables: map[string]*querypb.BindVariable{},
  2024  	}}
  2025  	for _, conn := range conns {
  2026  		utils.MustMatch(t, wantQueries, conn.Queries)
  2027  	}
  2028  
  2029  	wantResult := &sqltypes.Result{
  2030  		Fields: []*querypb.Field{
  2031  			{Name: "col", Type: sqltypes.Int32},
  2032  			{Name: "sum(foo)", Type: sqltypes.Int32},
  2033  		},
  2034  		InsertID: 0,
  2035  	}
  2036  	for i := 0; i < 4; i++ {
  2037  		row := []sqltypes.Value{
  2038  			sqltypes.NewInt32(int32(i)),
  2039  			sqltypes.NewInt32(int32(i*2 + 4)),
  2040  		}
  2041  		wantResult.Rows = append(wantResult.Rows, row)
  2042  	}
  2043  	utils.MustMatch(t, wantResult, gotResult)
  2044  }
  2045  
  2046  func TestStreamSelectScatterAggregate(t *testing.T) {
  2047  	// Special setup: Don't use createExecutorEnv.
  2048  	cell := "aa"
  2049  	hc := discovery.NewFakeHealthCheck(nil)
  2050  	s := createSandbox(KsTestSharded)
  2051  	s.VSchema = executorVSchema
  2052  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  2053  	serv := newSandboxForCells([]string{cell})
  2054  	resolver := newTestResolver(hc, serv, cell)
  2055  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  2056  	var conns []*sandboxconn.SandboxConn
  2057  	for i, shard := range shards {
  2058  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  2059  		sbc.SetResults([]*sqltypes.Result{{
  2060  			Fields: []*querypb.Field{
  2061  				{Name: "col", Type: sqltypes.Int32},
  2062  				{Name: "sum(foo)", Type: sqltypes.Int32},
  2063  				{Name: "weight_string(col)", Type: sqltypes.VarBinary},
  2064  			},
  2065  			InsertID: 0,
  2066  			Rows: [][]sqltypes.Value{{
  2067  				sqltypes.NewInt32(int32(i % 4)),
  2068  				sqltypes.NewInt32(int32(i)),
  2069  				sqltypes.NULL,
  2070  			}},
  2071  		}})
  2072  		conns = append(conns, sbc)
  2073  	}
  2074  	executor := createExecutor(serv, cell, resolver)
  2075  
  2076  	query := "select col, sum(foo) from user group by col"
  2077  	gotResult, err := executorStream(executor, query)
  2078  	require.NoError(t, err)
  2079  
  2080  	wantQueries := []*querypb.BoundQuery{{
  2081  		Sql:           "select col, sum(foo), weight_string(col) from `user` group by col, weight_string(col) order by col asc",
  2082  		BindVariables: map[string]*querypb.BindVariable{},
  2083  	}}
  2084  	for _, conn := range conns {
  2085  		utils.MustMatch(t, wantQueries, conn.Queries)
  2086  	}
  2087  
  2088  	wantResult := &sqltypes.Result{
  2089  		Fields: []*querypb.Field{
  2090  			{Name: "col", Type: sqltypes.Int32},
  2091  			{Name: "sum(foo)", Type: sqltypes.Int32},
  2092  		},
  2093  	}
  2094  	for i := 0; i < 4; i++ {
  2095  		row := []sqltypes.Value{
  2096  			sqltypes.NewInt32(int32(i)),
  2097  			sqltypes.NewInt32(int32(i*2 + 4)),
  2098  		}
  2099  		wantResult.Rows = append(wantResult.Rows, row)
  2100  	}
  2101  	utils.MustMatch(t, wantResult, gotResult)
  2102  }
  2103  
  2104  // TestSelectScatterLimit will run a limit query (ordered for consistency) against
  2105  // a scatter route and verify that the limit primitive works as intended.
  2106  func TestSelectScatterLimit(t *testing.T) {
  2107  	// Special setup: Don't use createExecutorEnv.
  2108  	cell := "aa"
  2109  	hc := discovery.NewFakeHealthCheck(nil)
  2110  	s := createSandbox(KsTestSharded)
  2111  	s.VSchema = executorVSchema
  2112  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  2113  	serv := newSandboxForCells([]string{cell})
  2114  	resolver := newTestResolver(hc, serv, cell)
  2115  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  2116  	var conns []*sandboxconn.SandboxConn
  2117  	for i, shard := range shards {
  2118  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  2119  		sbc.SetResults([]*sqltypes.Result{{
  2120  			Fields: []*querypb.Field{
  2121  				{Name: "col1", Type: sqltypes.Int32},
  2122  				{Name: "col2", Type: sqltypes.Int32},
  2123  				{Name: "weight_string(col2)", Type: sqltypes.VarBinary},
  2124  			},
  2125  			InsertID: 0,
  2126  			Rows: [][]sqltypes.Value{{
  2127  				sqltypes.NewInt32(1),
  2128  				sqltypes.NewInt32(int32(i % 4)),
  2129  				sqltypes.NULL,
  2130  			}},
  2131  		}})
  2132  		conns = append(conns, sbc)
  2133  	}
  2134  	executor := createExecutor(serv, cell, resolver)
  2135  
  2136  	query := "select col1, col2 from user order by col2 desc limit 3"
  2137  	gotResult, err := executorExec(executor, query, nil)
  2138  	require.NoError(t, err)
  2139  
  2140  	wantQueries := []*querypb.BoundQuery{{
  2141  		Sql:           "select col1, col2, weight_string(col2) from `user` order by col2 desc limit :__upper_limit",
  2142  		BindVariables: map[string]*querypb.BindVariable{"__upper_limit": sqltypes.Int64BindVariable(3)},
  2143  	}}
  2144  	for _, conn := range conns {
  2145  		utils.MustMatch(t, wantQueries, conn.Queries)
  2146  	}
  2147  
  2148  	wantResult := &sqltypes.Result{
  2149  		Fields: []*querypb.Field{
  2150  			{Name: "col1", Type: sqltypes.Int32},
  2151  			{Name: "col2", Type: sqltypes.Int32},
  2152  		},
  2153  		InsertID: 0,
  2154  	}
  2155  	wantResult.Rows = append(wantResult.Rows,
  2156  		[]sqltypes.Value{
  2157  			sqltypes.NewInt32(1),
  2158  			sqltypes.NewInt32(3),
  2159  		},
  2160  		[]sqltypes.Value{
  2161  			sqltypes.NewInt32(1),
  2162  			sqltypes.NewInt32(3),
  2163  		},
  2164  		[]sqltypes.Value{
  2165  			sqltypes.NewInt32(1),
  2166  			sqltypes.NewInt32(2),
  2167  		})
  2168  
  2169  	utils.MustMatch(t, wantResult, gotResult)
  2170  }
  2171  
  2172  // TestStreamSelectScatterLimit will run a streaming limit query (ordered for consistency) against
  2173  // a scatter route and verify that the limit primitive works as intended.
  2174  func TestStreamSelectScatterLimit(t *testing.T) {
  2175  	// Special setup: Don't use createExecutorEnv.
  2176  	cell := "aa"
  2177  	hc := discovery.NewFakeHealthCheck(nil)
  2178  	s := createSandbox(KsTestSharded)
  2179  	s.VSchema = executorVSchema
  2180  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  2181  	serv := newSandboxForCells([]string{cell})
  2182  	resolver := newTestResolver(hc, serv, cell)
  2183  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  2184  	var conns []*sandboxconn.SandboxConn
  2185  	for i, shard := range shards {
  2186  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  2187  		sbc.SetResults([]*sqltypes.Result{{
  2188  			Fields: []*querypb.Field{
  2189  				{Name: "col1", Type: sqltypes.Int32},
  2190  				{Name: "col2", Type: sqltypes.Int32},
  2191  				{Name: "weight_string(col2)", Type: sqltypes.VarBinary},
  2192  			},
  2193  			InsertID: 0,
  2194  			Rows: [][]sqltypes.Value{{
  2195  				sqltypes.NewInt32(1),
  2196  				sqltypes.NewInt32(int32(i % 4)),
  2197  				sqltypes.NULL,
  2198  			}},
  2199  		}})
  2200  		conns = append(conns, sbc)
  2201  	}
  2202  	executor := createExecutor(serv, cell, resolver)
  2203  
  2204  	query := "select col1, col2 from user order by col2 desc limit 3"
  2205  	gotResult, err := executorStream(executor, query)
  2206  	require.NoError(t, err)
  2207  
  2208  	wantQueries := []*querypb.BoundQuery{{
  2209  		Sql:           "select col1, col2, weight_string(col2) from `user` order by col2 desc limit :__upper_limit",
  2210  		BindVariables: map[string]*querypb.BindVariable{"__upper_limit": sqltypes.Int64BindVariable(3)},
  2211  	}}
  2212  	for _, conn := range conns {
  2213  		utils.MustMatch(t, wantQueries, conn.Queries)
  2214  	}
  2215  
  2216  	wantResult := &sqltypes.Result{
  2217  		Fields: []*querypb.Field{
  2218  			{Name: "col1", Type: sqltypes.Int32},
  2219  			{Name: "col2", Type: sqltypes.Int32},
  2220  		},
  2221  	}
  2222  	wantResult.Rows = append(wantResult.Rows,
  2223  		[]sqltypes.Value{
  2224  			sqltypes.NewInt32(1),
  2225  			sqltypes.NewInt32(3),
  2226  		},
  2227  		[]sqltypes.Value{
  2228  			sqltypes.NewInt32(1),
  2229  			sqltypes.NewInt32(3),
  2230  		},
  2231  		[]sqltypes.Value{
  2232  			sqltypes.NewInt32(1),
  2233  			sqltypes.NewInt32(2),
  2234  		})
  2235  
  2236  	utils.MustMatch(t, wantResult, gotResult)
  2237  }
  2238  
  2239  // TODO(sougou): stream and non-stream testing are very similar.
  2240  // Could reuse code,
  2241  func TestSimpleJoin(t *testing.T) {
  2242  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2243  	logChan := QueryLogger.Subscribe("Test")
  2244  	defer QueryLogger.Unsubscribe(logChan)
  2245  
  2246  	sql := "select u1.id, u2.id from user u1 join user u2 where u1.id = 1 and u2.id = 3"
  2247  	result, err := executorExec(executor, sql, nil)
  2248  	require.NoError(t, err)
  2249  	wantQueries := []*querypb.BoundQuery{{
  2250  		Sql:           "select u1.id from `user` as u1 where u1.id = 1",
  2251  		BindVariables: map[string]*querypb.BindVariable{},
  2252  	}}
  2253  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2254  	wantQueries = []*querypb.BoundQuery{{
  2255  		Sql:           "select u2.id from `user` as u2 where u2.id = 3",
  2256  		BindVariables: map[string]*querypb.BindVariable{},
  2257  	}}
  2258  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  2259  	wantResult := &sqltypes.Result{
  2260  		Fields: []*querypb.Field{
  2261  			sandboxconn.SingleRowResult.Fields[0],
  2262  			sandboxconn.SingleRowResult.Fields[0],
  2263  		},
  2264  		Rows: [][]sqltypes.Value{
  2265  			{
  2266  				sandboxconn.SingleRowResult.Rows[0][0],
  2267  				sandboxconn.SingleRowResult.Rows[0][0],
  2268  			},
  2269  		},
  2270  	}
  2271  	if !result.Equal(wantResult) {
  2272  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2273  	}
  2274  
  2275  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 2)
  2276  }
  2277  
  2278  func TestJoinComments(t *testing.T) {
  2279  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2280  	logChan := QueryLogger.Subscribe("Test")
  2281  	defer QueryLogger.Unsubscribe(logChan)
  2282  
  2283  	sql := "select u1.id, u2.id from user u1 join user u2 where u1.id = 1 and u2.id = 3 /* trailing */"
  2284  	_, err := executorExec(executor, sql, nil)
  2285  	require.NoError(t, err)
  2286  	wantQueries := []*querypb.BoundQuery{{
  2287  		Sql:           "select u1.id from `user` as u1 where u1.id = 1 /* trailing */",
  2288  		BindVariables: map[string]*querypb.BindVariable{},
  2289  	}}
  2290  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2291  	wantQueries = []*querypb.BoundQuery{{
  2292  		Sql:           "select u2.id from `user` as u2 where u2.id = 3 /* trailing */",
  2293  		BindVariables: map[string]*querypb.BindVariable{},
  2294  	}}
  2295  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  2296  
  2297  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 2)
  2298  }
  2299  
  2300  func TestSimpleJoinStream(t *testing.T) {
  2301  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2302  	logChan := QueryLogger.Subscribe("Test")
  2303  	defer QueryLogger.Unsubscribe(logChan)
  2304  
  2305  	sql := "select u1.id, u2.id from user u1 join user u2 where u1.id = 1 and u2.id = 3"
  2306  	result, err := executorStream(executor, sql)
  2307  	require.NoError(t, err)
  2308  	wantQueries := []*querypb.BoundQuery{{
  2309  		Sql:           "select u1.id from `user` as u1 where u1.id = 1",
  2310  		BindVariables: map[string]*querypb.BindVariable{},
  2311  	}}
  2312  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2313  	wantQueries = []*querypb.BoundQuery{{
  2314  		Sql:           "select u2.id from `user` as u2 where u2.id = 3",
  2315  		BindVariables: map[string]*querypb.BindVariable{},
  2316  	}}
  2317  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  2318  	wantResult := &sqltypes.Result{
  2319  		Fields: []*querypb.Field{
  2320  			sandboxconn.SingleRowResult.Fields[0],
  2321  			sandboxconn.SingleRowResult.Fields[0],
  2322  		},
  2323  		Rows: [][]sqltypes.Value{
  2324  			{
  2325  				sandboxconn.SingleRowResult.Rows[0][0],
  2326  				sandboxconn.SingleRowResult.Rows[0][0],
  2327  			},
  2328  		},
  2329  		RowsAffected: 0,
  2330  	}
  2331  	if !result.Equal(wantResult) {
  2332  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2333  	}
  2334  
  2335  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", sql, 2)
  2336  }
  2337  
  2338  func TestVarJoin(t *testing.T) {
  2339  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2340  	logChan := QueryLogger.Subscribe("Test")
  2341  	defer QueryLogger.Unsubscribe(logChan)
  2342  
  2343  	result1 := []*sqltypes.Result{{
  2344  		Fields: []*querypb.Field{
  2345  			{Name: "id", Type: sqltypes.Int32},
  2346  			{Name: "col", Type: sqltypes.Int32},
  2347  		},
  2348  		InsertID: 0,
  2349  		Rows: [][]sqltypes.Value{{
  2350  			sqltypes.NewInt32(1),
  2351  			sqltypes.NewInt32(3),
  2352  		}},
  2353  	}}
  2354  	sbc1.SetResults(result1)
  2355  	sql := "select u1.id, u2.id from user u1 join user u2 on u2.id = u1.col where u1.id = 1"
  2356  	_, err := executorExec(executor, sql, nil)
  2357  	require.NoError(t, err)
  2358  	wantQueries := []*querypb.BoundQuery{{
  2359  		Sql:           "select u1.id, u1.col from `user` as u1 where u1.id = 1",
  2360  		BindVariables: map[string]*querypb.BindVariable{},
  2361  	}}
  2362  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2363  	// We have to use string representation because bindvars type is too complex.
  2364  	got := fmt.Sprintf("%+v", sbc2.Queries)
  2365  	want := `[sql:"select u2.id from ` + "`user`" + ` as u2 where u2.id = :u1_col" bind_variables:{key:"u1_col" value:{type:INT32 value:"3"}}]`
  2366  	if got != want {
  2367  		t.Errorf("sbc2.Queries: %s, want %s\n", got, want)
  2368  	}
  2369  
  2370  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 2)
  2371  }
  2372  
  2373  func TestVarJoinStream(t *testing.T) {
  2374  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2375  	logChan := QueryLogger.Subscribe("Test")
  2376  	defer QueryLogger.Unsubscribe(logChan)
  2377  
  2378  	result1 := []*sqltypes.Result{{
  2379  		Fields: []*querypb.Field{
  2380  			{Name: "id", Type: sqltypes.Int32},
  2381  			{Name: "col", Type: sqltypes.Int32},
  2382  		},
  2383  		InsertID: 0,
  2384  		Rows: [][]sqltypes.Value{{
  2385  			sqltypes.NewInt32(1),
  2386  			sqltypes.NewInt32(3),
  2387  		}},
  2388  	}}
  2389  	sbc1.SetResults(result1)
  2390  	sql := "select u1.id, u2.id from user u1 join user u2 on u2.id = u1.col where u1.id = 1"
  2391  	_, err := executorStream(executor, sql)
  2392  	require.NoError(t, err)
  2393  	wantQueries := []*querypb.BoundQuery{{
  2394  		Sql:           "select u1.id, u1.col from `user` as u1 where u1.id = 1",
  2395  		BindVariables: map[string]*querypb.BindVariable{},
  2396  	}}
  2397  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2398  	// We have to use string representation because bindvars type is too complex.
  2399  	got := fmt.Sprintf("%+v", sbc2.Queries)
  2400  	want := `[sql:"select u2.id from ` + "`user`" + ` as u2 where u2.id = :u1_col" bind_variables:{key:"u1_col" value:{type:INT32 value:"3"}}]`
  2401  	if got != want {
  2402  		t.Errorf("sbc2.Queries: %s, want %s\n", got, want)
  2403  	}
  2404  
  2405  	testQueryLog(t, logChan, "TestExecuteStream", "SELECT", sql, 2)
  2406  }
  2407  
  2408  func TestLeftJoin(t *testing.T) {
  2409  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2410  	logChan := QueryLogger.Subscribe("Test")
  2411  	defer QueryLogger.Unsubscribe(logChan)
  2412  	result1 := []*sqltypes.Result{{
  2413  		Fields: []*querypb.Field{
  2414  			{Name: "col", Type: sqltypes.Int32},
  2415  			{Name: "id", Type: sqltypes.Int32},
  2416  		},
  2417  		InsertID: 0,
  2418  		Rows: [][]sqltypes.Value{{
  2419  			sqltypes.NewInt32(3),
  2420  			sqltypes.NewInt32(1),
  2421  		}},
  2422  	}}
  2423  	emptyResult := []*sqltypes.Result{{
  2424  		Fields: []*querypb.Field{
  2425  			{Name: "id", Type: sqltypes.Int32},
  2426  		},
  2427  	}}
  2428  	sbc1.SetResults(result1)
  2429  	sbc2.SetResults(emptyResult)
  2430  	sql := "select u1.id, u2.id from user u1 left join user u2 on u2.id = u1.col where u1.id = 1"
  2431  	result, err := executorExec(executor, sql, nil)
  2432  	require.NoError(t, err)
  2433  	wantResult := &sqltypes.Result{
  2434  		Fields: []*querypb.Field{
  2435  			sandboxconn.SingleRowResult.Fields[0],
  2436  			sandboxconn.SingleRowResult.Fields[0],
  2437  		},
  2438  		Rows: [][]sqltypes.Value{
  2439  			{
  2440  				sandboxconn.SingleRowResult.Rows[0][0],
  2441  				{},
  2442  			},
  2443  		},
  2444  	}
  2445  	if !result.Equal(wantResult) {
  2446  		t.Errorf("result: \n%+v, want \n%+v", result, wantResult)
  2447  	}
  2448  	testQueryLog(t, logChan, "TestExecute", "SELECT", sql, 2)
  2449  }
  2450  
  2451  func TestLeftJoinStream(t *testing.T) {
  2452  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2453  	result1 := []*sqltypes.Result{{
  2454  		Fields: []*querypb.Field{
  2455  			{Name: "col", Type: sqltypes.Int32},
  2456  			{Name: "id", Type: sqltypes.Int32},
  2457  		},
  2458  		InsertID: 0,
  2459  		Rows: [][]sqltypes.Value{{
  2460  			sqltypes.NewInt32(3),
  2461  			sqltypes.NewInt32(1),
  2462  		}},
  2463  	}}
  2464  	emptyResult := []*sqltypes.Result{{
  2465  		Fields: []*querypb.Field{
  2466  			{Name: "id", Type: sqltypes.Int32},
  2467  		},
  2468  	}}
  2469  	sbc1.SetResults(result1)
  2470  	sbc2.SetResults(emptyResult)
  2471  	result, err := executorStream(executor, "select u1.id, u2.id from user u1 left join user u2 on u2.id = u1.col where u1.id = 1")
  2472  	require.NoError(t, err)
  2473  	wantResult := &sqltypes.Result{
  2474  		Fields: []*querypb.Field{
  2475  			sandboxconn.SingleRowResult.Fields[0],
  2476  			sandboxconn.SingleRowResult.Fields[0],
  2477  		},
  2478  		Rows: [][]sqltypes.Value{
  2479  			{
  2480  				sandboxconn.SingleRowResult.Rows[0][0],
  2481  				{},
  2482  			},
  2483  		},
  2484  		RowsAffected: 0,
  2485  	}
  2486  	if !result.Equal(wantResult) {
  2487  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2488  	}
  2489  }
  2490  
  2491  func TestEmptyJoin(t *testing.T) {
  2492  	executor, sbc1, _, _ := createExecutorEnv()
  2493  	// Empty result requires a field query for the second part of join,
  2494  	// which is sent to shard 0.
  2495  	sbc1.SetResults([]*sqltypes.Result{{
  2496  		Fields: []*querypb.Field{
  2497  			{Name: "id", Type: sqltypes.Int32},
  2498  		},
  2499  	}, {
  2500  		Fields: []*querypb.Field{
  2501  			{Name: "id", Type: sqltypes.Int32},
  2502  		},
  2503  	}})
  2504  	result, err := executorExec(executor, "select u1.id, u2.id from user u1 join user u2 on u2.id = u1.col where u1.id = 1", nil)
  2505  	require.NoError(t, err)
  2506  	wantQueries := []*querypb.BoundQuery{{
  2507  		Sql:           "select u1.id, u1.col from `user` as u1 where u1.id = 1",
  2508  		BindVariables: map[string]*querypb.BindVariable{},
  2509  	}, {
  2510  		Sql: "select u2.id from `user` as u2 where 1 != 1",
  2511  		BindVariables: map[string]*querypb.BindVariable{
  2512  			"u1_col": sqltypes.NullBindVariable,
  2513  		},
  2514  	}}
  2515  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2516  	wantResult := &sqltypes.Result{
  2517  		Fields: []*querypb.Field{
  2518  			{Name: "id", Type: sqltypes.Int32},
  2519  			{Name: "id", Type: sqltypes.Int32},
  2520  		},
  2521  	}
  2522  	if !result.Equal(wantResult) {
  2523  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2524  	}
  2525  }
  2526  
  2527  func TestEmptyJoinStream(t *testing.T) {
  2528  	executor, sbc1, _, _ := createExecutorEnv()
  2529  	// Empty result requires a field query for the second part of join,
  2530  	// which is sent to shard 0.
  2531  	sbc1.SetResults([]*sqltypes.Result{{
  2532  		Fields: []*querypb.Field{
  2533  			{Name: "id", Type: sqltypes.Int32},
  2534  		},
  2535  	}, {
  2536  		Fields: []*querypb.Field{
  2537  			{Name: "id", Type: sqltypes.Int32},
  2538  		},
  2539  	}})
  2540  	result, err := executorStream(executor, "select u1.id, u2.id from user u1 join user u2 on u2.id = u1.col where u1.id = 1")
  2541  	require.NoError(t, err)
  2542  	wantQueries := []*querypb.BoundQuery{{
  2543  		Sql:           "select u1.id, u1.col from `user` as u1 where u1.id = 1",
  2544  		BindVariables: map[string]*querypb.BindVariable{},
  2545  	}, {
  2546  		Sql: "select u2.id from `user` as u2 where 1 != 1",
  2547  		BindVariables: map[string]*querypb.BindVariable{
  2548  			"u1_col": sqltypes.NullBindVariable,
  2549  		},
  2550  	}}
  2551  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2552  	wantResult := &sqltypes.Result{
  2553  		Fields: []*querypb.Field{
  2554  			{Name: "id", Type: sqltypes.Int32},
  2555  			{Name: "id", Type: sqltypes.Int32},
  2556  		},
  2557  	}
  2558  	if !result.Equal(wantResult) {
  2559  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2560  	}
  2561  }
  2562  
  2563  func TestEmptyJoinRecursive(t *testing.T) {
  2564  	executor, sbc1, _, _ := createExecutorEnv()
  2565  	// Make sure it also works recursively.
  2566  	sbc1.SetResults([]*sqltypes.Result{{
  2567  		Fields: []*querypb.Field{
  2568  			{Name: "id", Type: sqltypes.Int32},
  2569  		},
  2570  	}, {
  2571  		Fields: []*querypb.Field{
  2572  			{Name: "id", Type: sqltypes.Int32},
  2573  			{Name: "col", Type: sqltypes.Int32},
  2574  		},
  2575  	}, {
  2576  		Fields: []*querypb.Field{
  2577  			{Name: "id", Type: sqltypes.Int32},
  2578  		},
  2579  	}})
  2580  	result, err := executorExec(executor, "select u1.id, u2.id, u3.id from user u1 join (user u2 join user u3 on u3.id = u2.col) where u1.id = 1", nil)
  2581  	require.NoError(t, err)
  2582  	wantQueries := []*querypb.BoundQuery{{
  2583  		Sql:           "select u1.id from `user` as u1 where u1.id = 1",
  2584  		BindVariables: map[string]*querypb.BindVariable{},
  2585  	}, {
  2586  		Sql:           "select u2.id, u2.col from `user` as u2 where 1 != 1",
  2587  		BindVariables: map[string]*querypb.BindVariable{},
  2588  	}, {
  2589  		Sql: "select u3.id from `user` as u3 where 1 != 1",
  2590  		BindVariables: map[string]*querypb.BindVariable{
  2591  			"u2_col": sqltypes.NullBindVariable,
  2592  		},
  2593  	}}
  2594  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2595  	wantResult := &sqltypes.Result{
  2596  		Fields: []*querypb.Field{
  2597  			{Name: "id", Type: sqltypes.Int32},
  2598  			{Name: "id", Type: sqltypes.Int32},
  2599  			{Name: "id", Type: sqltypes.Int32},
  2600  		},
  2601  	}
  2602  	if !result.Equal(wantResult) {
  2603  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2604  	}
  2605  }
  2606  
  2607  func TestEmptyJoinRecursiveStream(t *testing.T) {
  2608  	executor, sbc1, _, _ := createExecutorEnv()
  2609  	// Make sure it also works recursively.
  2610  	sbc1.SetResults([]*sqltypes.Result{{
  2611  		Fields: []*querypb.Field{
  2612  			{Name: "id", Type: sqltypes.Int32},
  2613  		},
  2614  	}, {
  2615  		Fields: []*querypb.Field{
  2616  			{Name: "id", Type: sqltypes.Int32},
  2617  			{Name: "col", Type: sqltypes.Int32},
  2618  		},
  2619  	}, {
  2620  		Fields: []*querypb.Field{
  2621  			{Name: "id", Type: sqltypes.Int32},
  2622  		},
  2623  	}})
  2624  	result, err := executorStream(executor, "select u1.id, u2.id, u3.id from user u1 join (user u2 join user u3 on u3.id = u2.col) where u1.id = 1")
  2625  	require.NoError(t, err)
  2626  	wantQueries := []*querypb.BoundQuery{{
  2627  		Sql:           "select u1.id from `user` as u1 where u1.id = 1",
  2628  		BindVariables: map[string]*querypb.BindVariable{},
  2629  	}, {
  2630  		Sql:           "select u2.id, u2.col from `user` as u2 where 1 != 1",
  2631  		BindVariables: map[string]*querypb.BindVariable{},
  2632  	}, {
  2633  		Sql: "select u3.id from `user` as u3 where 1 != 1",
  2634  		BindVariables: map[string]*querypb.BindVariable{
  2635  			"u2_col": sqltypes.NullBindVariable,
  2636  		},
  2637  	}}
  2638  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2639  	wantResult := &sqltypes.Result{
  2640  		Fields: []*querypb.Field{
  2641  			{Name: "id", Type: sqltypes.Int32},
  2642  			{Name: "id", Type: sqltypes.Int32},
  2643  			{Name: "id", Type: sqltypes.Int32},
  2644  		},
  2645  	}
  2646  	if !result.Equal(wantResult) {
  2647  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2648  	}
  2649  }
  2650  
  2651  func TestCrossShardSubquery(t *testing.T) {
  2652  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2653  	result1 := []*sqltypes.Result{{
  2654  		Fields: []*querypb.Field{
  2655  			{Name: "id", Type: sqltypes.Int32},
  2656  			{Name: "col", Type: sqltypes.Int32},
  2657  		},
  2658  		InsertID: 0,
  2659  		Rows: [][]sqltypes.Value{{
  2660  			sqltypes.NewInt32(1),
  2661  			sqltypes.NewInt32(3),
  2662  		}},
  2663  	}}
  2664  	sbc1.SetResults(result1)
  2665  	result, err := executorExec(executor, "select id1 from (select u1.id id1, u2.id from user u1 join user u2 on u2.id = u1.col where u1.id = 1) as t", nil)
  2666  	require.NoError(t, err)
  2667  	wantQueries := []*querypb.BoundQuery{{
  2668  		Sql:           "select u1.id as id1, u1.col from `user` as u1 where u1.id = 1",
  2669  		BindVariables: map[string]*querypb.BindVariable{},
  2670  	}}
  2671  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2672  	// We have to use string representation because bindvars type is too complex.
  2673  	got := fmt.Sprintf("%+v", sbc2.Queries)
  2674  	want := `[sql:"select u2.id from ` + "`user`" + ` as u2 where u2.id = :u1_col" bind_variables:{key:"u1_col" value:{type:INT32 value:"3"}}]`
  2675  	if got != want {
  2676  		t.Errorf("sbc2.Queries: %s, want %s\n", got, want)
  2677  	}
  2678  
  2679  	wantResult := &sqltypes.Result{
  2680  		Fields: []*querypb.Field{
  2681  			{Name: "id", Type: sqltypes.Int32},
  2682  		},
  2683  		Rows: [][]sqltypes.Value{{
  2684  			sqltypes.NewInt32(1),
  2685  		}},
  2686  	}
  2687  	if !result.Equal(wantResult) {
  2688  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2689  	}
  2690  }
  2691  
  2692  func TestSubQueryAndQueryWithLimit(t *testing.T) {
  2693  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2694  	result1 := []*sqltypes.Result{{
  2695  		Fields: []*querypb.Field{
  2696  			{Name: "id", Type: sqltypes.Int32},
  2697  			{Name: "col", Type: sqltypes.Int32},
  2698  		},
  2699  		InsertID: 0,
  2700  		Rows: [][]sqltypes.Value{{
  2701  			sqltypes.NewInt32(1),
  2702  			sqltypes.NewInt32(3),
  2703  		}},
  2704  	}}
  2705  	result2 := []*sqltypes.Result{{
  2706  		Fields: []*querypb.Field{
  2707  			{Name: "id", Type: sqltypes.Int32},
  2708  			{Name: "col", Type: sqltypes.Int32},
  2709  		},
  2710  		InsertID: 0,
  2711  		Rows: [][]sqltypes.Value{{
  2712  			sqltypes.NewInt32(111),
  2713  			sqltypes.NewInt32(333),
  2714  		}},
  2715  	}}
  2716  	sbc1.SetResults(result1)
  2717  	sbc2.SetResults(result2)
  2718  
  2719  	exec(executor, NewSafeSession(&vtgatepb.Session{
  2720  		TargetString: "@primary",
  2721  	}), "select id1, id2 from t1 where id1 >= ( select id1 from t1 order by id1 asc limit 1) limit 100")
  2722  	require.Equal(t, 2, len(sbc1.Queries))
  2723  	require.Equal(t, 2, len(sbc2.Queries))
  2724  
  2725  	// sub query is evaluated first, and sees a limit of 1
  2726  	assert.Equal(t, `type:INT64 value:"1"`, sbc1.Queries[0].BindVariables["__upper_limit"].String())
  2727  	assert.Equal(t, `type:INT64 value:"1"`, sbc2.Queries[0].BindVariables["__upper_limit"].String())
  2728  
  2729  	// outer limit is only applied to the outer query
  2730  	assert.Equal(t, `type:INT64 value:"100"`, sbc1.Queries[1].BindVariables["__upper_limit"].String())
  2731  	assert.Equal(t, `type:INT64 value:"100"`, sbc2.Queries[1].BindVariables["__upper_limit"].String())
  2732  }
  2733  
  2734  func TestCrossShardSubqueryStream(t *testing.T) {
  2735  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2736  	result1 := []*sqltypes.Result{{
  2737  		Fields: []*querypb.Field{
  2738  			{Name: "id", Type: sqltypes.Int32},
  2739  			{Name: "col", Type: sqltypes.Int32},
  2740  		},
  2741  		InsertID: 0,
  2742  		Rows: [][]sqltypes.Value{{
  2743  			sqltypes.NewInt32(1),
  2744  			sqltypes.NewInt32(3),
  2745  		}},
  2746  	}}
  2747  	sbc1.SetResults(result1)
  2748  	result, err := executorStream(executor, "select id1 from (select u1.id id1, u2.id from user u1 join user u2 on u2.id = u1.col where u1.id = 1) as t")
  2749  	require.NoError(t, err)
  2750  	wantQueries := []*querypb.BoundQuery{{
  2751  		Sql:           "select u1.id as id1, u1.col from `user` as u1 where u1.id = 1",
  2752  		BindVariables: map[string]*querypb.BindVariable{},
  2753  	}}
  2754  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2755  	// We have to use string representation because bindvars type is too complex.
  2756  	got := fmt.Sprintf("%+v", sbc2.Queries)
  2757  	want := `[sql:"select u2.id from ` + "`user`" + ` as u2 where u2.id = :u1_col" bind_variables:{key:"u1_col" value:{type:INT32 value:"3"}}]`
  2758  	if got != want {
  2759  		t.Errorf("sbc2.Queries:\n%s, want\n%s\n", got, want)
  2760  	}
  2761  
  2762  	wantResult := &sqltypes.Result{
  2763  		Fields: []*querypb.Field{
  2764  			{Name: "id", Type: sqltypes.Int32},
  2765  		},
  2766  		Rows: [][]sqltypes.Value{{
  2767  			sqltypes.NewInt32(1),
  2768  		}},
  2769  	}
  2770  	if !result.Equal(wantResult) {
  2771  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2772  	}
  2773  }
  2774  
  2775  func TestCrossShardSubqueryGetFields(t *testing.T) {
  2776  	executor, sbc1, _, sbclookup := createExecutorEnv()
  2777  	sbclookup.SetResults([]*sqltypes.Result{{
  2778  		Fields: []*querypb.Field{
  2779  			{Name: "col", Type: sqltypes.Int32},
  2780  		},
  2781  	}})
  2782  	result1 := []*sqltypes.Result{{
  2783  		Fields: []*querypb.Field{
  2784  			{Name: "id", Type: sqltypes.Int32},
  2785  			{Name: "col", Type: sqltypes.Int32},
  2786  		},
  2787  	}}
  2788  	sbc1.SetResults(result1)
  2789  	result, err := executorExec(executor, "select main1.col, t.id1 from main1 join (select u1.id id1, u2.id from user u1 join user u2 on u2.id = u1.col where u1.id = 1) as t", nil)
  2790  	require.NoError(t, err)
  2791  	wantQueries := []*querypb.BoundQuery{{
  2792  		Sql:           "select u1.id as id1, u1.col from `user` as u1 where 1 != 1",
  2793  		BindVariables: map[string]*querypb.BindVariable{},
  2794  	}, {
  2795  		Sql: "select u2.id from `user` as u2 where 1 != 1",
  2796  		BindVariables: map[string]*querypb.BindVariable{
  2797  			"u1_col": sqltypes.NullBindVariable,
  2798  		},
  2799  	}}
  2800  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2801  
  2802  	wantResult := &sqltypes.Result{
  2803  		Fields: []*querypb.Field{
  2804  			{Name: "col", Type: sqltypes.Int32},
  2805  			{Name: "id", Type: sqltypes.Int32},
  2806  		},
  2807  	}
  2808  	if !result.Equal(wantResult) {
  2809  		t.Errorf("result: %+v, want %+v", result, wantResult)
  2810  	}
  2811  }
  2812  
  2813  func TestSelectBindvarswithPrepare(t *testing.T) {
  2814  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2815  	logChan := QueryLogger.Subscribe("Test")
  2816  	defer QueryLogger.Unsubscribe(logChan)
  2817  
  2818  	sql := "select id from user where id = :id"
  2819  	_, err := executorPrepare(executor, sql, map[string]*querypb.BindVariable{
  2820  		"id": sqltypes.Int64BindVariable(1),
  2821  	})
  2822  	require.NoError(t, err)
  2823  
  2824  	wantQueries := []*querypb.BoundQuery{{
  2825  		Sql:           "select id from `user` where 1 != 1",
  2826  		BindVariables: map[string]*querypb.BindVariable{"id": sqltypes.Int64BindVariable(1)},
  2827  	}}
  2828  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  2829  	if sbc2.Queries != nil {
  2830  		t.Errorf("sbc2.Queries: %+v, want nil\n", sbc2.Queries)
  2831  	}
  2832  }
  2833  
  2834  func TestSelectDatabasePrepare(t *testing.T) {
  2835  	executor, _, _, _ := createExecutorEnv()
  2836  	executor.normalize = true
  2837  	logChan := QueryLogger.Subscribe("Test")
  2838  	defer QueryLogger.Unsubscribe(logChan)
  2839  
  2840  	sql := "select database()"
  2841  	_, err := executorPrepare(executor, sql, map[string]*querypb.BindVariable{})
  2842  	require.NoError(t, err)
  2843  }
  2844  
  2845  func TestSelectWithUnionAll(t *testing.T) {
  2846  	executor, sbc1, sbc2, _ := createExecutorEnv()
  2847  	executor.normalize = true
  2848  	sql := "select id from user where id in (1, 2, 3) union all select id from user where id in (1, 2, 3)"
  2849  	bv, _ := sqltypes.BuildBindVariable([]int64{1, 2, 3})
  2850  	bv1, _ := sqltypes.BuildBindVariable([]int64{1, 2})
  2851  	bv2, _ := sqltypes.BuildBindVariable([]int64{3})
  2852  	sbc1WantQueries := []*querypb.BoundQuery{{
  2853  		Sql: "select id from `user` where id in ::__vals",
  2854  		BindVariables: map[string]*querypb.BindVariable{
  2855  			"__vals": bv1,
  2856  			"vtg1":   bv,
  2857  			"vtg2":   bv,
  2858  		},
  2859  	}, {
  2860  		Sql: "select id from `user` where id in ::__vals",
  2861  		BindVariables: map[string]*querypb.BindVariable{
  2862  			"__vals": bv1,
  2863  			"vtg1":   bv,
  2864  			"vtg2":   bv,
  2865  		},
  2866  	}}
  2867  	sbc2WantQueries := []*querypb.BoundQuery{{
  2868  		Sql: "select id from `user` where id in ::__vals",
  2869  		BindVariables: map[string]*querypb.BindVariable{
  2870  			"__vals": bv2,
  2871  			"vtg1":   bv,
  2872  			"vtg2":   bv,
  2873  		},
  2874  	}, {
  2875  		Sql: "select id from `user` where id in ::__vals",
  2876  		BindVariables: map[string]*querypb.BindVariable{
  2877  			"__vals": bv2,
  2878  			"vtg1":   bv,
  2879  			"vtg2":   bv,
  2880  		},
  2881  	}}
  2882  	_, err := executorExec(executor, sql, map[string]*querypb.BindVariable{})
  2883  	require.NoError(t, err)
  2884  	utils.MustMatch(t, sbc1WantQueries, sbc1.Queries, "sbc1")
  2885  	utils.MustMatch(t, sbc2WantQueries, sbc2.Queries, "sbc2")
  2886  
  2887  	// Reset
  2888  	sbc1.Queries = nil
  2889  	sbc2.Queries = nil
  2890  
  2891  	_, err = executorStream(executor, sql)
  2892  	require.NoError(t, err)
  2893  	utils.MustMatch(t, sbc1WantQueries, sbc1.Queries, "sbc1")
  2894  	utils.MustMatch(t, sbc2WantQueries, sbc2.Queries, "sbc2")
  2895  }
  2896  
  2897  func TestSelectLock(t *testing.T) {
  2898  	executor, sbc1, _, _ := createExecutorEnv()
  2899  	session := NewSafeSession(nil)
  2900  	session.Session.InTransaction = true
  2901  	session.ShardSessions = []*vtgatepb.Session_ShardSession{{
  2902  		Target: &querypb.Target{
  2903  			Keyspace:   "TestExecutor",
  2904  			Shard:      "-20",
  2905  			TabletType: topodatapb.TabletType_PRIMARY,
  2906  		},
  2907  		TransactionId: 12345,
  2908  		TabletAlias:   sbc1.Tablet().Alias,
  2909  	}}
  2910  
  2911  	wantQueries := []*querypb.BoundQuery{{
  2912  		Sql:           "select get_lock('lock name', 10) from dual",
  2913  		BindVariables: map[string]*querypb.BindVariable{},
  2914  	}}
  2915  	wantSession := &vtgatepb.Session{
  2916  		InTransaction: true,
  2917  		ShardSessions: []*vtgatepb.Session_ShardSession{{
  2918  			Target: &querypb.Target{
  2919  				Keyspace:   "TestExecutor",
  2920  				Shard:      "-20",
  2921  				TabletType: topodatapb.TabletType_PRIMARY,
  2922  			},
  2923  			TransactionId: 12345,
  2924  			TabletAlias:   sbc1.Tablet().Alias,
  2925  		}},
  2926  		LockSession: &vtgatepb.Session_ShardSession{
  2927  			Target:      &querypb.Target{Keyspace: "TestExecutor", Shard: "-20", TabletType: topodatapb.TabletType_PRIMARY},
  2928  			TabletAlias: sbc1.Tablet().Alias,
  2929  			ReservedId:  1,
  2930  		},
  2931  		AdvisoryLock: map[string]int64{"lock name": 1},
  2932  		FoundRows:    1,
  2933  		RowCount:     -1,
  2934  	}
  2935  
  2936  	_, err := exec(executor, session, "select get_lock('lock name', 10) from dual")
  2937  	require.NoError(t, err)
  2938  	wantSession.LastLockHeartbeat = session.Session.LastLockHeartbeat // copying as this is current timestamp value.
  2939  	utils.MustMatch(t, wantSession, session.Session, "")
  2940  	utils.MustMatch(t, wantQueries, sbc1.Queries, "")
  2941  
  2942  	wantQueries = append(wantQueries, &querypb.BoundQuery{
  2943  		Sql:           "select release_lock('lock name') from dual",
  2944  		BindVariables: map[string]*querypb.BindVariable{},
  2945  	})
  2946  	wantSession.AdvisoryLock = nil
  2947  	wantSession.LockSession = nil
  2948  
  2949  	_, err = exec(executor, session, "select release_lock('lock name') from dual")
  2950  	require.NoError(t, err)
  2951  	wantSession.LastLockHeartbeat = session.Session.LastLockHeartbeat // copying as this is current timestamp value.
  2952  	utils.MustMatch(t, wantQueries, sbc1.Queries, "")
  2953  	utils.MustMatch(t, wantSession, session.Session, "")
  2954  }
  2955  
  2956  func TestLockReserve(t *testing.T) {
  2957  	// no connection should be reserved for these queries.
  2958  	tcases := []string{
  2959  		"select is_free_lock('lock name') from dual",
  2960  		"select is_used_lock('lock name') from dual",
  2961  		"select release_all_locks() from dual",
  2962  		"select release_lock('lock name') from dual",
  2963  	}
  2964  
  2965  	executor, _, _, _ := createExecutorEnv()
  2966  	session := NewAutocommitSession(&vtgatepb.Session{})
  2967  
  2968  	for _, sql := range tcases {
  2969  		t.Run(sql, func(t *testing.T) {
  2970  			_, err := exec(executor, session, sql)
  2971  			require.NoError(t, err)
  2972  			require.Nil(t, session.LockSession)
  2973  		})
  2974  	}
  2975  
  2976  	// get_lock should reserve a connection.
  2977  	_, err := exec(executor, session, "select get_lock('lock name', 10) from dual")
  2978  	require.NoError(t, err)
  2979  	require.NotNil(t, session.LockSession)
  2980  
  2981  }
  2982  
  2983  func TestSelectFromInformationSchema(t *testing.T) {
  2984  	executor, sbc1, _, _ := createExecutorEnv()
  2985  	session := NewSafeSession(nil)
  2986  
  2987  	// check failure when trying to query two keyspaces
  2988  	_, err := exec(executor, session, "SELECT B.TABLE_NAME FROM INFORMATION_SCHEMA.TABLES AS A, INFORMATION_SCHEMA.COLUMNS AS B WHERE A.TABLE_SCHEMA = 'TestExecutor' AND A.TABLE_SCHEMA = 'TestXBadSharding'")
  2989  	require.Error(t, err)
  2990  	require.Contains(t, err.Error(), "specifying two different database in the query is not supported")
  2991  
  2992  	// we pick a keyspace and query for table_schema = database(). should be routed to the picked keyspace
  2993  	session.TargetString = "TestExecutor"
  2994  	_, err = exec(executor, session, "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = database()")
  2995  	require.NoError(t, err)
  2996  	assert.Equal(t, sbc1.StringQueries(), []string{"select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = database()"})
  2997  
  2998  	// `USE TestXBadSharding` and then query info_schema about TestExecutor - should target TestExecutor and not use the default keyspace
  2999  	sbc1.Queries = nil
  3000  	session.TargetString = "TestXBadSharding"
  3001  	_, err = exec(executor, session, "SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = 'TestExecutor'")
  3002  	require.NoError(t, err)
  3003  	assert.Equal(t, sbc1.StringQueries(), []string{"select * from INFORMATION_SCHEMA.`TABLES` where TABLE_SCHEMA = :__vtschemaname"})
  3004  }
  3005  
  3006  func TestStreamOrderByLimitWithMultipleResults(t *testing.T) {
  3007  	// Special setup: Don't use createExecutorEnv.
  3008  	cell := "aa"
  3009  	hc := discovery.NewFakeHealthCheck(nil)
  3010  	s := createSandbox(KsTestSharded)
  3011  	s.VSchema = executorVSchema
  3012  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  3013  	serv := newSandboxForCells([]string{cell})
  3014  	resolver := newTestResolver(hc, serv, cell)
  3015  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  3016  	count := 1
  3017  	for _, shard := range shards {
  3018  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  3019  		sbc.SetResults([]*sqltypes.Result{
  3020  			sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|col|weight_string(id)", "int32|int32|varchar"), fmt.Sprintf("%d|%d|NULL", count, count)),
  3021  			sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|col|weight_string(id)", "int32|int32|varchar"), fmt.Sprintf("%d|%d|NULL", count+10, count)),
  3022  		})
  3023  		count++
  3024  	}
  3025  
  3026  	executor := NewExecutor(context.Background(), serv, cell, resolver, true, false, testBufferSize, cache.DefaultConfig, nil, false, querypb.ExecuteOptions_V3)
  3027  	before := runtime.NumGoroutine()
  3028  
  3029  	query := "select id, col from user order by id limit 2"
  3030  	gotResult, err := executorStream(executor, query)
  3031  	require.NoError(t, err)
  3032  
  3033  	wantResult := sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|col", "int32|int32"), "1|1", "2|2")
  3034  	utils.MustMatch(t, wantResult, gotResult)
  3035  	// some sleep to close all goroutines.
  3036  	time.Sleep(100 * time.Millisecond)
  3037  	assert.GreaterOrEqual(t, before, runtime.NumGoroutine(), "left open goroutines lingering")
  3038  }
  3039  
  3040  func TestSelectScatterFails(t *testing.T) {
  3041  	sess := &vtgatepb.Session{}
  3042  	cell := "aa"
  3043  	hc := discovery.NewFakeHealthCheck(nil)
  3044  	s := createSandbox(KsTestSharded)
  3045  	s.VSchema = executorVSchema
  3046  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  3047  	serv := newSandboxForCells([]string{cell})
  3048  	resolver := newTestResolver(hc, serv, cell)
  3049  
  3050  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  3051  	for i, shard := range shards {
  3052  		sbc := hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  3053  		sbc.SetResults([]*sqltypes.Result{{
  3054  			Fields: []*querypb.Field{
  3055  				{Name: "col1", Type: sqltypes.Int32},
  3056  				{Name: "col2", Type: sqltypes.Int32},
  3057  				{Name: "weight_string(col2)", Type: sqltypes.VarBinary},
  3058  			},
  3059  			InsertID: 0,
  3060  			Rows: [][]sqltypes.Value{{
  3061  				sqltypes.NewInt32(1),
  3062  				sqltypes.NewInt32(int32(i % 4)),
  3063  				sqltypes.NULL,
  3064  			}},
  3065  		}})
  3066  	}
  3067  
  3068  	executor := createExecutor(serv, cell, resolver)
  3069  	executor.allowScatter = false
  3070  	logChan := QueryLogger.Subscribe("Test")
  3071  	defer QueryLogger.Unsubscribe(logChan)
  3072  
  3073  	_, err := executorExecSession(executor, "select id from user", nil, sess)
  3074  	require.Error(t, err)
  3075  	assert.Contains(t, err.Error(), "scatter")
  3076  
  3077  	// Run the test again, to ensure it behaves the same for a cached query
  3078  	_, err = executorExecSession(executor, "select id from user", nil, sess)
  3079  	require.Error(t, err)
  3080  	assert.Contains(t, err.Error(), "scatter")
  3081  
  3082  	_, err = executorExecSession(executor, "select /*vt+ ALLOW_SCATTER */ id from user", nil, sess)
  3083  	require.NoError(t, err)
  3084  
  3085  	_, err = executorExecSession(executor, "begin", nil, sess)
  3086  	require.NoError(t, err)
  3087  
  3088  	_, err = executorExecSession(executor, "commit", nil, sess)
  3089  	require.NoError(t, err)
  3090  
  3091  	_, err = executorExecSession(executor, "savepoint a", nil, sess)
  3092  	require.NoError(t, err)
  3093  }
  3094  
  3095  func TestGen4SelectStraightJoin(t *testing.T) {
  3096  	executor, sbc1, _, _ := createExecutorEnv()
  3097  	executor.normalize = true
  3098  	executor.pv = querypb.ExecuteOptions_Gen4
  3099  	session := NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"})
  3100  	query := "select u.id from user u straight_join user2 u2 on u.id = u2.id"
  3101  	_, err := executor.Execute(context.Background(),
  3102  		"TestGen4SelectStraightJoin",
  3103  		session,
  3104  		query, map[string]*querypb.BindVariable{},
  3105  	)
  3106  	require.NoError(t, err)
  3107  	wantQueries := []*querypb.BoundQuery{
  3108  		{
  3109  			Sql:           "select u.id from `user` as u, user2 as u2 where u.id = u2.id",
  3110  			BindVariables: map[string]*querypb.BindVariable{},
  3111  		},
  3112  	}
  3113  	wantWarnings := []*querypb.QueryWarning{
  3114  		{
  3115  			Code:    1235,
  3116  			Message: "straight join is converted to normal join",
  3117  		},
  3118  	}
  3119  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  3120  	utils.MustMatch(t, wantWarnings, session.Warnings)
  3121  }
  3122  
  3123  func TestGen4MultiColumnVindexEqual(t *testing.T) {
  3124  	executor, sbc1, sbc2, _ := createExecutorEnv()
  3125  	executor.normalize = true
  3126  	executor.pv = querypb.ExecuteOptions_Gen4
  3127  
  3128  	session := NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"})
  3129  	query := "select * from user_region where cola = 1 and colb = 2"
  3130  	_, err := executor.Execute(context.Background(),
  3131  		"TestGen4MultiColumnVindex",
  3132  		session,
  3133  		query, map[string]*querypb.BindVariable{},
  3134  	)
  3135  	require.NoError(t, err)
  3136  	wantQueries := []*querypb.BoundQuery{
  3137  		{
  3138  			Sql: "select * from user_region where cola = :cola and colb = :colb",
  3139  			BindVariables: map[string]*querypb.BindVariable{
  3140  				"cola": sqltypes.Int64BindVariable(1),
  3141  				"colb": sqltypes.Int64BindVariable(2),
  3142  			},
  3143  		},
  3144  	}
  3145  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  3146  	require.Nil(t, sbc2.Queries)
  3147  
  3148  	sbc1.Queries = nil
  3149  
  3150  	query = "select * from user_region where cola = 17984 and colb = 1"
  3151  	_, err = executor.Execute(context.Background(),
  3152  		"TestGen4MultiColumnVindex",
  3153  		session,
  3154  		query, map[string]*querypb.BindVariable{},
  3155  	)
  3156  	require.NoError(t, err)
  3157  	wantQueries = []*querypb.BoundQuery{
  3158  		{
  3159  			Sql: "select * from user_region where cola = :cola and colb = :colb",
  3160  			BindVariables: map[string]*querypb.BindVariable{
  3161  				"cola": sqltypes.Int64BindVariable(17984),
  3162  				"colb": sqltypes.Int64BindVariable(1),
  3163  			},
  3164  		},
  3165  	}
  3166  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  3167  	require.Nil(t, sbc1.Queries)
  3168  }
  3169  
  3170  func TestGen4MultiColumnVindexIn(t *testing.T) {
  3171  	executor, sbc1, sbc2, _ := createExecutorEnv()
  3172  	executor.normalize = true
  3173  	executor.pv = querypb.ExecuteOptions_Gen4
  3174  
  3175  	session := NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"})
  3176  	query := "select * from user_region where cola IN (1,17984) and colb IN (2,3,4)"
  3177  	_, err := executor.Execute(context.Background(),
  3178  		"TestGen4MultiColumnVindex",
  3179  		session,
  3180  		query, map[string]*querypb.BindVariable{},
  3181  	)
  3182  	require.NoError(t, err)
  3183  	bv1, _ := sqltypes.BuildBindVariable([]int64{1})
  3184  	bv2, _ := sqltypes.BuildBindVariable([]int64{17984})
  3185  	bvtg1, _ := sqltypes.BuildBindVariable([]int64{1, 17984})
  3186  	bvtg2, _ := sqltypes.BuildBindVariable([]int64{2, 3, 4})
  3187  	wantQueries := []*querypb.BoundQuery{
  3188  		{
  3189  			Sql: "select * from user_region where cola in ::__vals0 and colb in ::__vals1",
  3190  			BindVariables: map[string]*querypb.BindVariable{
  3191  				"__vals0": bv1,
  3192  				"__vals1": bvtg2,
  3193  				"vtg1":    bvtg1,
  3194  				"vtg2":    bvtg2,
  3195  			},
  3196  		},
  3197  	}
  3198  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  3199  	wantQueries = []*querypb.BoundQuery{
  3200  		{
  3201  			Sql: "select * from user_region where cola in ::__vals0 and colb in ::__vals1",
  3202  			BindVariables: map[string]*querypb.BindVariable{
  3203  				"__vals0": bv2,
  3204  				"__vals1": bvtg2,
  3205  				"vtg1":    bvtg1,
  3206  				"vtg2":    bvtg2,
  3207  			},
  3208  		},
  3209  	}
  3210  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  3211  }
  3212  
  3213  func TestGen4MultiColMixedColComparision(t *testing.T) {
  3214  	executor, sbc1, sbc2, _ := createExecutorEnv()
  3215  	executor.normalize = true
  3216  	executor.pv = querypb.ExecuteOptions_Gen4
  3217  
  3218  	session := NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"})
  3219  	query := "select * from user_region where colb = 2 and cola IN (1,17984)"
  3220  	_, err := executor.Execute(context.Background(),
  3221  		"TestGen4MultiColMixedColComparision",
  3222  		session,
  3223  		query, map[string]*querypb.BindVariable{},
  3224  	)
  3225  	require.NoError(t, err)
  3226  	bvtg1 := sqltypes.Int64BindVariable(2)
  3227  	bvtg2, _ := sqltypes.BuildBindVariable([]int64{1, 17984})
  3228  	vals0sbc1, _ := sqltypes.BuildBindVariable([]int64{1})
  3229  	vals0sbc2, _ := sqltypes.BuildBindVariable([]int64{17984})
  3230  	wantQueries := []*querypb.BoundQuery{
  3231  		{
  3232  			Sql: "select * from user_region where colb = :colb and cola in ::__vals0",
  3233  			BindVariables: map[string]*querypb.BindVariable{
  3234  				"__vals0": vals0sbc1,
  3235  				"colb":    bvtg1,
  3236  				"vtg1":    bvtg2,
  3237  			},
  3238  		},
  3239  	}
  3240  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  3241  	wantQueries = []*querypb.BoundQuery{
  3242  		{
  3243  			Sql: "select * from user_region where colb = :colb and cola in ::__vals0",
  3244  			BindVariables: map[string]*querypb.BindVariable{
  3245  				"__vals0": vals0sbc2,
  3246  				"colb":    bvtg1,
  3247  				"vtg1":    bvtg2,
  3248  			},
  3249  		},
  3250  	}
  3251  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  3252  }
  3253  
  3254  func TestGen4MultiColBestVindexSel(t *testing.T) {
  3255  	executor, sbc1, sbc2, _ := createExecutorEnv()
  3256  	executor.normalize = true
  3257  	executor.pv = querypb.ExecuteOptions_Gen4
  3258  
  3259  	session := NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"})
  3260  	query := "select * from user_region where colb = 2 and cola IN (1,17984) and cola = 1"
  3261  	_, err := executor.Execute(context.Background(),
  3262  		"TestGen4MultiColBestVindexSel",
  3263  		session,
  3264  		query, map[string]*querypb.BindVariable{},
  3265  	)
  3266  	require.NoError(t, err)
  3267  	bvtg2, _ := sqltypes.BuildBindVariable([]int64{1, 17984})
  3268  	wantQueries := []*querypb.BoundQuery{
  3269  		{
  3270  			Sql: "select * from user_region where colb = :colb and cola in ::vtg1 and cola = :cola",
  3271  			BindVariables: map[string]*querypb.BindVariable{
  3272  				"colb": sqltypes.Int64BindVariable(2),
  3273  				"vtg1": bvtg2,
  3274  				"cola": sqltypes.Int64BindVariable(1),
  3275  			},
  3276  		},
  3277  	}
  3278  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  3279  	require.Nil(t, sbc2.Queries)
  3280  
  3281  	// reset
  3282  	sbc1.Queries = nil
  3283  
  3284  	query = "select * from user_region where colb in (10,20) and cola IN (1,17984) and cola = 1 and colb = 2"
  3285  	_, err = executor.Execute(context.Background(),
  3286  		"TestGen4MultiColBestVindexSel",
  3287  		session,
  3288  		query, map[string]*querypb.BindVariable{},
  3289  	)
  3290  	require.NoError(t, err)
  3291  
  3292  	bvtg1, _ := sqltypes.BuildBindVariable([]int64{10, 20})
  3293  	wantQueries = []*querypb.BoundQuery{
  3294  		{
  3295  			Sql: "select * from user_region where colb in ::vtg1 and cola in ::vtg2 and cola = :cola and colb = :colb",
  3296  			BindVariables: map[string]*querypb.BindVariable{
  3297  				"vtg1": bvtg1,
  3298  				"vtg2": bvtg2,
  3299  				"cola": sqltypes.Int64BindVariable(1),
  3300  				"colb": sqltypes.Int64BindVariable(2),
  3301  			},
  3302  		},
  3303  	}
  3304  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  3305  	require.Nil(t, sbc2.Queries)
  3306  }
  3307  
  3308  func TestGen4MultiColMultiEqual(t *testing.T) {
  3309  	executor, sbc1, sbc2, _ := createExecutorEnv()
  3310  	executor.normalize = true
  3311  	executor.pv = querypb.ExecuteOptions_Gen4
  3312  
  3313  	session := NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"})
  3314  	query := "select * from user_region where (cola,colb) in ((17984,2),(17984,3))"
  3315  	_, err := executor.Execute(context.Background(),
  3316  		"TestGen4MultiColMultiEqual",
  3317  		session,
  3318  		query, map[string]*querypb.BindVariable{},
  3319  	)
  3320  	require.NoError(t, err)
  3321  	wantQueries := []*querypb.BoundQuery{
  3322  		{
  3323  			Sql: "select * from user_region where (cola, colb) in ((:vtg1, :vtg2), (:vtg1, :vtg3))",
  3324  			BindVariables: map[string]*querypb.BindVariable{
  3325  				"vtg1": sqltypes.Int64BindVariable(17984),
  3326  				"vtg2": sqltypes.Int64BindVariable(2),
  3327  				"vtg3": sqltypes.Int64BindVariable(3),
  3328  			},
  3329  		},
  3330  	}
  3331  	require.Nil(t, sbc1.Queries)
  3332  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  3333  }
  3334  
  3335  func TestGen4SelectUnqualifiedReferenceTable(t *testing.T) {
  3336  	executor, sbc1, sbc2, sbclookup := createExecutorEnv()
  3337  	executor.pv = querypb.ExecuteOptions_Gen4
  3338  
  3339  	query := "select * from zip_detail"
  3340  	_, err := executorExec(executor, query, nil)
  3341  	require.NoError(t, err)
  3342  	wantQueries := []*querypb.BoundQuery{
  3343  		{
  3344  			Sql:           query,
  3345  			BindVariables: map[string]*querypb.BindVariable{},
  3346  		},
  3347  	}
  3348  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
  3349  	require.Nil(t, sbc1.Queries)
  3350  	require.Nil(t, sbc2.Queries)
  3351  }
  3352  
  3353  func TestGen4SelectQualifiedReferenceTable(t *testing.T) {
  3354  	executor, sbc1, sbc2, sbclookup := createExecutorEnv()
  3355  	executor.pv = querypb.ExecuteOptions_Gen4
  3356  
  3357  	query := fmt.Sprintf("select * from %s.zip_detail", KsTestSharded)
  3358  	_, err := executorExec(executor, query, nil)
  3359  	require.NoError(t, err)
  3360  	wantQueries := []*querypb.BoundQuery{
  3361  		{
  3362  			Sql:           "select * from zip_detail",
  3363  			BindVariables: map[string]*querypb.BindVariable{},
  3364  		},
  3365  	}
  3366  	require.Nil(t, sbclookup.Queries)
  3367  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  3368  	require.Nil(t, sbc2.Queries)
  3369  }
  3370  
  3371  func TestGen4JoinUnqualifiedReferenceTable(t *testing.T) {
  3372  	executor, sbc1, sbc2, sbclookup := createExecutorEnv()
  3373  	executor.pv = querypb.ExecuteOptions_Gen4
  3374  
  3375  	query := "select * from user join zip_detail on user.zip_detail_id = zip_detail.id"
  3376  	_, err := executorExec(executor, query, nil)
  3377  	require.NoError(t, err)
  3378  	wantQueries := []*querypb.BoundQuery{
  3379  		{
  3380  			Sql:           "select * from `user`, zip_detail where `user`.zip_detail_id = zip_detail.id",
  3381  			BindVariables: map[string]*querypb.BindVariable{},
  3382  		},
  3383  	}
  3384  	require.Nil(t, sbclookup.Queries)
  3385  	utils.MustMatch(t, wantQueries, sbc1.Queries)
  3386  	utils.MustMatch(t, wantQueries, sbc2.Queries)
  3387  
  3388  	sbc1.Queries = nil
  3389  	sbc2.Queries = nil
  3390  
  3391  	query = "select * from simple join zip_detail on simple.zip_detail_id = zip_detail.id"
  3392  	_, err = executorExec(executor, query, nil)
  3393  	require.NoError(t, err)
  3394  	wantQueries = []*querypb.BoundQuery{
  3395  		{
  3396  			Sql:           "select * from `simple` join zip_detail on `simple`.zip_detail_id = zip_detail.id",
  3397  			BindVariables: map[string]*querypb.BindVariable{},
  3398  		},
  3399  	}
  3400  	utils.MustMatch(t, wantQueries, sbclookup.Queries)
  3401  	require.Nil(t, sbc1.Queries)
  3402  	require.Nil(t, sbc2.Queries)
  3403  }
  3404  
  3405  func TestGen4CrossShardJoinQualifiedReferenceTable(t *testing.T) {
  3406  	executor, sbc1, sbc2, sbclookup := createExecutorEnv()
  3407  	executor.pv = querypb.ExecuteOptions_Gen4
  3408  
  3409  	query := "select user.id from user join TestUnsharded.zip_detail on user.zip_detail_id = TestUnsharded.zip_detail.id"
  3410  	_, err := executorExec(executor, query, nil)
  3411  	require.NoError(t, err)
  3412  
  3413  	shardedWantQueries := []*querypb.BoundQuery{
  3414  		{
  3415  			Sql:           "select `user`.id from `user`, zip_detail where `user`.zip_detail_id = zip_detail.id",
  3416  			BindVariables: map[string]*querypb.BindVariable{},
  3417  		},
  3418  	}
  3419  	require.Nil(t, sbclookup.Queries)
  3420  	utils.MustMatch(t, shardedWantQueries, sbc1.Queries)
  3421  	utils.MustMatch(t, shardedWantQueries, sbc2.Queries)
  3422  
  3423  	sbclookup.Queries = nil
  3424  	sbc1.Queries = nil
  3425  	sbc2.Queries = nil
  3426  
  3427  	query = "select simple.id from simple join TestExecutor.zip_detail on simple.zip_detail_id = TestExecutor.zip_detail.id"
  3428  	_, err = executorExec(executor, query, nil)
  3429  	require.NoError(t, err)
  3430  	unshardedWantQueries := []*querypb.BoundQuery{
  3431  		{
  3432  			Sql:           "select `simple`.id from `simple` join zip_detail on `simple`.zip_detail_id = zip_detail.id",
  3433  			BindVariables: map[string]*querypb.BindVariable{},
  3434  		},
  3435  	}
  3436  	utils.MustMatch(t, unshardedWantQueries, sbclookup.Queries)
  3437  	require.Nil(t, sbc1.Queries)
  3438  	require.Nil(t, sbc2.Queries)
  3439  }
  3440  
  3441  func TestRegionRange(t *testing.T) {
  3442  	// Special setup: Don't use createExecutorEnv.
  3443  
  3444  	cell := "regioncell"
  3445  	ks := "TestExecutor"
  3446  	hc := discovery.NewFakeHealthCheck(nil)
  3447  	s := createSandbox(ks)
  3448  	s.ShardSpec = "-20-20a0-"
  3449  	s.VSchema = executorVSchema
  3450  	serv := newSandboxForCells([]string{cell})
  3451  	resolver := newTestResolver(hc, serv, cell)
  3452  	shards := []string{"-20", "20-20a0", "20a0-"}
  3453  	var conns []*sandboxconn.SandboxConn
  3454  	for _, shard := range shards {
  3455  		sbc := hc.AddTestTablet(cell, shard, 1, ks, shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  3456  		conns = append(conns, sbc)
  3457  	}
  3458  	executor := createExecutor(serv, cell, resolver)
  3459  	executor.pv = querypb.ExecuteOptions_Gen4
  3460  
  3461  	tcases := []struct {
  3462  		regionID          int
  3463  		noOfShardsTouched int
  3464  	}{{
  3465  		regionID:          31,
  3466  		noOfShardsTouched: 1,
  3467  	}, {
  3468  		regionID:          32,
  3469  		noOfShardsTouched: 2,
  3470  	}, {
  3471  		regionID:          33,
  3472  		noOfShardsTouched: 1,
  3473  	}}
  3474  	for _, tcase := range tcases {
  3475  		t.Run(strconv.Itoa(tcase.regionID), func(t *testing.T) {
  3476  			sql := fmt.Sprintf("select * from user_region where cola = %d", tcase.regionID)
  3477  			_, err := executor.Execute(
  3478  				context.Background(),
  3479  				"TestRegionRange",
  3480  				NewAutocommitSession(&vtgatepb.Session{}),
  3481  				sql,
  3482  				nil)
  3483  			require.NoError(t, err)
  3484  			count := 0
  3485  			for _, sbc := range conns {
  3486  				count = count + len(sbc.Queries)
  3487  				sbc.Queries = nil
  3488  			}
  3489  			require.Equal(t, tcase.noOfShardsTouched, count)
  3490  		})
  3491  	}
  3492  }
  3493  
  3494  func TestMultiCol(t *testing.T) {
  3495  	// Special setup: Don't use createLegacyExecutorEnv.
  3496  	cell := "multicol"
  3497  	ks := "TestMultiCol"
  3498  	hc := discovery.NewFakeHealthCheck(nil)
  3499  	s := createSandbox(ks)
  3500  	s.ShardSpec = "-20-20a0-"
  3501  	s.VSchema = multiColVschema
  3502  	serv := newSandboxForCells([]string{cell})
  3503  	resolver := newTestResolver(hc, serv, cell)
  3504  	shards := []string{"-20", "20-20a0", "20a0-"}
  3505  	var conns []*sandboxconn.SandboxConn
  3506  	for _, shard := range shards {
  3507  		sbc := hc.AddTestTablet(cell, shard, 1, ks, shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  3508  		conns = append(conns, sbc)
  3509  	}
  3510  	executor := createExecutor(serv, cell, resolver)
  3511  	executor.pv = querypb.ExecuteOptions_Gen4
  3512  
  3513  	tcases := []struct {
  3514  		cola, colb, colc int
  3515  		shards           []string
  3516  	}{{
  3517  		cola: 202, colb: 1, colc: 1,
  3518  		shards: []string{"-20"},
  3519  	}, {
  3520  		cola: 203, colb: 1, colc: 1,
  3521  		shards: []string{"20-20a0"},
  3522  	}, {
  3523  		cola: 204, colb: 1, colc: 1,
  3524  		shards: []string{"20a0-"},
  3525  	}}
  3526  
  3527  	ctx := context.Background()
  3528  	session := NewAutocommitSession(&vtgatepb.Session{})
  3529  
  3530  	for _, tcase := range tcases {
  3531  		t.Run(fmt.Sprintf("%d_%d_%d", tcase.cola, tcase.colb, tcase.colc), func(t *testing.T) {
  3532  			sql := fmt.Sprintf("select * from multicoltbl where cola = %d and colb = %d and colc = '%d'", tcase.cola, tcase.colb, tcase.colc)
  3533  			_, err := executor.Execute(ctx, "TestMultiCol", session, sql, nil)
  3534  			require.NoError(t, err)
  3535  			var shards []string
  3536  			for _, sbc := range conns {
  3537  				if len(sbc.Queries) > 0 {
  3538  					shards = append(shards, sbc.Tablet().Shard)
  3539  					sbc.Queries = nil
  3540  				}
  3541  			}
  3542  			require.Equal(t, tcase.shards, shards)
  3543  		})
  3544  	}
  3545  }
  3546  
  3547  var multiColVschema = `
  3548  {
  3549  	"sharded": true,
  3550  	"vindexes": {
  3551  		"multicol_vdx": {
  3552  			"type": "multicol",
  3553  			"params": {
  3554  				"column_count": "3",
  3555  				"column_bytes": "1,3,4",
  3556  				"column_vindex": "hash,binary,unicode_loose_xxhash"
  3557  			}
  3558          }
  3559  	},
  3560  	"tables": {
  3561  		"multicoltbl": {
  3562  			"column_vindexes": [
  3563  				{
  3564  					"columns": ["cola","colb","colc"],
  3565  					"name": "multicol_vdx"
  3566  				}
  3567  			]
  3568  		}
  3569  	}
  3570  }
  3571  `
  3572  
  3573  func TestMultiColPartial(t *testing.T) {
  3574  	// Special setup: Don't use createLegacyExecutorEnv.
  3575  	cell := "multicol"
  3576  	ks := "TestMultiCol"
  3577  	hc := discovery.NewFakeHealthCheck(nil)
  3578  	s := createSandbox(ks)
  3579  	s.ShardSpec = "-20-20a0c0-"
  3580  	s.VSchema = multiColVschema
  3581  	serv := newSandboxForCells([]string{cell})
  3582  	resolver := newTestResolver(hc, serv, cell)
  3583  	shards := []string{"-20", "20-20a0c0", "20a0c0-"}
  3584  	var conns []*sandboxconn.SandboxConn
  3585  	for _, shard := range shards {
  3586  		sbc := hc.AddTestTablet(cell, shard, 1, ks, shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  3587  		conns = append(conns, sbc)
  3588  	}
  3589  	executor := createExecutor(serv, cell, resolver)
  3590  	executor.pv = querypb.ExecuteOptions_Gen4
  3591  
  3592  	tcases := []struct {
  3593  		where  string
  3594  		shards []string
  3595  	}{{
  3596  		where:  "cola = 252",
  3597  		shards: []string{"-20"},
  3598  	}, {
  3599  		where:  "cola = 289",
  3600  		shards: []string{"20a0c0-"},
  3601  	}, {
  3602  		where:  "cola = 606",
  3603  		shards: []string{"20-20a0c0", "20a0c0-"},
  3604  	}, {
  3605  		where:  "cola = 606 and colb = _binary '\x1f'",
  3606  		shards: []string{"20-20a0c0"},
  3607  	}, {
  3608  		where:  "cola = 606 and colb = _binary '\xa0'",
  3609  		shards: []string{"20-20a0c0", "20a0c0-"},
  3610  	}, {
  3611  		where:  "cola = 606 and colb = _binary '\xa1'",
  3612  		shards: []string{"20a0c0-"},
  3613  	}}
  3614  
  3615  	ctx := context.Background()
  3616  	session := NewAutocommitSession(&vtgatepb.Session{})
  3617  
  3618  	for _, tcase := range tcases {
  3619  		t.Run(tcase.where, func(t *testing.T) {
  3620  			sql := fmt.Sprintf("select * from multicoltbl where %s", tcase.where)
  3621  			_, err := executor.Execute(ctx, "TestMultiCol", session, sql, nil)
  3622  			require.NoError(t, err)
  3623  			var shards []string
  3624  			for _, sbc := range conns {
  3625  				if len(sbc.Queries) > 0 {
  3626  					shards = append(shards, sbc.Tablet().Shard)
  3627  					sbc.Queries = nil
  3628  				}
  3629  			}
  3630  			require.Equal(t, tcase.shards, shards)
  3631  		})
  3632  	}
  3633  }
  3634  
  3635  func TestSelectAggregationNoData(t *testing.T) {
  3636  	// Special setup: Don't use createExecutorEnv.
  3637  	cell := "aa"
  3638  	hc := discovery.NewFakeHealthCheck(nil)
  3639  	createSandbox(KsTestSharded).VSchema = executorVSchema
  3640  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  3641  	serv := newSandboxForCells([]string{cell})
  3642  	resolver := newTestResolver(hc, serv, cell)
  3643  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  3644  	var conns []*sandboxconn.SandboxConn
  3645  	for _, shard := range shards {
  3646  		sbc := hc.AddTestTablet(cell, shard, 1, KsTestSharded, shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  3647  		conns = append(conns, sbc)
  3648  	}
  3649  	executor := createExecutor(serv, cell, resolver)
  3650  	executor.pv = querypb.ExecuteOptions_Gen4
  3651  
  3652  	tcases := []struct {
  3653  		sql         string
  3654  		sandboxRes  *sqltypes.Result
  3655  		expSandboxQ string
  3656  		expField    string
  3657  		expRow      string
  3658  	}{
  3659  		{
  3660  			sql:         `select count(distinct col) from user`,
  3661  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col", "int64")),
  3662  			expSandboxQ: "select col, weight_string(col) from `user` group by col, weight_string(col) order by col asc",
  3663  			expField:    `[name:"count(distinct col)" type:INT64]`,
  3664  			expRow:      `[[INT64(0)]]`,
  3665  		},
  3666  		{
  3667  			sql:         `select count(*) from user`,
  3668  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("count(*)", "int64"), "0"),
  3669  			expSandboxQ: "select count(*) from `user`",
  3670  			expField:    `[name:"count(*)" type:INT64]`,
  3671  			expRow:      `[[INT64(0)]]`,
  3672  		},
  3673  		{
  3674  			sql:         `select col, count(*) from user group by col`,
  3675  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col|count(*)", "int64|int64")),
  3676  			expSandboxQ: "select col, count(*), weight_string(col) from `user` group by col, weight_string(col) order by col asc",
  3677  			expField:    `[name:"col" type:INT64 name:"count(*)" type:INT64]`,
  3678  			expRow:      `[]`,
  3679  		},
  3680  		{
  3681  			sql:         `select col, count(*) from user group by col limit 2`,
  3682  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col|count(*)", "int64|int64")),
  3683  			expSandboxQ: "select col, count(*), weight_string(col) from `user` group by col, weight_string(col) order by col asc limit :__upper_limit",
  3684  			expField:    `[name:"col" type:INT64 name:"count(*)" type:INT64]`,
  3685  			expRow:      `[]`,
  3686  		},
  3687  		{
  3688  			sql:         `select count(*) from (select col1, col2 from user limit 2) x`,
  3689  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2", "int64|int64")),
  3690  			expSandboxQ: "select col1, col2 from `user` limit :__upper_limit",
  3691  			expField:    `[name:"count(*)" type:INT64]`,
  3692  			expRow:      `[[INT64(0)]]`,
  3693  		},
  3694  		{
  3695  			sql:         `select col2, count(*) from (select col1, col2 from user limit 2) x group by col2`,
  3696  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2|weight_string(col2)", "int64|int64|varbinary")),
  3697  			expSandboxQ: "select col1, col2, weight_string(col2) from `user` order by col2 asc limit :__upper_limit",
  3698  			expField:    `[name:"col2" type:INT64 name:"count(*)" type:INT64]`,
  3699  			expRow:      `[]`,
  3700  		},
  3701  	}
  3702  
  3703  	for _, tc := range tcases {
  3704  		t.Run(tc.sql, func(t *testing.T) {
  3705  			for _, sbc := range conns {
  3706  				sbc.SetResults([]*sqltypes.Result{tc.sandboxRes})
  3707  				sbc.Queries = nil
  3708  			}
  3709  			qr, err := executorExec(executor, tc.sql, nil)
  3710  			require.NoError(t, err)
  3711  			assert.Equal(t, tc.expField, fmt.Sprintf("%v", qr.Fields))
  3712  			assert.Equal(t, tc.expRow, fmt.Sprintf("%v", qr.Rows))
  3713  			require.Len(t, conns[0].Queries, 1)
  3714  			assert.Equal(t, tc.expSandboxQ, conns[0].Queries[0].Sql)
  3715  		})
  3716  	}
  3717  }
  3718  
  3719  func TestSelectAggregationData(t *testing.T) {
  3720  	// Special setup: Don't use createExecutorEnv.
  3721  	cell := "aa"
  3722  	hc := discovery.NewFakeHealthCheck(nil)
  3723  	createSandbox(KsTestSharded).VSchema = executorVSchema
  3724  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  3725  	serv := newSandboxForCells([]string{cell})
  3726  	resolver := newTestResolver(hc, serv, cell)
  3727  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  3728  	var conns []*sandboxconn.SandboxConn
  3729  	for _, shard := range shards {
  3730  		sbc := hc.AddTestTablet(cell, shard, 1, KsTestSharded, shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  3731  		conns = append(conns, sbc)
  3732  	}
  3733  	executor := createExecutor(serv, cell, resolver)
  3734  	executor.pv = querypb.ExecuteOptions_Gen4
  3735  
  3736  	tcases := []struct {
  3737  		sql         string
  3738  		sandboxRes  *sqltypes.Result
  3739  		expSandboxQ string
  3740  		expField    string
  3741  		expRow      string
  3742  	}{
  3743  		{
  3744  			sql:         `select count(distinct col) from user`,
  3745  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col|weight_string(col)", "int64|varbinary"), "1|NULL", "2|NULL", "2|NULL", "3|NULL"),
  3746  			expSandboxQ: "select col, weight_string(col) from `user` group by col, weight_string(col) order by col asc",
  3747  			expField:    `[name:"count(distinct col)" type:INT64]`,
  3748  			expRow:      `[[INT64(3)]]`,
  3749  		},
  3750  		{
  3751  			sql:         `select count(*) from user`,
  3752  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("count(*)", "int64"), "3"),
  3753  			expSandboxQ: "select count(*) from `user`",
  3754  			expField:    `[name:"count(*)" type:INT64]`,
  3755  			expRow:      `[[INT64(24)]]`,
  3756  		},
  3757  		{
  3758  			sql:         `select col, count(*) from user group by col`,
  3759  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col|count(*)|weight_string(col)", "int64|int64|varbinary"), "1|3|NULL"),
  3760  			expSandboxQ: "select col, count(*), weight_string(col) from `user` group by col, weight_string(col) order by col asc",
  3761  			expField:    `[name:"col" type:INT64 name:"count(*)" type:INT64]`,
  3762  			expRow:      `[[INT64(1) INT64(24)]]`,
  3763  		},
  3764  		{
  3765  			sql:         `select col, count(*) from user group by col limit 2`,
  3766  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col|count(*)|weight_string(col)", "int64|int64|varbinary"), "1|2|NULL", "2|1|NULL", "3|4|NULL"),
  3767  			expSandboxQ: "select col, count(*), weight_string(col) from `user` group by col, weight_string(col) order by col asc limit :__upper_limit",
  3768  			expField:    `[name:"col" type:INT64 name:"count(*)" type:INT64]`,
  3769  			expRow:      `[[INT64(1) INT64(16)] [INT64(2) INT64(8)]]`,
  3770  		},
  3771  		{
  3772  			sql:         `select count(*) from (select col1, col2 from user limit 2) x`,
  3773  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2", "int64|int64"), "1|2", "2|1"),
  3774  			expSandboxQ: "select col1, col2 from `user` limit :__upper_limit",
  3775  			expField:    `[name:"count(*)" type:INT64]`,
  3776  			expRow:      `[[INT64(2)]]`,
  3777  		},
  3778  		{
  3779  			sql:         `select col2, count(*) from (select col1, col2 from user limit 9) x group by col2`,
  3780  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2|weight_string(col2)", "int64|int64|varbinary"), "3|1|NULL", "2|2|NULL"),
  3781  			expSandboxQ: "select col1, col2, weight_string(col2) from `user` order by col2 asc limit :__upper_limit",
  3782  			expField:    `[name:"col2" type:INT64 name:"count(*)" type:INT64]`,
  3783  			expRow:      `[[INT64(1) INT64(8)] [INT64(2) INT64(1)]]`,
  3784  		},
  3785  		{
  3786  			sql:         `select count(col1) from (select id, col1 from user limit 2) x`,
  3787  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("id|col1", "int64|varchar"), "3|a", "2|b"),
  3788  			expSandboxQ: "select id, col1 from `user` limit :__upper_limit",
  3789  			expField:    `[name:"count(col1)" type:INT64]`,
  3790  			expRow:      `[[INT64(2)]]`,
  3791  		},
  3792  		{
  3793  			sql:         `select count(col1), col2 from (select col2, col1 from user limit 9) x group by col2`,
  3794  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col2|col1|weight_string(col2)", "int64|varchar|varbinary"), "3|a|NULL", "2|b|NULL"),
  3795  			expSandboxQ: "select col2, col1, weight_string(col2) from `user` order by col2 asc limit :__upper_limit",
  3796  			expField:    `[name:"count(col1)" type:INT64 name:"col2" type:INT64]`,
  3797  			expRow:      `[[INT64(8) INT64(2)] [INT64(1) INT64(3)]]`,
  3798  		},
  3799  		{
  3800  			sql:         `select col1, count(col2) from (select col1, col2 from user limit 9) x group by col1`,
  3801  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2|weight_string(col1)", "varchar|int64|varbinary"), "a|1|a", "b|null|b"),
  3802  			expSandboxQ: "select col1, col2, weight_string(col1) from `user` order by col1 asc limit :__upper_limit",
  3803  			expField:    `[name:"col1" type:VARCHAR name:"count(col2)" type:INT64]`,
  3804  			expRow:      `[[VARCHAR("a") INT64(8)] [VARCHAR("b") INT64(0)]]`,
  3805  		},
  3806  		{
  3807  			sql:         `select col1, count(col2) from (select col1, col2 from user limit 32) x group by col1`,
  3808  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2|weight_string(col1)", "varchar|int64|varbinary"), "null|1|null", "null|null|null", "a|1|a", "b|null|b"),
  3809  			expSandboxQ: "select col1, col2, weight_string(col1) from `user` order by col1 asc limit :__upper_limit",
  3810  			expField:    `[name:"col1" type:VARCHAR name:"count(col2)" type:INT64]`,
  3811  			expRow:      `[[NULL INT64(8)] [VARCHAR("a") INT64(8)] [VARCHAR("b") INT64(0)]]`,
  3812  		},
  3813  		{
  3814  			sql:         `select col1, sum(col2) from (select col1, col2 from user limit 4) x group by col1`,
  3815  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2|weight_string(col1)", "varchar|int64|varbinary"), "a|3|a"),
  3816  			expSandboxQ: "select col1, col2, weight_string(col1) from `user` order by col1 asc limit :__upper_limit",
  3817  			expField:    `[name:"col1" type:VARCHAR name:"sum(col2)" type:DECIMAL]`,
  3818  			expRow:      `[[VARCHAR("a") DECIMAL(12)]]`,
  3819  		},
  3820  		{
  3821  			sql:         `select col1, sum(col2) from (select col1, col2 from user limit 4) x group by col1`,
  3822  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2|weight_string(col1)", "varchar|varchar|varbinary"), "a|2|a"),
  3823  			expSandboxQ: "select col1, col2, weight_string(col1) from `user` order by col1 asc limit :__upper_limit",
  3824  			expField:    `[name:"col1" type:VARCHAR name:"sum(col2)" type:DECIMAL]`,
  3825  			expRow:      `[[VARCHAR("a") DECIMAL(8)]]`,
  3826  		},
  3827  		{
  3828  			sql:         `select col1, sum(col2) from (select col1, col2 from user limit 4) x group by col1`,
  3829  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2|weight_string(col1)", "varchar|varchar|varbinary"), "a|x|a"),
  3830  			expSandboxQ: "select col1, col2, weight_string(col1) from `user` order by col1 asc limit :__upper_limit",
  3831  			expField:    `[name:"col1" type:VARCHAR name:"sum(col2)" type:DECIMAL]`,
  3832  			expRow:      `[[VARCHAR("a") DECIMAL(0)]]`,
  3833  		},
  3834  		{
  3835  			sql:         `select col1, sum(col2) from (select col1, col2 from user limit 4) x group by col1`,
  3836  			sandboxRes:  sqltypes.MakeTestResult(sqltypes.MakeTestFields("col1|col2|weight_string(col1)", "varchar|varchar|varbinary"), "a|null|a"),
  3837  			expSandboxQ: "select col1, col2, weight_string(col1) from `user` order by col1 asc limit :__upper_limit",
  3838  			expField:    `[name:"col1" type:VARCHAR name:"sum(col2)" type:DECIMAL]`,
  3839  			expRow:      `[[VARCHAR("a") NULL]]`,
  3840  		},
  3841  	}
  3842  
  3843  	for _, tc := range tcases {
  3844  		t.Run(tc.sql, func(t *testing.T) {
  3845  			for _, sbc := range conns {
  3846  				sbc.SetResults([]*sqltypes.Result{tc.sandboxRes})
  3847  				sbc.Queries = nil
  3848  			}
  3849  			qr, err := executorExec(executor, tc.sql, nil)
  3850  			require.NoError(t, err)
  3851  			assert.Equal(t, tc.expField, fmt.Sprintf("%v", qr.Fields))
  3852  			assert.Equal(t, tc.expRow, fmt.Sprintf("%v", qr.Rows))
  3853  			require.Len(t, conns[0].Queries, 1)
  3854  			assert.Equal(t, tc.expSandboxQ, conns[0].Queries[0].Sql)
  3855  		})
  3856  	}
  3857  }
  3858  
  3859  func TestSelectAggregationRandom(t *testing.T) {
  3860  	cell := "aa"
  3861  	hc := discovery.NewFakeHealthCheck(nil)
  3862  	createSandbox(KsTestSharded).VSchema = executorVSchema
  3863  	getSandbox(KsTestUnsharded).VSchema = unshardedVSchema
  3864  	serv := newSandboxForCells([]string{cell})
  3865  	resolver := newTestResolver(hc, serv, cell)
  3866  	shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"}
  3867  	var conns []*sandboxconn.SandboxConn
  3868  	for _, shard := range shards {
  3869  		sbc := hc.AddTestTablet(cell, shard, 1, KsTestSharded, shard, topodatapb.TabletType_PRIMARY, true, 1, nil)
  3870  		conns = append(conns, sbc)
  3871  
  3872  		sbc.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult(
  3873  			sqltypes.MakeTestFields("a|b", "int64|int64"),
  3874  			"null|null",
  3875  		)})
  3876  	}
  3877  
  3878  	conns[0].SetResults([]*sqltypes.Result{sqltypes.MakeTestResult(
  3879  		sqltypes.MakeTestFields("a|b", "int64|int64"),
  3880  		"10|1",
  3881  	)})
  3882  
  3883  	executor := createExecutor(serv, cell, resolver)
  3884  	executor.pv = querypb.ExecuteOptions_Gen4
  3885  	session := NewAutocommitSession(&vtgatepb.Session{})
  3886  
  3887  	rs, err := executor.Execute(context.Background(), "TestSelectCFC", session,
  3888  		"select /*vt+ PLANNER=gen4 */ A.a, A.b, (A.a / A.b) as c from (select sum(a) as a, sum(b) as b from user) A", nil)
  3889  	require.NoError(t, err)
  3890  	assert.Equal(t, `[[INT64(10) INT64(1) DECIMAL(10.0000)]]`, fmt.Sprintf("%v", rs.Rows))
  3891  }
  3892  
  3893  func TestSelectHexAndBit(t *testing.T) {
  3894  	executor, _, _, _ := createExecutorEnv()
  3895  	executor.normalize = true
  3896  	session := NewAutocommitSession(&vtgatepb.Session{})
  3897  
  3898  	qr, err := executor.Execute(context.Background(), "TestSelectHexAndBit", session,
  3899  		"select 0b1001, b'1001', 0x9, x'09'", nil)
  3900  	require.NoError(t, err)
  3901  	require.Equal(t, `[[VARBINARY("\t") VARBINARY("\t") VARBINARY("\t") VARBINARY("\t")]]`, fmt.Sprintf("%v", qr.Rows))
  3902  
  3903  	qr, err = executor.Execute(context.Background(), "TestSelectHexAndBit", session,
  3904  		"select 1 + 0b1001, 1 + b'1001', 1 + 0x9, 1 + x'09'", nil)
  3905  	require.NoError(t, err)
  3906  	require.Equal(t, `[[UINT64(10) UINT64(10) UINT64(10) UINT64(10)]]`, fmt.Sprintf("%v", qr.Rows))
  3907  }
  3908  
  3909  // TestSelectCFC tests validates that cfc vindex plan gets cached and same plan is getting reused.
  3910  // This also validates that cache_size is able to calculate the cfc vindex plan size.
  3911  func TestSelectCFC(t *testing.T) {
  3912  	executor, _, _, _ := createExecutorEnv()
  3913  	executor.normalize = true
  3914  	session := NewAutocommitSession(&vtgatepb.Session{})
  3915  
  3916  	_, err := executor.Execute(context.Background(), "TestSelectCFC", session,
  3917  		"select /*vt+ PLANNER=gen4 */ c2 from tbl_cfc where c1 like 'A%'", nil)
  3918  	require.NoError(t, err)
  3919  
  3920  	timeout := time.After(10 * time.Second)
  3921  	for {
  3922  		select {
  3923  		case <-timeout:
  3924  			t.Fatal("not able to cache a plan withing 10 seconds.")
  3925  		case <-time.After(5 * time.Millisecond):
  3926  			// should be able to find cache entry before the timeout.
  3927  			cacheItems := executor.debugCacheEntries()
  3928  			for _, item := range cacheItems {
  3929  				if strings.Contains(item.Key, "c2 from tbl_cfc where c1 like") {
  3930  					return
  3931  				}
  3932  			}
  3933  		}
  3934  	}
  3935  }
  3936  
  3937  func TestSelectView(t *testing.T) {
  3938  	executor, sbc, _, _ := createExecutorEnv()
  3939  	// add the view to local vschema
  3940  	err := executor.vschema.AddView(KsTestSharded, "user_details_view", "select user.id, user_extra.col from user join user_extra on user.id = user_extra.user_id")
  3941  	require.NoError(t, err)
  3942  
  3943  	executor.normalize = true
  3944  	session := NewAutocommitSession(&vtgatepb.Session{})
  3945  
  3946  	_, err = executor.Execute(context.Background(), "TestSelectView", session,
  3947  		"select * from user_details_view", nil)
  3948  	require.NoError(t, err)
  3949  	wantQueries := []*querypb.BoundQuery{{
  3950  		Sql:           "select * from (select `user`.id, user_extra.col from `user` join user_extra on `user`.id = user_extra.user_id) as user_details_view",
  3951  		BindVariables: map[string]*querypb.BindVariable{},
  3952  	}}
  3953  	utils.MustMatch(t, wantQueries, sbc.Queries)
  3954  
  3955  	sbc.Queries = nil
  3956  	_, err = executor.Execute(context.Background(), "TestSelectView", session,
  3957  		"select * from user_details_view where id = 2", nil)
  3958  	require.NoError(t, err)
  3959  	wantQueries = []*querypb.BoundQuery{{
  3960  		Sql: "select * from (select `user`.id, user_extra.col from `user` join user_extra on `user`.id = user_extra.user_id) as user_details_view where id = :id",
  3961  		BindVariables: map[string]*querypb.BindVariable{
  3962  			"id": sqltypes.Int64BindVariable(2),
  3963  		},
  3964  	}}
  3965  	utils.MustMatch(t, wantQueries, sbc.Queries)
  3966  
  3967  	sbc.Queries = nil
  3968  	_, err = executor.Execute(context.Background(), "TestSelectView", session,
  3969  		"select * from user_details_view where id in (1,2,3,4,5)", nil)
  3970  	require.NoError(t, err)
  3971  	bvtg1, _ := sqltypes.BuildBindVariable([]int64{1, 2, 3, 4, 5})
  3972  	bvals, _ := sqltypes.BuildBindVariable([]int64{1, 2})
  3973  	wantQueries = []*querypb.BoundQuery{{
  3974  		Sql: "select * from (select `user`.id, user_extra.col from `user` join user_extra on `user`.id = user_extra.user_id) as user_details_view where id in ::__vals",
  3975  		BindVariables: map[string]*querypb.BindVariable{
  3976  			"vtg1":   bvtg1,
  3977  			"__vals": bvals,
  3978  		},
  3979  	}}
  3980  	utils.MustMatch(t, wantQueries, sbc.Queries)
  3981  }
  3982  
  3983  func TestMain(m *testing.M) {
  3984  	_flag.ParseFlagsForTest()
  3985  	os.Exit(m.Run())
  3986  }