vitess.io/vitess@v0.16.2/go/vt/vtgate/endtoend/lookup_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 endtoend 18 19 import ( 20 "context" 21 "fmt" 22 "testing" 23 24 "github.com/stretchr/testify/assert" 25 26 "github.com/stretchr/testify/require" 27 28 "vitess.io/vitess/go/mysql" 29 "vitess.io/vitess/go/sqltypes" 30 ) 31 32 func TestConsistentLookup(t *testing.T) { 33 ctx := context.Background() 34 conn, err := mysql.Connect(ctx, &vtParams) 35 if err != nil { 36 t.Fatal(err) 37 } 38 defer conn.Close() 39 // conn2 is for queries that target shards. 40 conn2, err := mysql.Connect(ctx, &vtParams) 41 if err != nil { 42 t.Fatal(err) 43 } 44 defer conn2.Close() 45 46 // Simple insert. 47 exec(t, conn, "begin") 48 exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 49 exec(t, conn, "commit") 50 qr := exec(t, conn, "select * from t1") 51 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 52 t.Errorf("select:\n%v want\n%v", got, want) 53 } 54 qr = exec(t, conn, "select * from t1_id2_idx") 55 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 56 t.Errorf("select:\n%v want\n%v", got, want) 57 } 58 59 // Inserting again should fail. 60 exec(t, conn, "begin") 61 _, err = conn.ExecuteFetch("insert into t1(id1, id2) values(1, 4)", 1000, false) 62 exec(t, conn, "rollback") 63 require.Error(t, err) 64 mysqlErr := err.(*mysql.SQLError) 65 assert.Equal(t, 1062, mysqlErr.Num) 66 assert.Equal(t, "23000", mysqlErr.State) 67 68 // Simple delete. 69 exec(t, conn, "begin") 70 exec(t, conn, "delete from t1 where id1=1") 71 exec(t, conn, "commit") 72 qr = exec(t, conn, "select * from t1") 73 if got, want := fmt.Sprintf("%v", qr.Rows), "[]"; got != want { 74 t.Errorf("select:\n%v want\n%v", got, want) 75 } 76 qr = exec(t, conn, "select * from t1_id2_idx") 77 if got, want := fmt.Sprintf("%v", qr.Rows), "[]"; got != want { 78 t.Errorf("select:\n%v want\n%v", got, want) 79 } 80 81 // Autocommit insert. 82 exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 83 qr = exec(t, conn, "select * from t1") 84 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 85 t.Errorf("select:\n%v want\n%v", got, want) 86 } 87 qr = exec(t, conn, "select id2 from t1_id2_idx") 88 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4)]]"; got != want { 89 t.Errorf("select:\n%v want\n%v", got, want) 90 } 91 // Autocommit delete. 92 exec(t, conn, "delete from t1 where id1=1") 93 94 // Dangling row pointing to existing keyspace id. 95 exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 96 // Delete the main row only. 97 exec(t, conn2, "use `ks:-80`") 98 exec(t, conn2, "delete from t1 where id1=1") 99 // Verify the lookup row is still there. 100 qr = exec(t, conn, "select id2 from t1_id2_idx") 101 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4)]]"; got != want { 102 t.Errorf("select:\n%v want\n%v", got, want) 103 } 104 // Insert should still succeed. 105 exec(t, conn, "begin") 106 exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 107 exec(t, conn, "commit") 108 qr = exec(t, conn, "select * from t1") 109 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 110 t.Errorf("select:\n%v want\n%v", got, want) 111 } 112 // Lookup row should be unchanged. 113 qr = exec(t, conn, "select * from t1_id2_idx") 114 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 115 t.Errorf("select:\n%v want\n%v", got, want) 116 } 117 118 // Dangling row not pointing to existing keyspace id. 119 exec(t, conn2, "use `ks:-80`") 120 exec(t, conn2, "delete from t1 where id1=1") 121 // Update the lookup row with bogus keyspace id. 122 exec(t, conn, "update t1_id2_idx set keyspace_id='aaa' where id2=4") 123 qr = exec(t, conn, "select * from t1_id2_idx") 124 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"aaa\")]]"; got != want { 125 t.Errorf("select:\n%v want\n%v", got, want) 126 } 127 // Insert should still succeed. 128 exec(t, conn, "begin") 129 exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 130 exec(t, conn, "commit") 131 qr = exec(t, conn, "select * from t1") 132 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 133 t.Errorf("select:\n%v want\n%v", got, want) 134 } 135 // lookup row must be updated. 136 qr = exec(t, conn, "select * from t1_id2_idx") 137 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 138 t.Errorf("select:\n%v want\n%v", got, want) 139 } 140 141 // Update, but don't change anything. This should not deadlock. 142 exec(t, conn, "begin") 143 exec(t, conn, "update t1 set id2=4 where id1=1") 144 exec(t, conn, "commit") 145 qr = exec(t, conn, "select * from t1") 146 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 147 t.Errorf("select:\n%v want\n%v", got, want) 148 } 149 qr = exec(t, conn, "select * from t1_id2_idx") 150 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 151 t.Errorf("select:\n%v want\n%v", got, want) 152 } 153 154 // Update, and change the lookup value. This should change main and lookup rows. 155 exec(t, conn, "begin") 156 exec(t, conn, "update t1 set id2=5 where id1=1") 157 exec(t, conn, "commit") 158 qr = exec(t, conn, "select * from t1") 159 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(5)]]"; got != want { 160 t.Errorf("select:\n%v want\n%v", got, want) 161 } 162 qr = exec(t, conn, "select * from t1_id2_idx") 163 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(5) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 164 t.Errorf("select:\n%v want\n%v", got, want) 165 } 166 exec(t, conn, "delete from t1 where id1=1") 167 } 168 169 func TestConsistentLookupMultiInsert(t *testing.T) { 170 ctx := context.Background() 171 conn, err := mysql.Connect(ctx, &vtParams) 172 if err != nil { 173 t.Fatal(err) 174 } 175 defer conn.Close() 176 // conn2 is for queries that target shards. 177 conn2, err := mysql.Connect(ctx, &vtParams) 178 if err != nil { 179 t.Fatal(err) 180 } 181 defer conn2.Close() 182 183 exec(t, conn, "begin") 184 exec(t, conn, "insert into t1(id1, id2) values(1,4), (2,5)") 185 exec(t, conn, "commit") 186 qr := exec(t, conn, "select * from t1") 187 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)] [INT64(2) INT64(5)]]"; got != want { 188 t.Errorf("select:\n%v want\n%v", got, want) 189 } 190 qr = exec(t, conn, "select count(*) from t1_id2_idx") 191 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(2)]]"; got != want { 192 t.Errorf("select:\n%v want\n%v", got, want) 193 } 194 195 // Delete one row but leave its lookup dangling. 196 exec(t, conn2, "use `ks:-80`") 197 exec(t, conn2, "delete from t1 where id1=1") 198 // Insert a bogus lookup row. 199 exec(t, conn, "insert into t1_id2_idx(id2, keyspace_id) values(6, 'aaa')") 200 // Insert 3 rows: 201 // first row will insert without changing lookup. 202 // second will insert and change lookup. 203 // third will be a fresh insert for main and lookup. 204 exec(t, conn, "begin") 205 exec(t, conn, "insert into t1(id1, id2) values(1,2), (3,6), (4,7)") 206 exec(t, conn, "commit") 207 qr = exec(t, conn, "select id1, id2 from t1 order by id1") 208 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(2)] [INT64(2) INT64(5)] [INT64(3) INT64(6)] [INT64(4) INT64(7)]]"; got != want { 209 t.Errorf("select:\n%v want\n%v", got, want) 210 } 211 qr = exec(t, conn, "select * from t1_id2_idx where id2=6") 212 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(6) VARBINARY(\"N\\xb1\\x90ΙΆ\\xfa\\x16\\x9c\")]]"; got != want { 213 t.Errorf("select:\n%v want\n%v", got, want) 214 } 215 qr = exec(t, conn, "select count(*) from t1_id2_idx") 216 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(5)]]"; got != want { 217 t.Errorf("select:\n%v want\n%v", got, want) 218 } 219 exec(t, conn, "delete from t1 where id1=1") 220 exec(t, conn, "delete from t1 where id1=2") 221 exec(t, conn, "delete from t1 where id1=3") 222 exec(t, conn, "delete from t1 where id1=4") 223 exec(t, conn, "delete from t1_id2_idx where id2=4") 224 } 225 226 func TestLookupMultiInsertIgnore(t *testing.T) { 227 ctx := context.Background() 228 conn, err := mysql.Connect(ctx, &vtParams) 229 if err != nil { 230 t.Fatal(err) 231 } 232 defer conn.Close() 233 // conn2 is for queries that target shards. 234 conn2, err := mysql.Connect(ctx, &vtParams) 235 if err != nil { 236 t.Fatal(err) 237 } 238 defer conn2.Close() 239 240 // DB should start out clean 241 qr := exec(t, conn, "select count(*) from t2_id4_idx") 242 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(0)]]"; got != want { 243 t.Errorf("select:\n%v want\n%v", got, want) 244 } 245 qr = exec(t, conn, "select count(*) from t2") 246 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(0)]]"; got != want { 247 t.Errorf("select:\n%v want\n%v", got, want) 248 } 249 250 // Try inserting a bunch of ids at once 251 exec(t, conn, "begin") 252 exec(t, conn, "insert ignore into t2(id3, id4) values(50,60), (30,40), (10,20)") 253 exec(t, conn, "commit") 254 255 // Verify 256 qr = exec(t, conn, "select id3, id4 from t2 order by id3") 257 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(10) INT64(20)] [INT64(30) INT64(40)] [INT64(50) INT64(60)]]"; got != want { 258 t.Errorf("select:\n%v want\n%v", got, want) 259 } 260 qr = exec(t, conn, "select id3, id4 from t2_id4_idx order by id3") 261 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(10) INT64(20)] [INT64(30) INT64(40)] [INT64(50) INT64(60)]]"; got != want { 262 t.Errorf("select:\n%v want\n%v", got, want) 263 } 264 } 265 266 func TestConsistentLookupMultiInsertIgnore(t *testing.T) { 267 ctx := context.Background() 268 conn, err := mysql.Connect(ctx, &vtParams) 269 if err != nil { 270 t.Fatal(err) 271 } 272 defer conn.Close() 273 // conn2 is for queries that target shards. 274 conn2, err := mysql.Connect(ctx, &vtParams) 275 if err != nil { 276 t.Fatal(err) 277 } 278 defer conn2.Close() 279 280 // DB should start out clean 281 qr := exec(t, conn, "select count(*) from t1_id2_idx") 282 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(0)]]"; got != want { 283 t.Errorf("select:\n%v want\n%v", got, want) 284 } 285 qr = exec(t, conn, "select count(*) from t1") 286 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(0)]]"; got != want { 287 t.Errorf("select:\n%v want\n%v", got, want) 288 } 289 290 // Try inserting a bunch of ids at once 291 exec(t, conn, "begin") 292 exec(t, conn, "insert ignore into t1(id1, id2) values(50,60), (30,40), (10,20)") 293 exec(t, conn, "commit") 294 295 // Verify 296 qr = exec(t, conn, "select id1, id2 from t1 order by id1") 297 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(10) INT64(20)] [INT64(30) INT64(40)] [INT64(50) INT64(60)]]"; got != want { 298 t.Errorf("select:\n%v want\n%v", got, want) 299 } 300 qr = exec(t, conn, "select id2 from t1_id2_idx order by id2") 301 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(20)] [INT64(40)] [INT64(60)]]"; got != want { 302 t.Errorf("select:\n%v want\n%v", got, want) 303 } 304 } 305 306 func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { 307 t.Helper() 308 qr, err := conn.ExecuteFetch(query, 1000, true) 309 if err != nil { 310 t.Fatal(err) 311 } 312 return qr 313 }