vitess.io/vitess@v0.16.2/go/vt/vtgate/vindexes/lookup_unicodeloosemd5_hash_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 vindexes 18 19 import ( 20 "context" 21 "reflect" 22 "testing" 23 24 "github.com/stretchr/testify/require" 25 26 "vitess.io/vitess/go/sqltypes" 27 28 "vitess.io/vitess/go/vt/key" 29 querypb "vitess.io/vitess/go/vt/proto/query" 30 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 31 ) 32 33 const ( 34 hashed10 uint64 = 17563797831108199066 35 hashed20 uint64 = 8729390916138266389 36 hashed30 uint64 = 1472608112194674795 37 hashed40 uint64 = 16576388050845489136 38 ) 39 40 func TestLookupUnicodeLooseMD5HashMap(t *testing.T) { 41 lookup := createLookup(t, "lookup_unicodeloosemd5_hash", false) 42 vc := &vcursor{numRows: 2, keys: []sqltypes.Value{sqltypes.NewUint64(hashed10), sqltypes.NewUint64(hashed20)}} 43 44 got, err := lookup.Map(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(10), sqltypes.NewInt64(20)}) 45 require.NoError(t, err) 46 want := []key.Destination{ 47 key.DestinationKeyspaceIDs([][]byte{ 48 []byte("\x16k@\xb4J\xbaK\xd6"), 49 []byte("\x06\xe7\xea\"Βp\x8f"), 50 }), 51 key.DestinationKeyspaceIDs([][]byte{ 52 []byte("\x16k@\xb4J\xbaK\xd6"), 53 []byte("\x06\xe7\xea\"Βp\x8f"), 54 }), 55 } 56 if !reflect.DeepEqual(got, want) { 57 t.Errorf("Map(): %#v, want %+v", got, want) 58 } 59 60 vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewUint64(hashed10), sqltypes.NewUint64(hashed20)}) 61 require.NoError(t, err) 62 wantqueries := []*querypb.BoundQuery{{ 63 Sql: "select fromc, toc from t where fromc in ::fromc", 64 BindVariables: map[string]*querypb.BindVariable{ 65 "fromc": vars, 66 }, 67 }} 68 if !reflect.DeepEqual(vc.queries, wantqueries) { 69 t.Errorf("lookup.Map queries:\n%v, want\n%v", vc.queries, wantqueries) 70 } 71 72 // Test query fail. 73 vc.mustFail = true 74 _, err = lookup.Map(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(1)}) 75 wantErr := "lookup.Map: execute failed" 76 if err == nil || err.Error() != wantErr { 77 t.Errorf("lookup(query fail) err: %v, want %s", err, wantErr) 78 } 79 vc.mustFail = false 80 } 81 82 func TestLookupUnicodeLooseMD5HashMapAutocommit(t *testing.T) { 83 vindex, err := CreateVindex("lookup_unicodeloosemd5_hash", "lookup", map[string]string{ 84 "table": "t", 85 "from": "fromc", 86 "to": "toc", 87 "hash_from": "true", 88 "autocommit": "true", 89 }) 90 if err != nil { 91 t.Fatal(err) 92 } 93 lookupNonUnique := vindex.(SingleColumn) 94 vc := &vcursor{numRows: 2, keys: []sqltypes.Value{sqltypes.NewUint64(hashed10), sqltypes.NewUint64(hashed20)}} 95 96 got, err := lookupNonUnique.Map(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(10), sqltypes.NewInt64(20)}) 97 require.NoError(t, err) 98 want := []key.Destination{ 99 key.DestinationKeyspaceIDs([][]byte{ 100 []byte("\x16k@\xb4J\xbaK\xd6"), 101 []byte("\x06\xe7\xea\"Βp\x8f"), 102 }), 103 key.DestinationKeyspaceIDs([][]byte{ 104 []byte("\x16k@\xb4J\xbaK\xd6"), 105 []byte("\x06\xe7\xea\"Βp\x8f"), 106 }), 107 } 108 if !reflect.DeepEqual(got, want) { 109 t.Errorf("Map(): %#v, want %+v", got, want) 110 } 111 112 vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewUint64(hashed10), sqltypes.NewUint64(hashed20)}) 113 require.NoError(t, err) 114 wantqueries := []*querypb.BoundQuery{{ 115 Sql: "select fromc, toc from t where fromc in ::fromc", 116 BindVariables: map[string]*querypb.BindVariable{ 117 "fromc": vars, 118 }, 119 }} 120 if !reflect.DeepEqual(vc.queries, wantqueries) { 121 t.Errorf("lookup.Map queries:\n%v, want\n%v", vc.queries, wantqueries) 122 } 123 124 if got, want := vc.autocommits, 1; got != want { 125 t.Errorf("Create(autocommit) count: %d, want %d", got, want) 126 } 127 } 128 129 func TestLookupUnicodeLooseMD5HashMapWriteOnly(t *testing.T) { 130 lookupNonUnique := createLookup(t, "lookup_unicodeloosemd5_hash", true) 131 vc := &vcursor{numRows: 0} 132 133 got, err := lookupNonUnique.Map(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(10), sqltypes.NewInt64(20)}) 134 require.NoError(t, err) 135 want := []key.Destination{ 136 key.DestinationKeyRange{ 137 KeyRange: &topodatapb.KeyRange{}, 138 }, 139 key.DestinationKeyRange{ 140 KeyRange: &topodatapb.KeyRange{}, 141 }, 142 } 143 if !reflect.DeepEqual(got, want) { 144 t.Errorf("Map(): %#v, want %+v", got, want) 145 } 146 } 147 148 func TestLookupUnicodeLooseMD5HashMapAbsent(t *testing.T) { 149 lookupNonUnique := createLookup(t, "lookup_unicodeloosemd5_hash", false) 150 vc := &vcursor{numRows: 0} 151 152 got, err := lookupNonUnique.Map(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(10), sqltypes.NewInt64(20)}) 153 require.NoError(t, err) 154 want := []key.Destination{ 155 key.DestinationNone{}, 156 key.DestinationNone{}, 157 } 158 if !reflect.DeepEqual(got, want) { 159 t.Errorf("Map(): %#v, want %+v", got, want) 160 } 161 } 162 163 func TestLookupUnicodeLooseMD5HashVerify(t *testing.T) { 164 lookupNonUnique := createLookup(t, "lookup_unicodeloosemd5_hash", false) 165 vc := &vcursor{numRows: 1} 166 167 got, err := lookupNonUnique.Verify(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(10), sqltypes.NewInt64(20)}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6"), []byte("\x06\xe7\xea\"Βp\x8f")}) 168 require.NoError(t, err) 169 wantResult := []bool{true, true} 170 if !reflect.DeepEqual(got, wantResult) { 171 t.Errorf("lookuphash.Verify(match): %v, want %v", got, wantResult) 172 } 173 174 wantqueries := []*querypb.BoundQuery{{ 175 Sql: "select fromc from t where fromc = :fromc and toc = :toc", 176 BindVariables: map[string]*querypb.BindVariable{ 177 "fromc": sqltypes.Uint64BindVariable(hashed10), 178 "toc": sqltypes.Uint64BindVariable(1), 179 }, 180 }, { 181 Sql: "select fromc from t where fromc = :fromc and toc = :toc", 182 BindVariables: map[string]*querypb.BindVariable{ 183 "fromc": sqltypes.Uint64BindVariable(hashed20), 184 "toc": sqltypes.Uint64BindVariable(2), 185 }, 186 }} 187 if !reflect.DeepEqual(vc.queries, wantqueries) { 188 t.Errorf("lookup.Verify queries:\n%v, want\n%v", vc.queries, wantqueries) 189 } 190 191 // Test query fail. 192 vc.mustFail = true 193 _, err = lookupNonUnique.Verify(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(1)}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}) 194 want := "lookup.Verify: execute failed" 195 if err == nil || err.Error() != want { 196 t.Errorf("lookupNonUnique(query fail) err: %v, want %s", err, want) 197 } 198 vc.mustFail = false 199 200 // writeOnly true should always yield true. 201 lookupNonUnique = createLookup(t, "lookup_unicodeloosemd5_hash", true) 202 vc.queries = nil 203 204 got, err = lookupNonUnique.Verify(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(10), sqltypes.NewInt64(20)}, [][]byte{[]byte(""), []byte("")}) 205 require.NoError(t, err) 206 if vc.queries != nil { 207 t.Errorf("lookup.Verify(writeOnly), queries: %v, want nil", vc.queries) 208 } 209 wantBools := []bool{true, true} 210 if !reflect.DeepEqual(got, wantBools) { 211 t.Errorf("lookup.Verify(writeOnly): %v, want %v", got, wantBools) 212 } 213 } 214 215 func TestLookupUnicodeLooseMD5HashVerifyAutocommit(t *testing.T) { 216 vindex, err := CreateVindex("lookup_unicodeloosemd5_hash", "lookup", map[string]string{ 217 "table": "t", 218 "from": "fromc", 219 "to": "toc", 220 "autocommit": "true", 221 }) 222 if err != nil { 223 t.Fatal(err) 224 } 225 lookupNonUnique := vindex.(SingleColumn) 226 vc := &vcursor{numRows: 1} 227 228 _, err = lookupNonUnique.Verify(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(10), sqltypes.NewInt64(20)}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6"), []byte("\x06\xe7\xea\"Βp\x8f")}) 229 require.NoError(t, err) 230 231 wantqueries := []*querypb.BoundQuery{{ 232 Sql: "select fromc from t where fromc = :fromc and toc = :toc", 233 BindVariables: map[string]*querypb.BindVariable{ 234 "fromc": sqltypes.Uint64BindVariable(hashed10), 235 "toc": sqltypes.Uint64BindVariable(1), 236 }, 237 }, { 238 Sql: "select fromc from t where fromc = :fromc and toc = :toc", 239 BindVariables: map[string]*querypb.BindVariable{ 240 "fromc": sqltypes.Uint64BindVariable(hashed20), 241 "toc": sqltypes.Uint64BindVariable(2), 242 }, 243 }} 244 if !reflect.DeepEqual(vc.queries, wantqueries) { 245 t.Errorf("lookup.Verify queries:\n%v, want\n%v", vc.queries, wantqueries) 246 } 247 248 if got, want := vc.autocommits, 2; got != want { 249 t.Errorf("Create(autocommit) count: %d, want %d", got, want) 250 } 251 } 252 253 func TestLookupUnicodeLooseMD5HashCreate(t *testing.T) { 254 lookupNonUnique := createLookup(t, "lookup_unicodeloosemd5_hash", false) 255 vc := &vcursor{} 256 257 err := lookupNonUnique.(Lookup).Create(context.Background(), vc, [][]sqltypes.Value{{sqltypes.NewInt64(10)}, {sqltypes.NewInt64(20)}}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6"), []byte("\x06\xe7\xea\"Βp\x8f")}, false) 258 require.NoError(t, err) 259 260 wantqueries := []*querypb.BoundQuery{{ 261 Sql: "insert into t(fromc, toc) values(:fromc_0, :toc_0), (:fromc_1, :toc_1)", 262 BindVariables: map[string]*querypb.BindVariable{ 263 "fromc_0": sqltypes.Uint64BindVariable(hashed10), 264 "toc_0": sqltypes.Uint64BindVariable(1), 265 "fromc_1": sqltypes.Uint64BindVariable(hashed20), 266 "toc_1": sqltypes.Uint64BindVariable(2), 267 }, 268 }} 269 if !reflect.DeepEqual(vc.queries, wantqueries) { 270 t.Errorf("lookup.Create queries:\n%v, want\n%v", vc.queries, wantqueries) 271 } 272 273 // With ignore. 274 vc.queries = nil 275 err = lookupNonUnique.(Lookup).Create(context.Background(), vc, [][]sqltypes.Value{{sqltypes.NewInt64(10)}, {sqltypes.NewInt64(20)}}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6"), []byte("\x06\xe7\xea\"Βp\x8f")}, true) 276 require.NoError(t, err) 277 278 wantqueries[0].Sql = "insert ignore into t(fromc, toc) values(:fromc_0, :toc_0), (:fromc_1, :toc_1)" 279 if !reflect.DeepEqual(vc.queries, wantqueries) { 280 t.Errorf("lookup.Create queries:\n%v, want\n%v", vc.queries, wantqueries) 281 } 282 283 // Test query fail. 284 vc.mustFail = true 285 err = lookupNonUnique.(Lookup).Create(context.Background(), vc, [][]sqltypes.Value{{sqltypes.NewInt64(10)}}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}, false) 286 want := "lookup.Create: execute failed" 287 if err == nil || err.Error() != want { 288 t.Errorf("lookupNonUnique(query fail) err: %v, want %s", err, want) 289 } 290 vc.mustFail = false 291 292 // Test column mismatch. 293 err = lookupNonUnique.(Lookup).Create(context.Background(), vc, [][]sqltypes.Value{{sqltypes.NewInt64(10), sqltypes.NewInt64(20)}}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6")}, false) 294 want = "lookup.Create: column vindex count does not match the columns in the lookup: 2 vs [fromc]" 295 if err == nil || err.Error() != want { 296 t.Errorf("lookupNonUnique(query fail) err: %v, want %s", err, want) 297 } 298 } 299 300 func TestLookupUnicodeLooseMD5HashCreateAutocommit(t *testing.T) { 301 lookupNonUnique, err := CreateVindex("lookup_unicodeloosemd5_hash", "lookup", map[string]string{ 302 "table": "t", 303 "from": "from1,from2", 304 "to": "toc", 305 "autocommit": "true", 306 }) 307 if err != nil { 308 t.Fatal(err) 309 } 310 vc := &vcursor{} 311 312 err = lookupNonUnique.(Lookup).Create(context.Background(), vc, [][]sqltypes.Value{{ 313 sqltypes.NewInt64(10), sqltypes.NewInt64(20), 314 }, { 315 sqltypes.NewInt64(30), sqltypes.NewInt64(40), 316 }}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6"), []byte("\x06\xe7\xea\"Βp\x8f")}, false) 317 require.NoError(t, err) 318 319 wantqueries := []*querypb.BoundQuery{{ 320 Sql: "insert into t(from1, from2, toc) values(:from1_0, :from2_0, :toc_0), (:from1_1, :from2_1, :toc_1) on duplicate key update from1=values(from1), from2=values(from2), toc=values(toc)", 321 BindVariables: map[string]*querypb.BindVariable{ 322 "from1_0": sqltypes.Uint64BindVariable(hashed30), 323 "from2_0": sqltypes.Uint64BindVariable(hashed40), 324 "toc_0": sqltypes.Uint64BindVariable(2), 325 "from1_1": sqltypes.Uint64BindVariable(hashed10), 326 "from2_1": sqltypes.Uint64BindVariable(hashed20), 327 "toc_1": sqltypes.Uint64BindVariable(1), 328 }, 329 }} 330 if !reflect.DeepEqual(vc.queries, wantqueries) { 331 t.Errorf("lookup.Create queries:\n%v, want\n%v", vc.queries, wantqueries) 332 } 333 334 if got, want := vc.autocommits, 1; got != want { 335 t.Errorf("Create(autocommit) count: %d, want %d", got, want) 336 } 337 } 338 339 func TestLookupUnicodeLooseMD5HashCreateMultiShardAutocommit(t *testing.T) { 340 lookupNonUnique, err := CreateVindex("lookup_unicodeloosemd5_hash", "lookup", map[string]string{ 341 "table": "t", 342 "from": "from1,from2", 343 "to": "toc", 344 "multi_shard_autocommit": "true", 345 }) 346 if err != nil { 347 t.Fatal(err) 348 } 349 vc := &vcursor{} 350 351 err = lookupNonUnique.(Lookup).Create(context.Background(), vc, [][]sqltypes.Value{{ 352 sqltypes.NewInt64(10), sqltypes.NewInt64(20), 353 }, { 354 sqltypes.NewInt64(30), sqltypes.NewInt64(40), 355 }}, [][]byte{[]byte("\x16k@\xb4J\xbaK\xd6"), []byte("\x06\xe7\xea\"Βp\x8f")}, false) 356 require.NoError(t, err) 357 358 wantqueries := []*querypb.BoundQuery{{ 359 Sql: "insert /*vt+ MULTI_SHARD_AUTOCOMMIT=1 */ into t(from1, from2, toc) values(:from1_0, :from2_0, :toc_0), (:from1_1, :from2_1, :toc_1) on duplicate key update from1=values(from1), from2=values(from2), toc=values(toc)", 360 BindVariables: map[string]*querypb.BindVariable{ 361 "from1_0": sqltypes.Uint64BindVariable(hashed30), 362 "from2_0": sqltypes.Uint64BindVariable(hashed40), 363 "toc_0": sqltypes.Uint64BindVariable(2), 364 "from1_1": sqltypes.Uint64BindVariable(hashed10), 365 "from2_1": sqltypes.Uint64BindVariable(hashed20), 366 "toc_1": sqltypes.Uint64BindVariable(1), 367 }, 368 }} 369 if !reflect.DeepEqual(vc.queries, wantqueries) { 370 t.Errorf("lookup.Create queries:\n%v, want\n%v", vc.queries, wantqueries) 371 } 372 373 if got, want := vc.autocommits, 1; got != want { 374 t.Errorf("Create(autocommit) count: %d, want %d", got, want) 375 } 376 } 377 378 func TestLookupUnicodeLooseMD5HashDelete(t *testing.T) { 379 lookupNonUnique := createLookup(t, "lookup_unicodeloosemd5_hash", false) 380 vc := &vcursor{} 381 382 err := lookupNonUnique.(Lookup).Delete(context.Background(), vc, [][]sqltypes.Value{{sqltypes.NewInt64(10)}, {sqltypes.NewInt64(20)}}, []byte("\x16k@\xb4J\xbaK\xd6")) 383 require.NoError(t, err) 384 385 wantqueries := []*querypb.BoundQuery{{ 386 Sql: "delete from t where fromc = :fromc and toc = :toc", 387 BindVariables: map[string]*querypb.BindVariable{ 388 "fromc": sqltypes.Uint64BindVariable(hashed10), 389 "toc": sqltypes.Uint64BindVariable(1), 390 }, 391 }, { 392 Sql: "delete from t where fromc = :fromc and toc = :toc", 393 BindVariables: map[string]*querypb.BindVariable{ 394 "fromc": sqltypes.Uint64BindVariable(hashed20), 395 "toc": sqltypes.Uint64BindVariable(1), 396 }, 397 }} 398 if !reflect.DeepEqual(vc.queries, wantqueries) { 399 t.Errorf("lookup.Delete queries:\n%v, want\n%v", vc.queries, wantqueries) 400 } 401 402 // Test query fail. 403 vc.mustFail = true 404 err = lookupNonUnique.(Lookup).Delete(context.Background(), vc, [][]sqltypes.Value{{sqltypes.NewInt64(1)}}, []byte("\x16k@\xb4J\xbaK\xd6")) 405 want := "lookup.Delete: execute failed" 406 if err == nil || err.Error() != want { 407 t.Errorf("lookupNonUnique(query fail) err: %v, want %s", err, want) 408 } 409 vc.mustFail = false 410 411 // Test column count fail. 412 err = lookupNonUnique.(Lookup).Delete(context.Background(), vc, [][]sqltypes.Value{{sqltypes.NewInt64(1), sqltypes.NewInt64(2)}}, []byte("\x16k@\xb4J\xbaK\xd6")) 413 want = "lookup.Delete: column vindex count does not match the columns in the lookup: 2 vs [fromc]" 414 if err == nil || err.Error() != want { 415 t.Errorf("lookupNonUnique(query fail) err: %v, want %s", err, want) 416 } 417 } 418 419 func TestLookupUnicodeLooseMD5HashDeleteAutocommit(t *testing.T) { 420 lookupNonUnique, _ := CreateVindex("lookup_unicodeloosemd5_hash", "lookup", map[string]string{ 421 "table": "t", 422 "from": "fromc", 423 "to": "toc", 424 "autocommit": "true", 425 }) 426 vc := &vcursor{} 427 428 err := lookupNonUnique.(Lookup).Delete(context.Background(), vc, [][]sqltypes.Value{{sqltypes.NewInt64(10)}, {sqltypes.NewInt64(20)}}, []byte("\x16k@\xb4J\xbaK\xd6")) 429 require.NoError(t, err) 430 431 wantqueries := []*querypb.BoundQuery(nil) 432 if !reflect.DeepEqual(vc.queries, wantqueries) { 433 t.Errorf("lookup.Delete queries:\n%v, want\n%v", vc.queries, wantqueries) 434 } 435 } 436 437 func TestLookupUnicodeLooseMD5HashUpdate(t *testing.T) { 438 lookupNonUnique := createLookup(t, "lookup_unicodeloosemd5_hash", false) 439 vc := &vcursor{} 440 441 err := lookupNonUnique.(Lookup).Update(context.Background(), vc, []sqltypes.Value{sqltypes.NewInt64(10)}, []byte("\x16k@\xb4J\xbaK\xd6"), []sqltypes.Value{sqltypes.NewInt64(20)}) 442 require.NoError(t, err) 443 444 wantqueries := []*querypb.BoundQuery{{ 445 Sql: "delete from t where fromc = :fromc and toc = :toc", 446 BindVariables: map[string]*querypb.BindVariable{ 447 "fromc": sqltypes.Uint64BindVariable(hashed10), 448 "toc": sqltypes.Uint64BindVariable(1), 449 }, 450 }, { 451 Sql: "insert into t(fromc, toc) values(:fromc_0, :toc_0)", 452 BindVariables: map[string]*querypb.BindVariable{ 453 "fromc_0": sqltypes.Uint64BindVariable(hashed20), 454 "toc_0": sqltypes.Uint64BindVariable(1), 455 }, 456 }} 457 if !reflect.DeepEqual(vc.queries, wantqueries) { 458 t.Errorf("lookup.Update queries:\n%v, want\n%v", vc.queries, wantqueries) 459 } 460 }