vitess.io/vitess@v0.16.2/go/test/endtoend/vtgate/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 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 ) 32 33 func TestUnownedLookupInsertNull(t *testing.T) { 34 conn, closer := start(t) 35 defer closer() 36 37 utils.Exec(t, conn, "insert into t9(id, parent_id) VALUES (1, 1)") 38 utils.Exec(t, conn, "insert into t9(id, parent_id) VALUES (2, 2)") 39 40 utils.Exec(t, conn, "insert into t8(id, parent_id, t9_id) VALUES (1, 1, NULL)") 41 utils.Exec(t, conn, "insert into t8(id, parent_id, t9_id) VALUES (2, 1, 1)") 42 utils.Exec(t, conn, "insert into t8(id, parent_id, t9_id) VALUES (3, 2, 2)") 43 } 44 45 func TestLookupUniqueWithAutocommit(t *testing.T) { 46 conn, closer := start(t) 47 defer closer() 48 49 // conn2 is to check entries in the lookup table 50 conn2, err := mysql.Connect(context.Background(), &vtParams) 51 require.Nil(t, err) 52 defer conn2.Close() 53 54 // Test that all vindex writes are autocommitted outside of any ongoing transactions. 55 // 56 // Also test that autocommited vindex entries are visible inside transactions, as lookups 57 // should also use the autocommit connection. 58 59 utils.Exec(t, conn, "insert into t10(id, sharding_key) VALUES (1, 1)") 60 61 utils.AssertMatches(t, conn2, "select id from t10_id_to_keyspace_id_idx order by id asc", "[[INT64(1)]]") 62 utils.AssertMatches(t, conn, "select id from t10 where id = 1", "[[INT64(1)]]") 63 64 utils.Exec(t, conn, "begin") 65 66 utils.Exec(t, conn, "insert into t10(id, sharding_key) VALUES (2, 1)") 67 68 utils.AssertMatches(t, conn2, "select id from t10_id_to_keyspace_id_idx order by id asc", "[[INT64(1)] [INT64(2)]]") 69 utils.AssertMatches(t, conn, "select id from t10 where id = 2", "[[INT64(2)]]") 70 71 utils.Exec(t, conn, "insert into t10(id, sharding_key) VALUES (3, 1)") 72 73 utils.AssertMatches(t, conn2, "select id from t10_id_to_keyspace_id_idx order by id asc", "[[INT64(1)] [INT64(2)] [INT64(3)]]") 74 utils.AssertMatches(t, conn, "select id from t10 where id = 3", "[[INT64(3)]]") 75 76 utils.Exec(t, conn, "savepoint sp_foobar") 77 78 utils.Exec(t, conn, "insert into t10(id, sharding_key) VALUES (4, 1)") 79 80 utils.AssertMatches(t, conn2, "select id from t10_id_to_keyspace_id_idx order by id asc", "[[INT64(1)] [INT64(2)] [INT64(3)] [INT64(4)]]") 81 utils.AssertMatches(t, conn, "select id from t10 where id = 4", "[[INT64(4)]]") 82 } 83 84 func TestUnownedLookupInsertChecksKeyspaceIdsAreMatching(t *testing.T) { 85 conn, closer := start(t) 86 defer closer() 87 88 utils.Exec(t, conn, "insert into t9(id, parent_id) VALUES (1, 1)") 89 90 // This fails because the keyspace id for `parent_id` does not match the one for `t9_id` 91 _, err := utils.ExecAllowError(t, conn, "insert into t8(id, parent_id, t9_id) VALUES (4, 2, 1)") 92 require.EqualError(t, err, "values [[INT64(1)]] for column [t9_id] does not map to keyspace ids (errno 1105) (sqlstate HY000) during query: insert into t8(id, parent_id, t9_id) VALUES (4, 2, 1)") 93 94 // This fails because the `t9_id` value can't be mapped to a keyspace id 95 _, err = utils.ExecAllowError(t, conn, "insert into t8(id, parent_id, t9_id) VALUES (4, 2, 2)") 96 require.EqualError(t, err, "values [[INT64(2)]] for column [t9_id] does not map to keyspace ids (errno 1105) (sqlstate HY000) during query: insert into t8(id, parent_id, t9_id) VALUES (4, 2, 2)") 97 } 98 99 func TestUnownedLookupSelectNull(t *testing.T) { 100 conn, closer := start(t) 101 defer closer() 102 103 utils.Exec(t, conn, "select * from t8 WHERE t9_id IS NULL") 104 } 105 106 func TestConsistentLookup(t *testing.T) { 107 conn, closer := start(t) 108 defer closer() 109 // conn2 is for queries that target shards. 110 conn2, err := mysql.Connect(context.Background(), &vtParams) 111 require.Nil(t, err) 112 defer conn2.Close() 113 114 // Simple insert. 115 utils.Exec(t, conn, "begin") 116 utils.Exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 117 // check that the lookup query happens in the right connection 118 utils.AssertMatches(t, conn, "select * from t1 where id2 = 4", "[[INT64(1) INT64(4)]]") 119 utils.Exec(t, conn, "commit") 120 utils.AssertMatches(t, conn, "select * from t1", "[[INT64(1) INT64(4)]]") 121 qr := utils.Exec(t, conn, "select * from t1_id2_idx") 122 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 123 t.Errorf("select:\n%v want\n%v", got, want) 124 } 125 126 // Inserting again should fail. 127 utils.Exec(t, conn, "begin") 128 _, err = conn.ExecuteFetch("insert into t1(id1, id2) values(1, 4)", 1000, false) 129 utils.Exec(t, conn, "rollback") 130 require.Error(t, err) 131 mysqlErr := err.(*mysql.SQLError) 132 assert.Equal(t, 1062, mysqlErr.Num) 133 assert.Equal(t, "23000", mysqlErr.State) 134 assert.Contains(t, mysqlErr.Message, "reverted partial DML execution") 135 136 // Simple delete. 137 utils.Exec(t, conn, "begin") 138 utils.Exec(t, conn, "delete from t1 where id1=1") 139 utils.AssertMatches(t, conn, "select * from t1 where id2 = 4", "[]") 140 utils.Exec(t, conn, "commit") 141 qr = utils.Exec(t, conn, "select * from t1") 142 if got, want := fmt.Sprintf("%v", qr.Rows), "[]"; got != want { 143 t.Errorf("select:\n%v want\n%v", got, want) 144 } 145 qr = utils.Exec(t, conn, "select * from t1_id2_idx") 146 if got, want := fmt.Sprintf("%v", qr.Rows), "[]"; got != want { 147 t.Errorf("select:\n%v want\n%v", got, want) 148 } 149 150 // Autocommit insert. 151 utils.Exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 152 qr = utils.Exec(t, conn, "select * from t1") 153 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 154 t.Errorf("select:\n%v want\n%v", got, want) 155 } 156 qr = utils.Exec(t, conn, "select id2 from t1_id2_idx") 157 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4)]]"; got != want { 158 t.Errorf("select:\n%v want\n%v", got, want) 159 } 160 // Autocommit delete. 161 utils.Exec(t, conn, "delete from t1 where id1=1") 162 163 // Dangling row pointing to existing keyspace id. 164 utils.Exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 165 // Delete the main row only. 166 utils.Exec(t, conn2, "use `ks:-80`") 167 utils.Exec(t, conn2, "delete from t1 where id1=1") 168 // Verify the lookup row is still there. 169 qr = utils.Exec(t, conn, "select id2 from t1_id2_idx") 170 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4)]]"; got != want { 171 t.Errorf("select:\n%v want\n%v", got, want) 172 } 173 // Insert should still succeed. 174 utils.Exec(t, conn, "begin") 175 utils.Exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 176 utils.Exec(t, conn, "commit") 177 qr = utils.Exec(t, conn, "select * from t1") 178 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 179 t.Errorf("select:\n%v want\n%v", got, want) 180 } 181 // Lookup row should be unchanged. 182 qr = utils.Exec(t, conn, "select * from t1_id2_idx") 183 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 184 t.Errorf("select:\n%v want\n%v", got, want) 185 } 186 187 // Dangling row not pointing to existing keyspace id. 188 utils.Exec(t, conn2, "use `ks:-80`") 189 utils.Exec(t, conn2, "delete from t1 where id1=1") 190 // Update the lookup row with bogus keyspace id. 191 utils.Exec(t, conn, "update t1_id2_idx set keyspace_id='aaa' where id2=4") 192 qr = utils.Exec(t, conn, "select * from t1_id2_idx") 193 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"aaa\")]]"; got != want { 194 t.Errorf("select:\n%v want\n%v", got, want) 195 } 196 // Insert should still succeed. 197 utils.Exec(t, conn, "begin") 198 utils.Exec(t, conn, "insert into t1(id1, id2) values(1, 4)") 199 utils.Exec(t, conn, "commit") 200 qr = utils.Exec(t, conn, "select * from t1") 201 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 202 t.Errorf("select:\n%v want\n%v", got, want) 203 } 204 // lookup row must be updated. 205 qr = utils.Exec(t, conn, "select * from t1_id2_idx") 206 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 207 t.Errorf("select:\n%v want\n%v", got, want) 208 } 209 210 // Update, but don't change anything. This should not deadlock. 211 utils.Exec(t, conn, "begin") 212 utils.Exec(t, conn, "update t1 set id2=4 where id1=1") 213 utils.Exec(t, conn, "commit") 214 qr = utils.Exec(t, conn, "select * from t1") 215 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)]]"; got != want { 216 t.Errorf("select:\n%v want\n%v", got, want) 217 } 218 qr = utils.Exec(t, conn, "select * from t1_id2_idx") 219 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(4) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 220 t.Errorf("select:\n%v want\n%v", got, want) 221 } 222 223 // Update, and change the lookup value. This should change main and lookup rows. 224 utils.Exec(t, conn, "begin") 225 utils.Exec(t, conn, "update t1 set id2=5 where id1=1") 226 utils.Exec(t, conn, "commit") 227 qr = utils.Exec(t, conn, "select * from t1") 228 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(5)]]"; got != want { 229 t.Errorf("select:\n%v want\n%v", got, want) 230 } 231 qr = utils.Exec(t, conn, "select * from t1_id2_idx") 232 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(5) VARBINARY(\"\\x16k@\\xb4J\\xbaK\\xd6\")]]"; got != want { 233 t.Errorf("select:\n%v want\n%v", got, want) 234 } 235 } 236 237 func TestDMLScatter(t *testing.T) { 238 conn, closer := start(t) 239 defer closer() 240 241 /* Simple insert. after this dml, the tables will contain the following: 242 t3 (id5, id6, id7): 243 1 2 3 244 2 2 3 245 3 4 3 246 4 5 4 247 248 t3_id7_idx (id7, keyspace_id:id6): 249 3 2 250 3 2 251 3 4 252 4 5 253 */ 254 utils.Exec(t, conn, "begin") 255 utils.Exec(t, conn, "insert into t3(id5, id6, id7) values(1, 2, 3), (2, 2, 3), (3, 4, 3), (4, 5, 4)") 256 utils.Exec(t, conn, "commit") 257 qr := utils.Exec(t, conn, "select id5, id6, id7 from t3 order by id5") 258 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(2) INT64(3)] [INT64(2) INT64(2) INT64(3)] [INT64(3) INT64(4) INT64(3)] [INT64(4) INT64(5) INT64(4)]]"; got != want { 259 t.Errorf("select:\n%v want\n%v", got, want) 260 } 261 262 /* Updating a non lookup column. after this dml, the tables will contain the following: 263 t3 (id5, id6, id7): 264 42 2 3 265 2 2 3 266 3 4 3 267 4 5 4 268 269 t3_id7_idx (id7, keyspace_id:id6): 270 3 2 271 3 2 272 3 4 273 4 5 274 */ 275 utils.Exec(t, conn, "update `ks[-]`.t3 set id5 = 42 where id5 = 1") 276 qr = utils.Exec(t, conn, "select id5, id6, id7 from t3 order by id5") 277 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(2) INT64(2) INT64(3)] [INT64(3) INT64(4) INT64(3)] [INT64(4) INT64(5) INT64(4)] [INT64(42) INT64(2) INT64(3)]]"; got != want { 278 t.Errorf("select:\n%v want\n%v", got, want) 279 } 280 281 /* Updating a lookup column. after this dml, the tables will contain the following: 282 t3 (id5, id6, id7): 283 42 2 42 284 2 2 42 285 3 4 3 286 4 5 4 287 288 t3_id7_idx (id7, keyspace_id:id6): 289 42 2 290 42 2 291 3 4 292 4 5 293 */ 294 utils.Exec(t, conn, "begin") 295 utils.Exec(t, conn, "update t3 set id7 = 42 where id6 = 2") 296 utils.Exec(t, conn, "commit") 297 qr = utils.Exec(t, conn, "select id5, id6, id7 from t3 order by id5") 298 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(2) INT64(2) INT64(42)] [INT64(3) INT64(4) INT64(3)] [INT64(4) INT64(5) INT64(4)] [INT64(42) INT64(2) INT64(42)]]"; got != want { 299 t.Errorf("select:\n%v want\n%v", got, want) 300 } 301 302 /* delete one specific keyspace id. after this dml, the tables will contain the following: 303 t3 (id5, id6, id7): 304 3 4 3 305 4 5 4 306 307 t3_id7_idx (id7, keyspace_id:id6): 308 3 4 309 4 5 310 */ 311 utils.Exec(t, conn, "delete from t3 where id6 = 2") 312 qr = utils.Exec(t, conn, "select * from t3 where id6 = 2") 313 require.Empty(t, qr.Rows) 314 qr = utils.Exec(t, conn, "select * from t3_id7_idx where id6 = 2") 315 require.Empty(t, qr.Rows) 316 317 // delete all the rows. 318 utils.Exec(t, conn, "delete from `ks[-]`.t3") 319 qr = utils.Exec(t, conn, "select * from t3") 320 require.Empty(t, qr.Rows) 321 qr = utils.Exec(t, conn, "select * from t3_id7_idx") 322 require.Empty(t, qr.Rows) 323 } 324 325 func TestDMLIn(t *testing.T) { 326 conn, closer := start(t) 327 defer closer() 328 329 /* Simple insert. after this dml, the tables will contain the following: 330 t3 (id5, id6, id7): 331 1 2 3 332 2 2 3 333 3 4 3 334 4 5 4 335 336 t3_id7_idx (id7, keyspace_id:id6): 337 3 2 338 3 2 339 3 4 340 4 5 341 */ 342 utils.Exec(t, conn, "begin") 343 utils.Exec(t, conn, "insert into t3(id5, id6, id7) values(1, 2, 3), (2, 2, 3), (3, 4, 3), (4, 5, 4)") 344 utils.Exec(t, conn, "commit") 345 qr := utils.Exec(t, conn, "select id5, id6, id7 from t3 order by id5, id6") 346 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(2) INT64(3)] [INT64(2) INT64(2) INT64(3)] [INT64(3) INT64(4) INT64(3)] [INT64(4) INT64(5) INT64(4)]]"; got != want { 347 t.Errorf("select:\n%v want\n%v", got, want) 348 } 349 350 /* Updating a non lookup column. after this dml, the tables will contain the following: 351 t3 (id5, id6, id7): 352 1 2 3 353 2 2 3 354 42 4 3 355 42 5 4 356 357 t3_id7_idx (id7, keyspace_id:id6): 358 3 2 359 3 2 360 3 4 361 4 5 362 */ 363 utils.Exec(t, conn, "update t3 set id5 = 42 where id6 in (4, 5)") 364 qr = utils.Exec(t, conn, "select id5, id6, id7 from t3 order by id5, id6") 365 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(2) INT64(3)] [INT64(2) INT64(2) INT64(3)] [INT64(42) INT64(4) INT64(3)] [INT64(42) INT64(5) INT64(4)]]"; got != want { 366 t.Errorf("select:\n%v want\n%v", got, want) 367 } 368 369 /* Updating a non lookup column. after this dml, the tables will contain the following: 370 t3 (id5, id6, id7): 371 1 2 42 372 2 2 42 373 42 4 3 374 42 5 4 375 376 t3_id7_idx (id7, keyspace_id:id6): 377 42 2 378 42 2 379 3 4 380 42 5 381 */ 382 utils.Exec(t, conn, "begin") 383 utils.Exec(t, conn, "update t3 set id7 = 42 where id6 in (2, 5)") 384 utils.Exec(t, conn, "commit") 385 qr = utils.Exec(t, conn, "select id5, id6, id7 from t3 order by id5, id6") 386 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(2) INT64(42)] [INT64(2) INT64(2) INT64(42)] [INT64(42) INT64(4) INT64(3)] [INT64(42) INT64(5) INT64(42)]]"; got != want { 387 t.Errorf("select:\n%v want\n%v", got, want) 388 } 389 390 /* Updating a non lookup column. after this dml, the tables will contain the following: 391 t3 (id5, id6, id7): 392 42 4 3 393 42 5 4 394 395 t3_id7_idx (id7, keyspace_id:id6): 396 3 4 397 42 5 398 */ 399 utils.Exec(t, conn, "delete from t3 where id6 in (2)") 400 qr = utils.Exec(t, conn, "select * from t3 where id6 = 2") 401 require.Empty(t, qr.Rows) 402 qr = utils.Exec(t, conn, "select * from t3_id7_idx where id6 = 2") 403 require.Empty(t, qr.Rows) 404 405 // delete all the rows. 406 utils.Exec(t, conn, "delete from t3 where id6 in (4, 5)") 407 qr = utils.Exec(t, conn, "select * from t3") 408 require.Empty(t, qr.Rows) 409 qr = utils.Exec(t, conn, "select * from t3_id7_idx") 410 require.Empty(t, qr.Rows) 411 } 412 413 func TestConsistentLookupMultiInsert(t *testing.T) { 414 conn, closer := start(t) 415 defer closer() 416 // conn2 is for queries that target shards. 417 conn2, err := mysql.Connect(context.Background(), &vtParams) 418 require.Nil(t, err) 419 defer conn2.Close() 420 421 utils.Exec(t, conn, "begin") 422 utils.Exec(t, conn, "insert into t1(id1, id2) values(1,4), (2,5)") 423 utils.Exec(t, conn, "commit") 424 qr := utils.Exec(t, conn, "select * from t1") 425 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(1) INT64(4)] [INT64(2) INT64(5)]]"; got != want { 426 t.Errorf("select:\n%v want\n%v", got, want) 427 } 428 qr = utils.Exec(t, conn, "select count(*) from t1_id2_idx") 429 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(2)]]"; got != want { 430 t.Errorf("select:\n%v want\n%v", got, want) 431 } 432 433 // Delete one row but leave its lookup dangling. 434 utils.Exec(t, conn2, "use `ks:-80`") 435 utils.Exec(t, conn2, "delete from t1 where id1=1") 436 // Insert a bogus lookup row. 437 utils.Exec(t, conn, "insert into t1_id2_idx(id2, keyspace_id) values(6, 'aaa')") 438 // Insert 3 rows: 439 // first row will insert without changing lookup. 440 // second will insert and change lookup. 441 // third will be a fresh insert for main and lookup. 442 utils.Exec(t, conn, "begin") 443 utils.Exec(t, conn, "insert into t1(id1, id2) values(1,2), (3,6), (4,7)") 444 utils.Exec(t, conn, "commit") 445 qr = utils.Exec(t, conn, "select id1, id2 from t1 order by id1") 446 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 { 447 t.Errorf("select:\n%v want\n%v", got, want) 448 } 449 qr = utils.Exec(t, conn, "select * from t1_id2_idx where id2=6") 450 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(6) VARBINARY(\"N\\xb1\\x90ΙΆ\\xfa\\x16\\x9c\")]]"; got != want { 451 t.Errorf("select:\n%v want\n%v", got, want) 452 } 453 qr = utils.Exec(t, conn, "select count(*) from t1_id2_idx") 454 if got, want := fmt.Sprintf("%v", qr.Rows), "[[INT64(5)]]"; got != want { 455 t.Errorf("select:\n%v want\n%v", got, want) 456 } 457 } 458 459 func TestHashLookupMultiInsertIgnore(t *testing.T) { 460 conn, closer := start(t) 461 defer closer() 462 // conn2 is for queries that target shards. 463 conn2, err := mysql.Connect(context.Background(), &vtParams) 464 require.Nil(t, err) 465 defer conn2.Close() 466 467 utils.Exec(t, conn, "delete from t2") 468 utils.Exec(t, conn, "delete from t2_id4_idx") 469 defer func() { 470 utils.Exec(t, conn, "delete from t2") 471 utils.Exec(t, conn, "delete from t2_id4_idx") 472 }() 473 474 // DB should start out clean 475 utils.AssertMatches(t, conn, "select count(*) from t2_id4_idx", "[[INT64(0)]]") 476 utils.AssertMatches(t, conn, "select count(*) from t2", "[[INT64(0)]]") 477 478 // Try inserting a bunch of ids at once 479 utils.Exec(t, conn, "begin") 480 utils.Exec(t, conn, "insert ignore into t2(id3, id4) values(50,60), (30,40), (10,20)") 481 utils.Exec(t, conn, "commit") 482 483 // Verify 484 utils.AssertMatches(t, conn, "select id3, id4 from t2 order by id3", "[[INT64(10) INT64(20)] [INT64(30) INT64(40)] [INT64(50) INT64(60)]]") 485 utils.AssertMatches(t, conn, "select id3, id4 from t2_id4_idx order by id3", "[[INT64(10) INT64(20)] [INT64(30) INT64(40)] [INT64(50) INT64(60)]]") 486 } 487 488 func TestConsistentLookupUpdate(t *testing.T) { 489 conn, closer := start(t) 490 defer closer() 491 492 /* Simple insert. after this dml, the tables will contain the following: 493 t4 (id1, id2): 494 1 2 495 2 2 496 3 3 497 4 3 498 499 t4_id2_idx (id2, id1, keyspace_id:id1): 500 2 1 1 501 2 2 2 502 3 3 3 503 3 4 4 504 */ 505 utils.Exec(t, conn, "insert into t4(id1, id2) values(1, '2'), (2, '2'), (3, '3'), (4, '3')") 506 qr := utils.Exec(t, conn, "select id1, id2 from t4 order by id1") 507 if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(1) VARCHAR("2")] [INT64(2) VARCHAR("2")] [INT64(3) VARCHAR("3")] [INT64(4) VARCHAR("3")]]`; got != want { 508 t.Errorf("select:\n%v want\n%v", got, want) 509 } 510 511 /* Updating a lookup column. after this dml, the tables will contain the following: 512 t4 (id1, id2): 513 1 42 514 2 2 515 3 3 516 4 3 517 518 t4_id2_idx (id2, id1, keyspace_id:id1): 519 42 1 1 520 2 2 2 521 3 3 3 522 3 4 4 523 */ 524 utils.Exec(t, conn, "update t4 a set a.id2 = '42' where a.id1 = 1") 525 qr = utils.Exec(t, conn, "select id1, id2 from t4 order by id1") 526 if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(1) VARCHAR("42")] [INT64(2) VARCHAR("2")] [INT64(3) VARCHAR("3")] [INT64(4) VARCHAR("3")]]`; got != want { 527 t.Errorf("select:\n%v want\n%v", got, want) 528 } 529 530 /* delete one specific keyspace id. after this dml, the tables will contain the following: 531 t4 (id1, id2): 532 2 2 533 3 3 534 4 3 535 536 t4_id2_idx (id2, id1, keyspace_id:id1): 537 2 2 2 538 3 3 3 539 3 4 4 540 */ 541 utils.Exec(t, conn, "delete from t4 where id2 = '42'") 542 qr = utils.Exec(t, conn, "select * from t4 where id2 = '42'") 543 require.Empty(t, qr.Rows) 544 qr = utils.Exec(t, conn, "select * from t4_id2_idx where id2 = '42'") 545 require.Empty(t, qr.Rows) 546 547 // delete all the rows. 548 utils.Exec(t, conn, "delete from t4") 549 qr = utils.Exec(t, conn, "select * from t4") 550 require.Empty(t, qr.Rows) 551 qr = utils.Exec(t, conn, "select * from t4_id2_idx") 552 require.Empty(t, qr.Rows) 553 } 554 555 func TestSelectNullLookup(t *testing.T) { 556 conn, closer := start(t) 557 defer closer() 558 559 utils.Exec(t, conn, "insert into t6(id1, id2) values(1, 'a'), (2, 'b'), (3, null)") 560 561 for _, workload := range []string{"oltp", "olap"} { 562 t.Run(workload, func(t *testing.T) { 563 utils.Exec(t, conn, "set workload = "+workload) 564 utils.AssertMatches(t, conn, "select id1, id2 from t6 order by id1", "[[INT64(1) VARCHAR(\"a\")] [INT64(2) VARCHAR(\"b\")] [INT64(3) NULL]]") 565 utils.AssertIsEmpty(t, conn, "select id1, id2 from t6 where id2 = null") 566 utils.AssertMatches(t, conn, "select id1, id2 from t6 where id2 is null", "[[INT64(3) NULL]]") 567 utils.AssertMatches(t, conn, "select id1, id2 from t6 where id2 is not null order by id1", "[[INT64(1) VARCHAR(\"a\")] [INT64(2) VARCHAR(\"b\")]]") 568 utils.AssertIsEmpty(t, conn, "select id1, id2 from t6 where id1 IN (null)") 569 utils.AssertMatches(t, conn, "select id1, id2 from t6 where id1 IN (1,2,null) order by id1", "[[INT64(1) VARCHAR(\"a\")] [INT64(2) VARCHAR(\"b\")]]") 570 utils.AssertIsEmpty(t, conn, "select id1, id2 from t6 where id1 NOT IN (1,null) order by id1") 571 utils.AssertMatches(t, conn, "select id1, id2 from t6 where id1 NOT IN (1,3)", "[[INT64(2) VARCHAR(\"b\")]]") 572 }) 573 } 574 } 575 576 func TestUnicodeLooseMD5CaseInsensitive(t *testing.T) { 577 conn, closer := start(t) 578 defer closer() 579 580 utils.Exec(t, conn, "insert into t4(id1, id2) values(1, 'test')") 581 582 utils.AssertMatches(t, conn, "SELECT id1, id2 from t4 where id2 = 'Test'", `[[INT64(1) VARCHAR("test")]]`) 583 }