vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/queries/informationschema/informationschema_test.go (about)

     1  /*
     2  Copyright 2021 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 informationschema
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"testing"
    23  
    24  	"vitess.io/vitess/go/test/endtoend/utils"
    25  
    26  	"github.com/stretchr/testify/assert"
    27  
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"vitess.io/vitess/go/mysql"
    31  	"vitess.io/vitess/go/test/endtoend/cluster"
    32  )
    33  
    34  func start(t *testing.T) (utils.MySQLCompare, func()) {
    35  	mcmp, err := utils.NewMySQLCompare(t, vtParams, mysqlParams)
    36  	require.NoError(t, err)
    37  
    38  	deleteAll := func() {
    39  		_, _ = utils.ExecAllowError(t, mcmp.VtConn, "set workload = oltp")
    40  
    41  		tables := []string{"t1", "t1_id2_idx", "t7_xxhash", "t7_xxhash_idx", "t7_fk"}
    42  		for _, table := range tables {
    43  			_, _ = mcmp.ExecAndIgnore("delete from " + table)
    44  		}
    45  	}
    46  
    47  	deleteAll()
    48  
    49  	return mcmp, func() {
    50  		deleteAll()
    51  		mcmp.Close()
    52  		cluster.PanicHandler(t)
    53  	}
    54  }
    55  
    56  func TestDbNameOverride(t *testing.T) {
    57  	if clusterInstance.HasPartialKeyspaces {
    58  		t.Skip("test can randomly select one of the shards, and the shards are in different keyspaces")
    59  	}
    60  	mcmp, closer := start(t)
    61  	defer closer()
    62  
    63  	qr, err := mcmp.VtConn.ExecuteFetch("SELECT distinct database() FROM information_schema.tables WHERE table_schema = database()", 1000, true)
    64  
    65  	require.Nil(t, err)
    66  	assert.Equal(t, 1, len(qr.Rows), "did not get enough rows back")
    67  	assert.Equal(t, "vt_ks", qr.Rows[0][0].ToString())
    68  }
    69  
    70  func TestInformationSchemaQuery(t *testing.T) {
    71  	if clusterInstance.HasPartialKeyspaces {
    72  		t.Skip("test can randomly select one of the shards, and the shards are in different keyspaces")
    73  	}
    74  	mcmp, closer := start(t)
    75  	defer closer()
    76  
    77  	utils.AssertSingleRowIsReturned(t, mcmp.VtConn, "table_schema = 'ks'", "vt_ks")
    78  	utils.AssertSingleRowIsReturned(t, mcmp.VtConn, "table_schema = 'vt_ks'", "vt_ks")
    79  	utils.AssertResultIsEmpty(t, mcmp.VtConn, "table_schema = 'NONE'")
    80  	utils.AssertSingleRowIsReturned(t, mcmp.VtConn, "table_schema = 'performance_schema'", "performance_schema")
    81  	utils.AssertResultIsEmpty(t, mcmp.VtConn, "table_schema = 'PERFORMANCE_SCHEMA'")
    82  	utils.AssertSingleRowIsReturned(t, mcmp.VtConn, "table_schema = 'performance_schema' and table_name = 'users'", "performance_schema")
    83  	utils.AssertResultIsEmpty(t, mcmp.VtConn, "table_schema = 'performance_schema' and table_name = 'foo'")
    84  	utils.AssertSingleRowIsReturned(t, mcmp.VtConn, "table_schema = 'vt_ks' and table_name = 't1'", "vt_ks")
    85  	utils.AssertSingleRowIsReturned(t, mcmp.VtConn, "table_schema = 'ks' and table_name = 't1'", "vt_ks")
    86  }
    87  
    88  func TestInformationSchemaWithSubquery(t *testing.T) {
    89  	mcmp, closer := start(t)
    90  	defer closer()
    91  
    92  	mcmp.AssertIsEmpty("SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA()) AND TABLE_NAME = 'not_exists'")
    93  }
    94  
    95  func TestInformationSchemaQueryGetsRoutedToTheRightTableAndKeyspace(t *testing.T) {
    96  	t.Skip("flaky. skipping for now")
    97  	mcmp, closer := start(t)
    98  	defer closer()
    99  
   100  	utils.Exec(t, mcmp.VtConn, "insert into t1(id1, id2) values (1, 1), (2, 2), (3,3), (4,4)")
   101  
   102  	_ = utils.Exec(t, mcmp.VtConn, "SELECT /*vt+ PLANNER=gen4 */ * FROM t1000") // test that the routed table is available to us
   103  	result := utils.Exec(t, mcmp.VtConn, "SELECT /*vt+ PLANNER=gen4 */ * FROM information_schema.tables WHERE table_schema = database() and table_name='t1000'")
   104  	assert.NotEmpty(t, result.Rows)
   105  }
   106  
   107  func TestFKConstraintUsingInformationSchema(t *testing.T) {
   108  	mcmp, closer := start(t)
   109  	defer closer()
   110  
   111  	query := "select  fk.referenced_table_name as to_table, fk.referenced_column_name as primary_key, fk.column_name as `column`, fk.constraint_name as name, rc.update_rule as on_update, rc.delete_rule as on_delete from information_schema.referential_constraints as rc join information_schema.key_column_usage as fk on fk.constraint_schema = rc.constraint_schema and fk.constraint_name = rc.constraint_name where fk.referenced_column_name is not null and fk.table_schema = database() and fk.table_name = 't7_fk' and rc.constraint_schema = database() and rc.table_name = 't7_fk'"
   112  	mcmp.AssertMatchesAny(query,
   113  		`[[VARBINARY("t7_xxhash") VARCHAR("uid") VARCHAR("t7_uid") VARCHAR("t7_fk_ibfk_1") BINARY("CASCADE") BINARY("SET NULL")]]`,
   114  		`[[VARCHAR("t7_xxhash") VARCHAR("uid") VARCHAR("t7_uid") VARCHAR("t7_fk_ibfk_1") VARCHAR("CASCADE") VARCHAR("SET NULL")]]`)
   115  }
   116  
   117  func TestConnectWithSystemSchema(t *testing.T) {
   118  	defer cluster.PanicHandler(t)
   119  	for _, dbname := range []string{"information_schema", "mysql", "performance_schema", "sys"} {
   120  		vtConnParams := vtParams
   121  		vtConnParams.DbName = dbname
   122  		mysqlConnParams := mysqlParams
   123  		mysqlConnParams.DbName = dbname
   124  
   125  		mcmp, err := utils.NewMySQLCompare(t, vtConnParams, mysqlConnParams)
   126  		require.NoError(t, err)
   127  		defer func() {
   128  			mcmp.Close()
   129  		}()
   130  
   131  		mcmp.Exec(`select @@max_allowed_packet from dual`)
   132  	}
   133  }
   134  
   135  func TestUseSystemSchema(t *testing.T) {
   136  	mcmp, closer := start(t)
   137  	defer closer()
   138  
   139  	for _, dbname := range []string{"information_schema", "mysql", "performance_schema", "sys"} {
   140  		mcmp.Exec(fmt.Sprintf("use %s", dbname))
   141  		mcmp.Exec(`select @@max_allowed_packet from dual`)
   142  	}
   143  }
   144  
   145  func TestSystemSchemaQueryWithoutQualifier(t *testing.T) {
   146  	if clusterInstance.HasPartialKeyspaces {
   147  		t.Skip("partial keyspace detected, skipping test")
   148  	}
   149  	mcmp, closer := start(t)
   150  	defer closer()
   151  
   152  	queryWithQualifier := fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+
   153  		"from information_schema.tables t "+
   154  		"join information_schema.columns c "+
   155  		"on c.table_schema = t.table_schema and c.table_name = t.table_name "+
   156  		"where t.table_schema = '%s' and c.table_schema = '%s' "+
   157  		"order by t.table_schema,t.table_name,c.column_name", keyspaceName, keyspaceName)
   158  	qr1 := utils.Exec(t, mcmp.VtConn, queryWithQualifier)
   159  
   160  	utils.Exec(t, mcmp.VtConn, "use information_schema")
   161  	queryWithoutQualifier := fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+
   162  		"from tables t "+
   163  		"join columns c "+
   164  		"on c.table_schema = t.table_schema and c.table_name = t.table_name "+
   165  		"where t.table_schema = '%s' and c.table_schema = '%s' "+
   166  		"order by t.table_schema,t.table_name,c.column_name", keyspaceName, keyspaceName)
   167  	qr2 := utils.Exec(t, mcmp.VtConn, queryWithoutQualifier)
   168  	require.Equal(t, qr1, qr2)
   169  
   170  	ctx := context.Background()
   171  	connParams := vtParams
   172  	connParams.DbName = "information_schema"
   173  	conn2, err := mysql.Connect(ctx, &connParams)
   174  	require.NoError(t, err)
   175  	defer conn2.Close()
   176  
   177  	qr3 := utils.Exec(t, conn2, queryWithoutQualifier)
   178  	require.Equal(t, qr2, qr3)
   179  }
   180  
   181  func TestMultipleSchemaPredicates(t *testing.T) {
   182  	if clusterInstance.HasPartialKeyspaces {
   183  		t.Skip("test can randomly select one of the shards, and the shards are in different keyspaces")
   184  	}
   185  	mcmp, closer := start(t)
   186  	defer closer()
   187  
   188  	query := fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+
   189  		"from information_schema.tables t "+
   190  		"join information_schema.columns c "+
   191  		"on c.table_schema = t.table_schema and c.table_name = t.table_name "+
   192  		"where t.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s'", keyspaceName, keyspaceName, keyspaceName, keyspaceName)
   193  	qr1 := utils.Exec(t, mcmp.VtConn, query)
   194  	require.EqualValues(t, 4, len(qr1.Fields))
   195  
   196  	// test a query with two keyspace names
   197  	query = fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+
   198  		"from information_schema.tables t "+
   199  		"join information_schema.columns c "+
   200  		"on c.table_schema = t.table_schema and c.table_name = t.table_name "+
   201  		"where t.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s'", keyspaceName, keyspaceName, "a")
   202  	_, err := mcmp.VtConn.ExecuteFetch(query, 1000, true)
   203  	require.Error(t, err)
   204  	require.Contains(t, err.Error(), "specifying two different database in the query is not supported")
   205  }
   206  
   207  func TestInfrSchemaAndUnionAll(t *testing.T) {
   208  	clusterInstance.VtGateExtraArgs = append(clusterInstance.VtGateExtraArgs, "--planner-version=gen4")
   209  	require.NoError(t,
   210  		clusterInstance.RestartVtgate())
   211  
   212  	vtConnParams := clusterInstance.GetVTParams(keyspaceName)
   213  	vtConnParams.DbName = keyspaceName
   214  	conn, err := mysql.Connect(context.Background(), &vtConnParams)
   215  	require.NoError(t, err)
   216  
   217  	for _, workload := range []string{"oltp", "olap"} {
   218  		t.Run(workload, func(t *testing.T) {
   219  			utils.Exec(t, conn, fmt.Sprintf("set workload = %s", workload))
   220  			utils.Exec(t, conn, "start transaction")
   221  			utils.Exec(t, conn, `select connection_id()`)
   222  			utils.Exec(t, conn, `(select 'corder' from t1 limit 1) union all (select 'customer' from t7_xxhash limit 1)`)
   223  			utils.Exec(t, conn, "rollback")
   224  		})
   225  	}
   226  }