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 }