vitess.io/vitess@v0.16.2/go/vt/vttablet/endtoend/settings_test.go (about)

     1  /*
     2  Copyright 2022 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 endtoend
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	"github.com/stretchr/testify/assert"
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"vitess.io/vitess/go/vt/vttablet/endtoend/framework"
    27  )
    28  
    29  func TestSelectNoConnectionReservationOnSettings(t *testing.T) {
    30  	framework.Server.Config().EnableSettingsPool = true
    31  	defer func() {
    32  		framework.Server.Config().EnableSettingsPool = false
    33  	}()
    34  
    35  	client := framework.NewClient()
    36  	defer client.Release()
    37  
    38  	query := "select @@sql_mode"
    39  	setting := "set @@sql_mode = ''"
    40  
    41  	for _, withTx := range []bool{false, true} {
    42  		if withTx {
    43  			err := client.Begin(false)
    44  			require.NoError(t, err)
    45  		}
    46  
    47  		qr, err := client.ReserveExecute(query, []string{setting}, nil)
    48  		require.NoError(t, err)
    49  		assert.Zero(t, client.ReservedID())
    50  		assert.Equal(t, `[[VARCHAR("")]]`, fmt.Sprintf("%v", qr.Rows))
    51  
    52  		qr, err = client.ReserveStreamExecute(query, []string{setting}, nil)
    53  		require.NoError(t, err)
    54  		assert.Zero(t, client.ReservedID())
    55  		assert.Equal(t, `[[VARCHAR("")]]`, fmt.Sprintf("%v", qr.Rows))
    56  	}
    57  }
    58  
    59  func TestSetttingsReuseConnWithSettings(t *testing.T) {
    60  	framework.Server.Config().EnableSettingsPool = true
    61  	defer func() {
    62  		framework.Server.Config().EnableSettingsPool = false
    63  	}()
    64  
    65  	resetTxConnPool(t)
    66  
    67  	client := framework.NewClient()
    68  	defer client.Release()
    69  
    70  	connectionIDQuery := "select connection_id()"
    71  	setting := "set @@sql_mode = ''"
    72  
    73  	// Create a connection
    74  	connectionIDRes, err := client.BeginExecute(connectionIDQuery, nil, nil)
    75  	require.NoError(t, err)
    76  
    77  	// Add settings to the connection
    78  	res, err := client.ReserveExecute(connectionIDQuery, []string{setting}, nil)
    79  	require.NoError(t, err)
    80  	require.Equal(t, connectionIDRes, res)
    81  
    82  	// Release the connection back
    83  	err = client.Rollback()
    84  	require.NoError(t, err)
    85  
    86  	// We iterate in a loop and try to get a connection with the same settings as before
    87  	// but only 1 at a time. So we expect the same connection to be reused everytime.
    88  	for i := 0; i < 100; i++ {
    89  		res, err = client.ReserveBeginExecute(connectionIDQuery, []string{setting}, nil, nil)
    90  		require.NoError(t, err)
    91  		require.True(t, connectionIDRes.Equal(res))
    92  		err = client.Rollback()
    93  		require.NoError(t, err)
    94  	}
    95  
    96  	// Create a new client
    97  	client2 := framework.NewClient()
    98  	defer client2.Release()
    99  	// Ask for a connection with the same settings. This too should be reused.
   100  	res, err = client.ReserveBeginExecute(connectionIDQuery, []string{setting}, nil, nil)
   101  	require.NoError(t, err)
   102  	require.True(t, connectionIDRes.Equal(res))
   103  
   104  	// Ask for a connection with the same settings, but the previous connection hasn't been released yet. So this will be a new connection.
   105  	connectionIDRes2, err := client2.ReserveBeginExecute(connectionIDQuery, []string{setting}, nil, nil)
   106  	require.NoError(t, err)
   107  	require.False(t, connectionIDRes.Equal(connectionIDRes2))
   108  
   109  	// Release both the connections
   110  	err = client.Rollback()
   111  	require.NoError(t, err)
   112  	err = client2.Rollback()
   113  	require.NoError(t, err)
   114  
   115  	// We iterate in a loop and try to get a connection with the same settings as before
   116  	// but only 1 at a time. So we expect the two connections to be reused, and we should be seeing both of them.
   117  	reusedConnection1 := false
   118  	reusedConnection2 := false
   119  	for i := 0; i < 100; i++ {
   120  		res, err = client.ReserveBeginExecute(connectionIDQuery, []string{setting}, nil, nil)
   121  		require.NoError(t, err)
   122  		if connectionIDRes.Equal(res) {
   123  			reusedConnection1 = true
   124  		} else if connectionIDRes2.Equal(res) {
   125  			reusedConnection2 = true
   126  		} else {
   127  			t.Fatalf("The connection should be either of the already created connections")
   128  		}
   129  
   130  		err = client.Rollback()
   131  		require.NoError(t, err)
   132  		if reusedConnection2 && reusedConnection1 {
   133  			break
   134  		}
   135  	}
   136  	require.True(t, reusedConnection1)
   137  	require.True(t, reusedConnection2)
   138  }
   139  
   140  // resetTxConnPool resets the settings pool by fetching all the connections from the pool with no settings.
   141  // this will make sure that the settings pool connections if any will be taken and settings are reset.
   142  func resetTxConnPool(t *testing.T) {
   143  	txPoolSize := framework.Server.Config().TxPool.Size
   144  	clients := make([]*framework.QueryClient, txPoolSize)
   145  	for i := 0; i < txPoolSize; i++ {
   146  		client := framework.NewClient()
   147  		_, err := client.BeginExecute("select 1", nil, nil)
   148  		require.NoError(t, err)
   149  		clients[i] = client
   150  	}
   151  	for _, client := range clients {
   152  		require.NoError(t,
   153  			client.Release())
   154  	}
   155  }
   156  
   157  func TestDDLNoConnectionReservationOnSettings(t *testing.T) {
   158  	framework.Server.Config().EnableSettingsPool = true
   159  	defer func() {
   160  		framework.Server.Config().EnableSettingsPool = false
   161  	}()
   162  
   163  	client := framework.NewClient()
   164  	defer client.Release()
   165  
   166  	query := "create table temp(c_date datetime default '0000-00-00')"
   167  	setting := "set sql_mode='TRADITIONAL'"
   168  
   169  	for _, withTx := range []bool{false, true} {
   170  		if withTx {
   171  			err := client.Begin(false)
   172  			require.NoError(t, err)
   173  		}
   174  		_, err := client.ReserveExecute(query, []string{setting}, nil)
   175  		require.Error(t, err, "create table should have failed with TRADITIONAL mode")
   176  		require.Contains(t, err.Error(), "Invalid default value")
   177  		assert.Zero(t, client.ReservedID())
   178  	}
   179  }
   180  
   181  func TestDMLNoConnectionReservationOnSettings(t *testing.T) {
   182  	framework.Server.Config().EnableSettingsPool = true
   183  	defer func() {
   184  		framework.Server.Config().EnableSettingsPool = false
   185  	}()
   186  
   187  	client := framework.NewClient()
   188  	defer client.Release()
   189  
   190  	_, err := client.Execute("create table temp(c_date datetime)", nil)
   191  	require.NoError(t, err)
   192  	defer client.Execute("drop table temp", nil)
   193  
   194  	_, err = client.Execute("insert into temp values ('2022-08-25')", nil)
   195  	require.NoError(t, err)
   196  
   197  	setting := "set sql_mode='TRADITIONAL'"
   198  	queries := []string{
   199  		"insert into temp values('0000-00-00')",
   200  		"update temp set c_date = '0000-00-00'",
   201  	}
   202  
   203  	for _, withTx := range []bool{false, true} {
   204  		if withTx {
   205  			err := client.Begin(false)
   206  			require.NoError(t, err)
   207  		}
   208  		for _, query := range queries {
   209  			t.Run(query, func(t *testing.T) {
   210  				_, err = client.ReserveExecute(query, []string{setting}, nil)
   211  				require.Error(t, err, "query should have failed with TRADITIONAL mode")
   212  				require.Contains(t, err.Error(), "Incorrect datetime value")
   213  				assert.Zero(t, client.ReservedID())
   214  			})
   215  		}
   216  	}
   217  }
   218  
   219  func TestSelectNoConnectionReservationOnSettingsWithTx(t *testing.T) {
   220  	framework.Server.Config().EnableSettingsPool = true
   221  	defer func() {
   222  		framework.Server.Config().EnableSettingsPool = false
   223  	}()
   224  
   225  	client := framework.NewClient()
   226  
   227  	query := "select @@sql_mode"
   228  	setting := "set @@sql_mode = ''"
   229  
   230  	qr, err := client.ReserveBeginExecute(query, []string{setting}, nil, nil)
   231  	require.NoError(t, err)
   232  	assert.Zero(t, client.ReservedID())
   233  	assert.Equal(t, `[[VARCHAR("")]]`, fmt.Sprintf("%v", qr.Rows))
   234  	require.NoError(t,
   235  		client.Release())
   236  
   237  	qr, err = client.ReserveBeginStreamExecute(query, []string{setting}, nil, nil)
   238  	require.NoError(t, err)
   239  	assert.Zero(t, client.ReservedID())
   240  	assert.Equal(t, `[[VARCHAR("")]]`, fmt.Sprintf("%v", qr.Rows))
   241  	require.NoError(t,
   242  		client.Release())
   243  }
   244  
   245  func TestDDLNoConnectionReservationOnSettingsWithTx(t *testing.T) {
   246  	framework.Server.Config().EnableSettingsPool = true
   247  	defer func() {
   248  		framework.Server.Config().EnableSettingsPool = false
   249  	}()
   250  
   251  	client := framework.NewClient()
   252  	defer client.Release()
   253  
   254  	query := "create table temp(c_date datetime default '0000-00-00')"
   255  	setting := "set sql_mode='TRADITIONAL'"
   256  
   257  	_, err := client.ReserveBeginExecute(query, []string{setting}, nil, nil)
   258  	require.Error(t, err, "create table should have failed with TRADITIONAL mode")
   259  	require.Contains(t, err.Error(), "Invalid default value")
   260  	assert.Zero(t, client.ReservedID())
   261  }
   262  
   263  func TestDMLNoConnectionReservationOnSettingsWithTx(t *testing.T) {
   264  	framework.Server.Config().EnableSettingsPool = true
   265  	defer func() {
   266  		framework.Server.Config().EnableSettingsPool = false
   267  	}()
   268  
   269  	client := framework.NewClient()
   270  
   271  	_, err := client.Execute("create table temp(c_date datetime)", nil)
   272  	require.NoError(t, err)
   273  	defer client.Execute("drop table temp", nil)
   274  
   275  	_, err = client.Execute("insert into temp values ('2022-08-25')", nil)
   276  	require.NoError(t, err)
   277  
   278  	setting := "set sql_mode='TRADITIONAL'"
   279  	queries := []string{
   280  		"insert into temp values('0000-00-00')",
   281  		"update temp set c_date = '0000-00-00'",
   282  	}
   283  
   284  	for _, query := range queries {
   285  		t.Run(query, func(t *testing.T) {
   286  			_, err = client.ReserveBeginExecute(query, []string{setting}, nil, nil)
   287  			require.Error(t, err, "query should have failed with TRADITIONAL mode")
   288  			require.Contains(t, err.Error(), "Incorrect datetime value")
   289  			assert.Zero(t, client.ReservedID())
   290  			require.NoError(t,
   291  				client.Release())
   292  		})
   293  	}
   294  }
   295  
   296  func TestSetQueryOnReserveApis(t *testing.T) {
   297  	framework.Server.Config().EnableSettingsPool = true
   298  	defer func() {
   299  		framework.Server.Config().EnableSettingsPool = false
   300  	}()
   301  
   302  	client := framework.NewClient()
   303  	defer client.Release()
   304  
   305  	setting := "set @@sql_mode = ''"
   306  
   307  	_, err := client.ReserveExecute(setting, []string{setting}, nil)
   308  	require.NoError(t, err)
   309  	assert.Zero(t, client.ReservedID())
   310  
   311  	_, err = client.ReserveBeginExecute(setting, []string{setting}, nil, nil)
   312  	require.NoError(t, err)
   313  	assert.Zero(t, client.ReservedID())
   314  }
   315  
   316  func TestGetLockQueryOnReserveExecute(t *testing.T) {
   317  	framework.Server.Config().EnableSettingsPool = true
   318  	defer func() {
   319  		framework.Server.Config().EnableSettingsPool = false
   320  	}()
   321  
   322  	client := framework.NewClient()
   323  	defer client.Release()
   324  
   325  	lockQuery := "select get_lock('test', 1)"
   326  
   327  	// without settings
   328  	_, err := client.ReserveExecute(lockQuery, nil, nil)
   329  	require.NoError(t, err)
   330  	assert.NotZero(t, client.ReservedID())
   331  	require.NoError(t,
   332  		client.Release())
   333  
   334  	// with settings
   335  	_, err = client.ReserveExecute(lockQuery, []string{"set @@sql_mode = ''"}, nil)
   336  	require.NoError(t, err)
   337  	assert.NotZero(t, client.ReservedID())
   338  	require.NoError(t,
   339  		client.Release())
   340  }
   341  
   342  func TestTempTableOnReserveExecute(t *testing.T) {
   343  	framework.Server.Config().EnableSettingsPool = true
   344  	defer func() {
   345  		framework.Server.Config().EnableSettingsPool = false
   346  	}()
   347  
   348  	client := framework.NewClient()
   349  	defer client.Release()
   350  	defer client.Execute("drop table if exists temp", nil)
   351  
   352  	tempTblQuery := "create temporary table if not exists temp(id bigint primary key)"
   353  
   354  	_, err := client.Execute(tempTblQuery, nil)
   355  	require.Error(t, err)
   356  
   357  	_, err = client.ReserveExecute(tempTblQuery, nil, nil)
   358  	require.NoError(t, err)
   359  	assert.NotZero(t, client.ReservedID())
   360  	require.NoError(t,
   361  		client.Release())
   362  
   363  	_, err = client.ReserveBeginExecute(tempTblQuery, nil, nil, nil)
   364  	require.NoError(t, err)
   365  	assert.NotZero(t, client.ReservedID())
   366  	require.NoError(t,
   367  		client.Release())
   368  
   369  	// drop the table
   370  	_, err = client.Execute("drop table if exists temp", nil)
   371  	require.NoError(t, err)
   372  
   373  	// with settings
   374  
   375  	tempTblQuery = "create temporary table if not exists temp(c_date datetime default '0000-00-00')"
   376  	setting := "set sql_mode='TRADITIONAL'"
   377  
   378  	_, err = client.ReserveExecute(tempTblQuery, []string{setting}, nil)
   379  	require.Error(t, err, "create table should have failed with TRADITIONAL mode")
   380  	require.Contains(t, err.Error(), "Invalid default value")
   381  	assert.NotZero(t, client.ReservedID(), "as this goes through fallback path of reserving a connection due to temporary tables")
   382  	require.NoError(t,
   383  		client.Release())
   384  
   385  	_, err = client.ReserveBeginExecute(tempTblQuery, []string{setting}, nil, nil)
   386  	require.Error(t, err, "create table should have failed with TRADITIONAL mode")
   387  	require.Contains(t, err.Error(), "Invalid default value")
   388  	assert.NotZero(t, client.ReservedID(), "as this goes through fallback path of reserving a connection due to temporary tables")
   389  	require.NoError(t,
   390  		client.Release())
   391  }
   392  
   393  func TestInfiniteSessions(t *testing.T) {
   394  	framework.Server.Config().EnableSettingsPool = true
   395  	defer func() {
   396  		framework.Server.Config().EnableSettingsPool = false
   397  	}()
   398  
   399  	client := framework.NewClient()
   400  	qr, err := client.Execute("select @@max_connections", nil)
   401  	require.NoError(t, err)
   402  	maxConn, err := qr.Rows[0][0].ToInt64()
   403  	require.NoError(t, err)
   404  
   405  	// twice the number of sessions than the pool size.
   406  	numOfSessions := int(maxConn * 2)
   407  
   408  	// read session
   409  	for i := 0; i < numOfSessions; i++ {
   410  		client := framework.NewClient()
   411  		_, err := client.ReserveExecute("select 1", []string{"set sql_mode = ''"}, nil)
   412  		require.NoError(t, err)
   413  	}
   414  
   415  	// write session
   416  	for i := 0; i < numOfSessions; i++ {
   417  		client := framework.NewClient()
   418  		_, err := client.ReserveBeginExecute("select 1", []string{"set sql_mode = ''"}, nil, nil)
   419  		require.NoError(t, err)
   420  		require.NoError(t,
   421  			client.Commit())
   422  	}
   423  }
   424  
   425  func TestSetQueriesMultipleWays(t *testing.T) {
   426  	client := framework.NewClient()
   427  	defer client.Release()
   428  	_, err := client.ReserveExecute("select 1", []string{"set sql_safe_updates = 1"}, nil)
   429  	require.NoError(t, err)
   430  
   431  	_, err = client.Execute("set sql_safe_updates = 1", nil)
   432  	require.NoError(t, err)
   433  
   434  	framework.Server.Config().EnableSettingsPool = true
   435  	defer func() {
   436  		framework.Server.Config().EnableSettingsPool = false
   437  	}()
   438  
   439  	client2 := framework.NewClient()
   440  	_, err = client2.ReserveExecute("select 1", []string{"set sql_safe_updates = 1"}, nil)
   441  	require.NoError(t, err)
   442  
   443  	// this should not panic.
   444  	_, err = client.Execute("set sql_safe_updates = 1", nil)
   445  	require.NoError(t, err)
   446  }