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 }