vitess.io/vitess@v0.16.2/go/vt/vtgate/mysql_protocol_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  	"net"
    21  	"strconv"
    22  	"testing"
    23  
    24  	"vitess.io/vitess/go/test/utils"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  	"github.com/stretchr/testify/require"
    28  
    29  	"context"
    30  
    31  	"google.golang.org/protobuf/proto"
    32  
    33  	"vitess.io/vitess/go/mysql"
    34  	"vitess.io/vitess/go/vt/vttablet/sandboxconn"
    35  
    36  	querypb "vitess.io/vitess/go/vt/proto/query"
    37  	topodatapb "vitess.io/vitess/go/vt/proto/topodata"
    38  )
    39  
    40  func TestMySQLProtocolExecute(t *testing.T) {
    41  	createSandbox(KsTestUnsharded)
    42  	hcVTGateTest.Reset()
    43  	sbc := hcVTGateTest.AddTestTablet("aa", "1.1.1.1", 1001, KsTestUnsharded, "0", topodatapb.TabletType_PRIMARY, true, 1, nil)
    44  
    45  	c, err := mysqlConnect(&mysql.ConnParams{})
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	defer c.Close()
    50  
    51  	qr, err := c.ExecuteFetch("select id from t1", 10, true /* wantfields */)
    52  	require.NoError(t, err)
    53  	utils.MustMatch(t, sandboxconn.SingleRowResult, qr, "mismatch in rows")
    54  
    55  	options := &querypb.ExecuteOptions{
    56  		IncludedFields: querypb.ExecuteOptions_ALL,
    57  		Workload:       querypb.ExecuteOptions_OLTP,
    58  	}
    59  	if !proto.Equal(sbc.Options[0], options) {
    60  		t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc.Options[0], options)
    61  	}
    62  }
    63  
    64  func TestMySQLProtocolStreamExecute(t *testing.T) {
    65  	createSandbox(KsTestUnsharded)
    66  	hcVTGateTest.Reset()
    67  	sbc := hcVTGateTest.AddTestTablet("aa", "1.1.1.1", 1001, KsTestUnsharded, "0", topodatapb.TabletType_PRIMARY, true, 1, nil)
    68  
    69  	c, err := mysqlConnect(&mysql.ConnParams{})
    70  	if err != nil {
    71  		t.Fatal(err)
    72  	}
    73  	defer c.Close()
    74  
    75  	_, err = c.ExecuteFetch("set workload='olap'", 1, true /* wantfields */)
    76  	require.NoError(t, err)
    77  
    78  	qr, err := c.ExecuteFetch("select id from t1", 10, true /* wantfields */)
    79  	require.NoError(t, err)
    80  	utils.MustMatch(t, sandboxconn.SingleRowResult, qr, "mismatch in rows")
    81  
    82  	options := &querypb.ExecuteOptions{
    83  		IncludedFields: querypb.ExecuteOptions_ALL,
    84  		Workload:       querypb.ExecuteOptions_OLAP,
    85  	}
    86  	if !proto.Equal(sbc.Options[0], options) {
    87  		t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc.Options[0], options)
    88  	}
    89  }
    90  
    91  func TestMySQLProtocolExecuteUseStatement(t *testing.T) {
    92  	createSandbox(KsTestUnsharded)
    93  	hcVTGateTest.Reset()
    94  	hcVTGateTest.AddTestTablet("aa", "1.1.1.1", 1001, KsTestUnsharded, "0", topodatapb.TabletType_PRIMARY, true, 1, nil)
    95  
    96  	c, err := mysqlConnect(&mysql.ConnParams{DbName: "@primary"})
    97  	if err != nil {
    98  		t.Fatal(err)
    99  	}
   100  	defer c.Close()
   101  
   102  	qr, err := c.ExecuteFetch("select id from t1", 10, true /* wantfields */)
   103  	require.NoError(t, err)
   104  	utils.MustMatch(t, sandboxconn.SingleRowResult, qr)
   105  
   106  	qr, err = c.ExecuteFetch("show vitess_target", 1, false)
   107  	require.NoError(t, err)
   108  	assert.Equal(t, "VARCHAR(\"@primary\")", qr.Rows[0][0].String())
   109  
   110  	_, err = c.ExecuteFetch("use TestUnsharded", 0, false)
   111  	require.NoError(t, err)
   112  
   113  	qr, err = c.ExecuteFetch("select id from t1", 10, true /* wantfields */)
   114  	require.NoError(t, err)
   115  	utils.MustMatch(t, sandboxconn.SingleRowResult, qr)
   116  
   117  	// No such keyspace this will fail
   118  	_, err = c.ExecuteFetch("use InvalidKeyspace", 0, false)
   119  	require.Error(t, err)
   120  	assert.Contains(t, err.Error(), "VT05003: unknown database 'InvalidKeyspace' in vschema (errno 1049) (sqlstate 42000)")
   121  
   122  	// That doesn't reset the vitess_target
   123  	qr, err = c.ExecuteFetch("show vitess_target", 1, false)
   124  	require.NoError(t, err)
   125  	assert.Equal(t, "VARCHAR(\"TestUnsharded\")", qr.Rows[0][0].String())
   126  
   127  	_, err = c.ExecuteFetch("use @replica", 0, false)
   128  	require.NoError(t, err)
   129  
   130  	// No replica tablets, this should also fail
   131  	_, err = c.ExecuteFetch("select id from t1", 10, true /* wantfields */)
   132  	require.Error(t, err)
   133  	assert.Contains(t, err.Error(), `no healthy tablet available for 'keyspace:"TestUnsharded" shard:"0" tablet_type:REPLICA`)
   134  }
   135  
   136  func TestMysqlProtocolInvalidDB(t *testing.T) {
   137  	_, err := mysqlConnect(&mysql.ConnParams{DbName: "invalidDB"})
   138  	require.EqualError(t, err, "VT05003: unknown database 'invalidDB' in vschema (errno 1049) (sqlstate 42000)")
   139  }
   140  
   141  func TestMySQLProtocolClientFoundRows(t *testing.T) {
   142  	createSandbox(KsTestUnsharded)
   143  	hcVTGateTest.Reset()
   144  	sbc := hcVTGateTest.AddTestTablet("aa", "1.1.1.1", 1001, KsTestUnsharded, "0", topodatapb.TabletType_PRIMARY, true, 1, nil)
   145  
   146  	c, err := mysqlConnect(&mysql.ConnParams{Flags: mysql.CapabilityClientFoundRows})
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  	defer c.Close()
   151  
   152  	qr, err := c.ExecuteFetch("select id from t1", 10, true /* wantfields */)
   153  	require.NoError(t, err)
   154  	utils.MustMatch(t, sandboxconn.SingleRowResult, qr)
   155  
   156  	options := &querypb.ExecuteOptions{
   157  		IncludedFields:  querypb.ExecuteOptions_ALL,
   158  		ClientFoundRows: true,
   159  		Workload:        querypb.ExecuteOptions_OLTP,
   160  	}
   161  
   162  	if !proto.Equal(sbc.Options[0], options) {
   163  		t.Errorf("got ExecuteOptions \n%+v, want \n%+v", sbc.Options[0], options)
   164  	}
   165  }
   166  
   167  // mysqlConnect fills the host & port into params and connects
   168  // to the mysql protocol port.
   169  func mysqlConnect(params *mysql.ConnParams) (*mysql.Conn, error) {
   170  	host, port, err := net.SplitHostPort(mysqlListener.Addr().String())
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	portnum, _ := strconv.Atoi(port)
   175  	params.Host = host
   176  	params.Port = portnum
   177  	return mysql.Connect(context.Background(), params)
   178  }