vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/gen4/system_schema_test.go (about)

     1  /*
     2  Copyright 2020 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  	"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 TestDbNameOverride(t *testing.T) {
    35  	defer cluster.PanicHandler(t)
    36  	ctx := context.Background()
    37  	conn, err := mysql.Connect(ctx, &vtParams)
    38  	require.Nil(t, err)
    39  	defer conn.Close()
    40  
    41  	// Test query in OLTP workload (default).
    42  	qr, err := conn.ExecuteFetch("SELECT distinct database() FROM information_schema.tables WHERE table_schema = database()", 1000, true)
    43  
    44  	require.Nil(t, err)
    45  	assert.Equal(t, 1, len(qr.Rows), "did not get enough rows back")
    46  	assert.Equal(t, "vt_ks", qr.Rows[0][0].ToString())
    47  
    48  	// Test again in OLAP workload (default).
    49  	utils.Exec(t, conn, "SET workload=OLAP")
    50  	qr, err = conn.ExecuteFetch("SELECT distinct database() FROM information_schema.tables WHERE table_schema = database()", 1000, true)
    51  
    52  	require.Nil(t, err)
    53  	assert.Equal(t, 1, len(qr.Rows), "did not get enough rows back")
    54  	assert.Equal(t, "vt_ks", qr.Rows[0][0].ToString())
    55  }
    56  
    57  func TestInformationSchemaQuery(t *testing.T) {
    58  	defer cluster.PanicHandler(t)
    59  	ctx := context.Background()
    60  	conn, err := mysql.Connect(ctx, &vtParams)
    61  	require.NoError(t, err)
    62  	defer conn.Close()
    63  
    64  	assertSingleRowIsReturned(t, conn, "table_schema = 'ks'", "vt_ks")
    65  	assertSingleRowIsReturned(t, conn, "table_schema = 'vt_ks'", "vt_ks")
    66  	assertResultIsEmpty(t, conn, "table_schema = 'NONE'")
    67  	assertSingleRowIsReturned(t, conn, "table_schema = 'performance_schema'", "performance_schema")
    68  	assertResultIsEmpty(t, conn, "table_schema = 'PERFORMANCE_SCHEMA'")
    69  	assertSingleRowIsReturned(t, conn, "table_schema = 'performance_schema' and table_name = 'users'", "performance_schema")
    70  	assertResultIsEmpty(t, conn, "table_schema = 'performance_schema' and table_name = 'foo'")
    71  	assertSingleRowIsReturned(t, conn, "table_schema = 'vt_ks' and table_name = 't1'", "vt_ks")
    72  	assertSingleRowIsReturned(t, conn, "table_schema = 'ks' and table_name = 't1'", "vt_ks")
    73  }
    74  
    75  func assertResultIsEmpty(t *testing.T, conn *mysql.Conn, pre string) {
    76  	t.Run(pre, func(t *testing.T) {
    77  		qr, err := conn.ExecuteFetch("SELECT distinct table_schema FROM information_schema.tables WHERE "+pre, 1000, true)
    78  		require.NoError(t, err)
    79  		assert.Empty(t, qr.Rows)
    80  	})
    81  }
    82  
    83  func assertSingleRowIsReturned(t *testing.T, conn *mysql.Conn, predicate string, expectedKs string) {
    84  	t.Run(predicate, func(t *testing.T) {
    85  		qr, err := conn.ExecuteFetch("SELECT distinct table_schema FROM information_schema.tables WHERE "+predicate, 1000, true)
    86  		require.NoError(t, err)
    87  		assert.Equal(t, 1, len(qr.Rows), "did not get enough rows back")
    88  		assert.Equal(t, expectedKs, qr.Rows[0][0].ToString())
    89  	})
    90  }
    91  
    92  func TestInformationSchemaWithSubquery(t *testing.T) {
    93  	defer cluster.PanicHandler(t)
    94  	ctx := context.Background()
    95  	conn, err := mysql.Connect(ctx, &vtParams)
    96  	require.NoError(t, err)
    97  	defer conn.Close()
    98  
    99  	result := utils.Exec(t, conn, "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = (SELECT SCHEMA()) AND TABLE_NAME = 'not_exists'")
   100  	assert.Empty(t, result.Rows)
   101  }
   102  
   103  func TestInformationSchemaQueryGetsRoutedToTheRightTableAndKeyspace(t *testing.T) {
   104  	defer cluster.PanicHandler(t)
   105  	ctx := context.Background()
   106  	conn, err := mysql.Connect(ctx, &vtParams)
   107  	require.NoError(t, err)
   108  	defer conn.Close()
   109  
   110  	_ = utils.Exec(t, conn, "SELECT id FROM ks.t1000") // test that the routed table is available to us
   111  	result := utils.Exec(t, conn, "SELECT * FROM information_schema.tables WHERE table_schema = database() and table_name='ks.t1000'")
   112  	assert.NotEmpty(t, result.Rows)
   113  }
   114  
   115  func TestFKConstraintUsingInformationSchema(t *testing.T) {
   116  	defer cluster.PanicHandler(t)
   117  	ctx := context.Background()
   118  	conn, err := mysql.Connect(ctx, &vtParams)
   119  	require.NoError(t, err)
   120  	defer conn.Close()
   121  
   122  	utils.Exec(t, conn, "create table ks.t7_xxhash(uid varchar(50),phone bigint,msg varchar(100),primary key(uid)) Engine=InnoDB")
   123  	utils.Exec(t, conn, "create table ks.t7_fk(id bigint,t7_uid varchar(50),primary key(id),CONSTRAINT t7_fk_ibfk_1 foreign key (t7_uid) references t7_xxhash(uid)	on delete set null on update cascade) Engine=InnoDB;")
   124  	defer utils.Exec(t, conn, "drop table ks.t7_fk, ks.t7_xxhash")
   125  
   126  	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'"
   127  	utils.AssertMatchesAny(t, conn, query,
   128  		`[[VARCHAR("t7_xxhash") VARCHAR("uid") VARCHAR("t7_uid") VARCHAR("t7_fk_ibfk_1") VARCHAR("CASCADE") VARCHAR("SET NULL")]]`,
   129  		`[[VARBINARY("t7_xxhash") VARCHAR("uid") VARCHAR("t7_uid") VARCHAR("t7_fk_ibfk_1") BINARY("CASCADE") BINARY("SET NULL")]]`)
   130  }
   131  
   132  func TestConnectWithSystemSchema(t *testing.T) {
   133  	defer cluster.PanicHandler(t)
   134  	ctx := context.Background()
   135  	for _, dbname := range []string{"information_schema", "mysql", "performance_schema", "sys"} {
   136  		connParams := vtParams
   137  		connParams.DbName = dbname
   138  		conn, err := mysql.Connect(ctx, &connParams)
   139  		require.NoError(t, err)
   140  		utils.Exec(t, conn, `select @@max_allowed_packet from dual`)
   141  		conn.Close()
   142  	}
   143  }
   144  
   145  func TestUseSystemSchema(t *testing.T) {
   146  	defer cluster.PanicHandler(t)
   147  	ctx := context.Background()
   148  	conn, err := mysql.Connect(ctx, &vtParams)
   149  	require.NoError(t, err)
   150  	defer conn.Close()
   151  	for _, dbname := range []string{"information_schema", "mysql", "performance_schema", "sys"} {
   152  		utils.Exec(t, conn, fmt.Sprintf("use %s", dbname))
   153  		utils.Exec(t, conn, `select @@max_allowed_packet from dual`)
   154  	}
   155  }
   156  
   157  func TestSystemSchemaQueryWithoutQualifier(t *testing.T) {
   158  	defer cluster.PanicHandler(t)
   159  	ctx := context.Background()
   160  	conn, err := mysql.Connect(ctx, &vtParams)
   161  	require.NoError(t, err)
   162  	defer conn.Close()
   163  
   164  	queryWithQualifier := fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+
   165  		"from information_schema.tables t "+
   166  		"join information_schema.columns c "+
   167  		"on c.table_schema = t.table_schema and c.table_name = t.table_name "+
   168  		"where t.table_schema = '%s' and c.table_schema = '%s' "+
   169  		"order by t.table_schema,t.table_name,c.column_name", shardedKs, shardedKs)
   170  	qr1 := utils.Exec(t, conn, queryWithQualifier)
   171  
   172  	utils.Exec(t, conn, "use information_schema")
   173  	queryWithoutQualifier := fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+
   174  		"from tables t "+
   175  		"join columns c "+
   176  		"on c.table_schema = t.table_schema and c.table_name = t.table_name "+
   177  		"where t.table_schema = '%s' and c.table_schema = '%s' "+
   178  		"order by t.table_schema,t.table_name,c.column_name", shardedKs, shardedKs)
   179  	qr2 := utils.Exec(t, conn, queryWithoutQualifier)
   180  	require.Equal(t, qr1, qr2)
   181  
   182  	connParams := vtParams
   183  	connParams.DbName = "information_schema"
   184  	conn2, err := mysql.Connect(ctx, &connParams)
   185  	require.NoError(t, err)
   186  	defer conn2.Close()
   187  
   188  	qr3 := utils.Exec(t, conn2, queryWithoutQualifier)
   189  	require.Equal(t, qr2, qr3)
   190  }
   191  
   192  func TestMultipleSchemaPredicates(t *testing.T) {
   193  	defer cluster.PanicHandler(t)
   194  	ctx := context.Background()
   195  	conn, err := mysql.Connect(ctx, &vtParams)
   196  	require.NoError(t, err)
   197  	defer conn.Close()
   198  
   199  	query := fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+
   200  		"from information_schema.tables t "+
   201  		"join information_schema.columns c "+
   202  		"on c.table_schema = t.table_schema and c.table_name = t.table_name "+
   203  		"where t.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s'", shardedKs, shardedKs, shardedKs, shardedKs)
   204  	qr1 := utils.Exec(t, conn, query)
   205  	require.EqualValues(t, 4, len(qr1.Fields))
   206  
   207  	// test a query with two keyspace names
   208  	query = fmt.Sprintf("select t.table_schema,t.table_name,c.column_name,c.column_type "+
   209  		"from information_schema.tables t "+
   210  		"join information_schema.columns c "+
   211  		"on c.table_schema = t.table_schema and c.table_name = t.table_name "+
   212  		"where t.table_schema = '%s' and c.table_schema = '%s' and c.table_schema = '%s'", shardedKs, shardedKs, "a")
   213  	_, err = conn.ExecuteFetch(query, 1000, true)
   214  	require.Error(t, err)
   215  	require.Contains(t, err.Error(), "specifying two different database in the query is not supported")
   216  }
   217  
   218  func TestQuerySystemTables(t *testing.T) {
   219  	defer cluster.PanicHandler(t)
   220  	ctx := context.Background()
   221  	conn, err := mysql.Connect(ctx, &vtParams)
   222  	require.NoError(t, err)
   223  	defer conn.Close()
   224  
   225  	utils.Exec(t, conn, `select * from sys.sys_config`)
   226  	utils.Exec(t, conn, "select * from mysql.`db`")
   227  	utils.Exec(t, conn, "select * from performance_schema.error_log")
   228  }