vitess.io/vitess@v0.16.2/go/vt/vtgate/executor_dml_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 "strings" 23 "testing" 24 25 "vitess.io/vitess/go/mysql" 26 "vitess.io/vitess/go/sqltypes" 27 "vitess.io/vitess/go/test/utils" 28 "vitess.io/vitess/go/vt/sqlparser" 29 _ "vitess.io/vitess/go/vt/vtgate/vindexes" 30 "vitess.io/vitess/go/vt/vttablet/sandboxconn" 31 32 "github.com/stretchr/testify/assert" 33 "github.com/stretchr/testify/require" 34 35 querypb "vitess.io/vitess/go/vt/proto/query" 36 vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" 37 vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" 38 ) 39 40 func TestUpdateEqual(t *testing.T) { 41 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 42 43 logChan := QueryLogger.Subscribe("Test") 44 defer QueryLogger.Unsubscribe(logChan) 45 46 // Update by primary vindex. 47 _, err := executorExec(executor, "update user set a=2 where id = 1", nil) 48 require.NoError(t, err) 49 wantQueries := []*querypb.BoundQuery{{ 50 Sql: "update `user` set a = 2 where id = 1", 51 BindVariables: map[string]*querypb.BindVariable{}, 52 }} 53 assertQueries(t, sbc1, wantQueries) 54 assertQueries(t, sbc2, nil) 55 testQueryLog(t, logChan, "TestExecute", "UPDATE", "update user set a=2 where id = 1", 1) 56 57 sbc1.Queries = nil 58 _, err = executorExec(executor, "update user set a=2 where id = 3", nil) 59 require.NoError(t, err) 60 wantQueries = []*querypb.BoundQuery{{ 61 Sql: "update `user` set a = 2 where id = 3", 62 BindVariables: map[string]*querypb.BindVariable{}, 63 }} 64 assertQueries(t, sbc2, wantQueries) 65 assertQueries(t, sbc1, nil) 66 67 // Update by secondary vindex. 68 sbc1.Queries = nil 69 sbc2.Queries = nil 70 sbclookup.SetResults([]*sqltypes.Result{{}}) 71 _, err = executorExec(executor, "update music set a=2 where id = 2", nil) 72 require.NoError(t, err) 73 vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewInt64(2)}) 74 require.NoError(t, err) 75 wantQueries = []*querypb.BoundQuery{{ 76 Sql: "select music_id, user_id from music_user_map where music_id in ::music_id for update", 77 BindVariables: map[string]*querypb.BindVariable{ 78 "music_id": vars, 79 }, 80 }} 81 assertQueries(t, sbclookup, wantQueries) 82 assertQueries(t, sbc2, nil) 83 assertQueries(t, sbc1, nil) 84 85 // Update changes lookup vindex values. 86 sbc1.Queries = nil 87 sbc2.Queries = nil 88 sbclookup.Queries = nil 89 sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 90 sqltypes.MakeTestFields("id|name|lastname|name_lastname_keyspace_id_map", "int64|int32|varchar|int64"), 91 "1|1|foo|0", 92 ), 93 }) 94 95 _, err = executorExec(executor, "update user2 set `name`='myname', lastname='mylastname' where id = 1", nil) 96 require.NoError(t, err) 97 wantQueries = []*querypb.BoundQuery{ 98 { 99 Sql: "select id, `name`, lastname, `name` = 'myname' and lastname = 'mylastname' from user2 where id = 1 for update", 100 BindVariables: map[string]*querypb.BindVariable{}, 101 }, 102 { 103 Sql: "update user2 set `name` = 'myname', lastname = 'mylastname' where id = 1", 104 BindVariables: map[string]*querypb.BindVariable{}, 105 }, 106 } 107 assertQueries(t, sbc1, wantQueries) 108 assertQueries(t, sbc2, nil) 109 110 wantQueries = []*querypb.BoundQuery{ 111 { 112 Sql: "delete from name_lastname_keyspace_id_map where `name` = :name and lastname = :lastname and keyspace_id = :keyspace_id", 113 BindVariables: map[string]*querypb.BindVariable{ 114 "lastname": sqltypes.StringBindVariable("foo"), 115 "name": sqltypes.Int32BindVariable(1), 116 "keyspace_id": sqltypes.BytesBindVariable([]byte("\x16k@\xb4J\xbaK\xd6")), 117 }, 118 }, 119 { 120 Sql: "insert into name_lastname_keyspace_id_map(`name`, lastname, keyspace_id) values (:name_0, :lastname_0, :keyspace_id_0)", 121 BindVariables: map[string]*querypb.BindVariable{ 122 "name_0": sqltypes.StringBindVariable("myname"), 123 "lastname_0": sqltypes.StringBindVariable("mylastname"), 124 "keyspace_id_0": sqltypes.BytesBindVariable([]byte("\x16k@\xb4J\xbaK\xd6")), 125 }, 126 }, 127 } 128 129 assertQueries(t, sbclookup, wantQueries) 130 } 131 132 func TestUpdateFromSubQuery(t *testing.T) { 133 executor, sbc1, sbc2, _ := createExecutorEnv() 134 executor.pv = querypb.ExecuteOptions_Gen4 135 logChan := QueryLogger.Subscribe("Test") 136 defer QueryLogger.Unsubscribe(logChan) 137 138 fields := []*querypb.Field{ 139 {Name: "count(*)", Type: sqltypes.Int64}, 140 } 141 sbc2.SetResults([]*sqltypes.Result{{ 142 Fields: fields, 143 Rows: [][]sqltypes.Value{{ 144 sqltypes.NewInt64(4), 145 }}, 146 }}) 147 148 // Update by primary vindex, but first execute subquery 149 _, err := executorExec(executor, "update user set a=(select count(*) from user where id = 3) where id = 1", nil) 150 require.NoError(t, err) 151 wantQueriesSbc1 := []*querypb.BoundQuery{{ 152 Sql: "update `user` set a = :__sq1 where id = 1", 153 BindVariables: map[string]*querypb.BindVariable{ 154 "__sq1": sqltypes.Int64BindVariable(4), 155 }, 156 }} 157 wantQueriesSbc2 := []*querypb.BoundQuery{{ 158 Sql: "select count(*) from `user` where id = 3 lock in share mode", 159 BindVariables: map[string]*querypb.BindVariable{}, 160 }} 161 assertQueries(t, sbc1, wantQueriesSbc1) 162 assertQueries(t, sbc2, wantQueriesSbc2) 163 testQueryLog(t, logChan, "TestExecute", "UPDATE", "update user set a=(select count(*) from user where id = 3) where id = 1", 2) 164 } 165 166 func TestUpdateEqualWithNoVerifyAndWriteOnlyLookupUniqueVindexes(t *testing.T) { 167 res := []*sqltypes.Result{sqltypes.MakeTestResult( 168 sqltypes.MakeTestFields( 169 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col|t2_lu_vdx", 170 "int64|int64|int64|int64|int64|int64|int64|int64", 171 ), 172 "1|2|2|2|2|2|1|0", 173 )} 174 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, res) 175 176 _, err := executorExec(executor, "update t2_lookup set lu_col = 5 where wo_lu_col = 2", nil) 177 require.NoError(t, err) 178 wantQueries := []*querypb.BoundQuery{ 179 { 180 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col, lu_col = 5 from t2_lookup where wo_lu_col = 2 for update", 181 BindVariables: map[string]*querypb.BindVariable{}, 182 }, { 183 Sql: "update t2_lookup set lu_col = 5 where wo_lu_col = 2", 184 BindVariables: map[string]*querypb.BindVariable{}, 185 }} 186 187 assertQueries(t, sbc1, wantQueries) 188 assertQueries(t, sbc2, wantQueries) 189 190 bq1 := &querypb.BoundQuery{ 191 Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", 192 BindVariables: map[string]*querypb.BindVariable{ 193 "keyspace_id": sqltypes.Uint64BindVariable(1), 194 "lu_col": sqltypes.Int64BindVariable(1), 195 }, 196 } 197 bq2 := &querypb.BoundQuery{ 198 Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", 199 BindVariables: map[string]*querypb.BindVariable{ 200 "keyspace_id_0": sqltypes.Uint64BindVariable(1), 201 "lu_col_0": sqltypes.Int64BindVariable(5), 202 }, 203 } 204 lookWant := []*querypb.BoundQuery{ 205 bq1, bq2, 206 bq1, bq2, 207 bq1, bq2, 208 bq1, bq2, 209 bq1, bq2, 210 bq1, bq2, 211 bq1, bq2, 212 bq1, bq2, 213 } 214 assertQueries(t, sbcLookup, lookWant) 215 } 216 217 func TestUpdateInTransactionLookupDefaultReadLock(t *testing.T) { 218 res := []*sqltypes.Result{sqltypes.MakeTestResult( 219 sqltypes.MakeTestFields( 220 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col|t2_lu_vdx", 221 "int64|int64|int64|int64|int64|int64|int64|int64", 222 ), 223 "1|2|2|2|2|2|1|0", 224 )} 225 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, res) 226 227 safeSession := NewSafeSession(&vtgatepb.Session{InTransaction: true}) 228 _, err := executorExecSession( 229 executor, 230 "update t2_lookup set lu_col = 5 where nv_lu_col = 2", 231 nil, 232 safeSession.Session, 233 ) 234 235 require.NoError(t, err) 236 wantQueries := []*querypb.BoundQuery{ 237 { 238 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col, lu_col = 5 from t2_lookup where nv_lu_col = 2 and lu_col = 1 for update", 239 BindVariables: map[string]*querypb.BindVariable{}, 240 }, { 241 Sql: "update t2_lookup set lu_col = 5 where nv_lu_col = 2", 242 BindVariables: map[string]*querypb.BindVariable{}, 243 }, 244 } 245 246 assertQueries(t, sbc1, wantQueries) 247 assertQueries(t, sbc2, wantQueries) 248 249 vars, _ := sqltypes.BuildBindVariable([]any{ 250 sqltypes.NewInt64(2), 251 }) 252 bq1 := &querypb.BoundQuery{ 253 Sql: "select nv_lu_col, keyspace_id from nv_lu_idx where nv_lu_col in ::nv_lu_col for update", 254 BindVariables: map[string]*querypb.BindVariable{ 255 "nv_lu_col": vars, 256 }, 257 } 258 bq2 := &querypb.BoundQuery{ 259 Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", 260 BindVariables: map[string]*querypb.BindVariable{ 261 "keyspace_id_0": sqltypes.Uint64BindVariable(1), 262 "lu_col_0": sqltypes.Int64BindVariable(5), 263 }, 264 } 265 lookWant := []*querypb.BoundQuery{ 266 bq1, bq2, 267 bq1, bq2, 268 bq1, bq2, 269 bq1, bq2, 270 bq1, bq2, 271 bq1, bq2, 272 bq1, bq2, 273 bq1, bq2, 274 } 275 276 assertQueries(t, sbcLookup, lookWant) 277 } 278 279 func TestUpdateInTransactionLookupExclusiveReadLock(t *testing.T) { 280 res := []*sqltypes.Result{sqltypes.MakeTestResult( 281 sqltypes.MakeTestFields( 282 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col|t2_lu_vdx", 283 "int64|int64|int64|int64|int64|int64|int64|int64", 284 ), 285 "1|2|2|2|2|2|1|0", 286 )} 287 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, res) 288 289 safeSession := NewSafeSession(&vtgatepb.Session{InTransaction: true}) 290 _, err := executorExecSession( 291 executor, 292 "update t2_lookup set lu_col = 5 where erl_lu_col = 2", 293 nil, 294 safeSession.Session, 295 ) 296 297 require.NoError(t, err) 298 wantQueries := []*querypb.BoundQuery{ 299 { 300 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col, lu_col = 5 from t2_lookup where nv_lu_col = 2 and lu_col = 1 for update", 301 BindVariables: map[string]*querypb.BindVariable{}, 302 }, { 303 Sql: "update t2_lookup set lu_col = 5 where erl_lu_col = 2", 304 BindVariables: map[string]*querypb.BindVariable{}, 305 }, 306 } 307 308 assertQueries(t, sbc1, wantQueries) 309 assertQueries(t, sbc2, wantQueries) 310 311 vars, _ := sqltypes.BuildBindVariable([]any{ 312 sqltypes.NewInt64(2), 313 }) 314 bq1 := &querypb.BoundQuery{ 315 Sql: "select erl_lu_col, keyspace_id from erl_lu_idx where erl_lu_col in ::erl_lu_col for update", 316 BindVariables: map[string]*querypb.BindVariable{ 317 "erl_lu_col": vars, 318 }, 319 } 320 bq2 := &querypb.BoundQuery{ 321 Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", 322 BindVariables: map[string]*querypb.BindVariable{ 323 "keyspace_id_0": sqltypes.Uint64BindVariable(1), 324 "lu_col_0": sqltypes.Int64BindVariable(5), 325 }, 326 } 327 lookWant := []*querypb.BoundQuery{ 328 bq1, bq2, 329 bq1, bq2, 330 bq1, bq2, 331 bq1, bq2, 332 bq1, bq2, 333 bq1, bq2, 334 bq1, bq2, 335 bq1, bq2, 336 } 337 338 assertQueries(t, sbcLookup, lookWant) 339 } 340 341 func TestUpdateInTransactionLookupSharedReadLock(t *testing.T) { 342 res := []*sqltypes.Result{sqltypes.MakeTestResult( 343 sqltypes.MakeTestFields( 344 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col|t2_lu_vdx", 345 "int64|int64|int64|int64|int64|int64|int64|int64", 346 ), 347 "1|2|2|2|2|2|1|0", 348 )} 349 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, res) 350 351 safeSession := NewSafeSession(&vtgatepb.Session{InTransaction: true}) 352 _, err := executorExecSession( 353 executor, 354 "update t2_lookup set lu_col = 5 where srl_lu_col = 2", 355 nil, 356 safeSession.Session, 357 ) 358 359 require.NoError(t, err) 360 wantQueries := []*querypb.BoundQuery{ 361 { 362 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col, lu_col = 5 from t2_lookup where nv_lu_col = 2 and lu_col = 1 for update", 363 BindVariables: map[string]*querypb.BindVariable{}, 364 }, { 365 Sql: "update t2_lookup set lu_col = 5 where srl_lu_col = 2", 366 BindVariables: map[string]*querypb.BindVariable{}, 367 }, 368 } 369 370 assertQueries(t, sbc1, wantQueries) 371 assertQueries(t, sbc2, wantQueries) 372 373 vars, _ := sqltypes.BuildBindVariable([]any{ 374 sqltypes.NewInt64(2), 375 }) 376 bq1 := &querypb.BoundQuery{ 377 Sql: "select srl_lu_col, keyspace_id from srl_lu_idx where srl_lu_col in ::srl_lu_col lock in share mode", 378 BindVariables: map[string]*querypb.BindVariable{ 379 "srl_lu_col": vars, 380 }, 381 } 382 bq2 := &querypb.BoundQuery{ 383 Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", 384 BindVariables: map[string]*querypb.BindVariable{ 385 "keyspace_id_0": sqltypes.Uint64BindVariable(1), 386 "lu_col_0": sqltypes.Int64BindVariable(5), 387 }, 388 } 389 lookWant := []*querypb.BoundQuery{ 390 bq1, bq2, 391 bq1, bq2, 392 bq1, bq2, 393 bq1, bq2, 394 bq1, bq2, 395 bq1, bq2, 396 bq1, bq2, 397 bq1, bq2, 398 } 399 400 assertQueries(t, sbcLookup, lookWant) 401 } 402 403 func TestUpdateInTransactionLookupNoReadLock(t *testing.T) { 404 res := []*sqltypes.Result{sqltypes.MakeTestResult( 405 sqltypes.MakeTestFields( 406 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col|t2_lu_vdx", 407 "int64|int64|int64|int64|int64|int64|int64|int64", 408 ), 409 "1|2|2|2|2|2|1|0", 410 )} 411 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, res) 412 413 safeSession := NewSafeSession(&vtgatepb.Session{InTransaction: true}) 414 _, err := executorExecSession( 415 executor, 416 "update t2_lookup set lu_col = 5 where nrl_lu_col = 2", 417 nil, 418 safeSession.Session, 419 ) 420 421 require.NoError(t, err) 422 wantQueries := []*querypb.BoundQuery{ 423 { 424 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col, lu_col = 5 from t2_lookup where nrl_lu_col = 2 and lu_col = 1 for update", 425 BindVariables: map[string]*querypb.BindVariable{}, 426 }, { 427 Sql: "update t2_lookup set lu_col = 5 where nrl_lu_col = 2", 428 BindVariables: map[string]*querypb.BindVariable{}, 429 }, 430 } 431 432 assertQueries(t, sbc1, wantQueries) 433 assertQueries(t, sbc2, wantQueries) 434 435 vars, _ := sqltypes.BuildBindVariable([]any{ 436 sqltypes.NewInt64(2), 437 }) 438 bq1 := &querypb.BoundQuery{ 439 Sql: "select nrl_lu_col, keyspace_id from nrl_lu_idx where nrl_lu_col in ::nrl_lu_col", 440 BindVariables: map[string]*querypb.BindVariable{ 441 "nrl_lu_col": vars, 442 }, 443 } 444 bq2 := &querypb.BoundQuery{ 445 Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", 446 BindVariables: map[string]*querypb.BindVariable{ 447 "keyspace_id_0": sqltypes.Uint64BindVariable(1), 448 "lu_col_0": sqltypes.Int64BindVariable(5), 449 }, 450 } 451 lookWant := []*querypb.BoundQuery{ 452 bq1, bq2, 453 bq1, bq2, 454 bq1, bq2, 455 bq1, bq2, 456 bq1, bq2, 457 bq1, bq2, 458 bq1, bq2, 459 bq1, bq2, 460 } 461 462 assertQueries(t, sbcLookup, lookWant) 463 } 464 465 func TestUpdateMultiOwned(t *testing.T) { 466 vschema := ` 467 { 468 "sharded": true, 469 "vindexes": { 470 "hash_index": { 471 "type": "hash" 472 }, 473 "lookup1": { 474 "type": "lookup_hash_unique", 475 "owner": "user", 476 "params": { 477 "table": "music_user_map", 478 "from": "from1,from2", 479 "to": "user_id" 480 } 481 }, 482 "lookup2": { 483 "type": "lookup_hash_unique", 484 "owner": "user", 485 "params": { 486 "table": "music_user_map", 487 "from": "from1,from2", 488 "to": "user_id" 489 } 490 }, 491 "lookup3": { 492 "type": "lookup_hash_unique", 493 "owner": "user", 494 "params": { 495 "table": "music_user_map", 496 "from": "from1,from2", 497 "to": "user_id" 498 } 499 } 500 }, 501 "tables": { 502 "user": { 503 "column_vindexes": [ 504 { 505 "column": "id", 506 "name": "hash_index" 507 }, 508 { 509 "columns": ["a", "b"], 510 "name": "lookup1" 511 }, 512 { 513 "columns": ["c", "d"], 514 "name": "lookup2" 515 }, 516 { 517 "columns": ["e", "f"], 518 "name": "lookup3" 519 } 520 ] 521 } 522 } 523 } 524 ` 525 executor, sbc1, sbc2, sbclookup := createCustomExecutor(vschema) 526 527 sbc1.SetResults([]*sqltypes.Result{ 528 sqltypes.MakeTestResult( 529 sqltypes.MakeTestFields("id|a|b|c|d|e|f|lookup1|lookup3", "int64|int64|int64|int64|int64|int64|int64|int64|int64"), 530 "1|10|20|30|40|50|60|0|0", 531 ), 532 }) 533 _, err := executorExec(executor, "update user set a=1, b=2, f=4, e=3 where id=1", nil) 534 if err != nil { 535 t.Fatal(err) 536 } 537 wantQueries := []*querypb.BoundQuery{{ 538 Sql: "select id, a, b, c, d, e, f, a = 1 and b = 2, e = 3 and f = 4 from `user` where id = 1 for update", 539 BindVariables: map[string]*querypb.BindVariable{}, 540 }, { 541 Sql: "update `user` set a = 1, b = 2, f = 4, e = 3 where id = 1", 542 BindVariables: map[string]*querypb.BindVariable{}, 543 }} 544 assertQueries(t, sbc1, wantQueries) 545 assertQueries(t, sbc2, nil) 546 547 wantQueries = []*querypb.BoundQuery{{ 548 Sql: "delete from music_user_map where from1 = :from1 and from2 = :from2 and user_id = :user_id", 549 BindVariables: map[string]*querypb.BindVariable{ 550 "from1": sqltypes.Int64BindVariable(10), 551 "from2": sqltypes.Int64BindVariable(20), 552 "user_id": sqltypes.Uint64BindVariable(1), 553 }, 554 }, { 555 Sql: "insert into music_user_map(from1, from2, user_id) values (:from1_0, :from2_0, :user_id_0)", 556 BindVariables: map[string]*querypb.BindVariable{ 557 "from1_0": sqltypes.Int64BindVariable(1), 558 "from2_0": sqltypes.Int64BindVariable(2), 559 "user_id_0": sqltypes.Uint64BindVariable(1), 560 }, 561 }, { 562 Sql: "delete from music_user_map where from1 = :from1 and from2 = :from2 and user_id = :user_id", 563 BindVariables: map[string]*querypb.BindVariable{ 564 "from1": sqltypes.Int64BindVariable(50), 565 "from2": sqltypes.Int64BindVariable(60), 566 "user_id": sqltypes.Uint64BindVariable(1), 567 }, 568 }, { 569 Sql: "insert into music_user_map(from1, from2, user_id) values (:from1_0, :from2_0, :user_id_0)", 570 BindVariables: map[string]*querypb.BindVariable{ 571 "from1_0": sqltypes.Int64BindVariable(3), 572 "from2_0": sqltypes.Int64BindVariable(4), 573 "user_id_0": sqltypes.Uint64BindVariable(1), 574 }, 575 }} 576 577 assertQueries(t, sbclookup, wantQueries) 578 } 579 580 func TestUpdateComments(t *testing.T) { 581 executor, sbc1, sbc2, _ := createExecutorEnv() 582 583 _, err := executorExec(executor, "update user set a=2 where id = 1 /* trailing */", nil) 584 require.NoError(t, err) 585 wantQueries := []*querypb.BoundQuery{{ 586 Sql: "update `user` set a = 2 where id = 1 /* trailing */", 587 BindVariables: map[string]*querypb.BindVariable{}, 588 }} 589 assertQueries(t, sbc1, wantQueries) 590 assertQueries(t, sbc2, nil) 591 } 592 593 func TestUpdateNormalize(t *testing.T) { 594 executor, sbc1, sbc2, _ := createExecutorEnv() 595 596 executor.normalize = true 597 _, err := executorExec(executor, "/* leading */ update user set a=2 where id = 1 /* trailing */", nil) 598 require.NoError(t, err) 599 wantQueries := []*querypb.BoundQuery{{ 600 Sql: "/* leading */ update `user` set a = :a where id = :id /* trailing */", 601 BindVariables: map[string]*querypb.BindVariable{ 602 "a": sqltypes.TestBindVariable(int64(2)), 603 "id": sqltypes.TestBindVariable(int64(1)), 604 }, 605 }} 606 assertQueries(t, sbc1, wantQueries) 607 assertQueries(t, sbc2, nil) 608 sbc1.Queries = nil 609 610 // Force the query to go to the "wrong" shard and ensure that normalization still happens 611 primarySession.TargetString = "TestExecutor/40-60" 612 _, err = executorExec(executor, "/* leading */ update user set a=2 where id = 1 /* trailing */", nil) 613 require.NoError(t, err) 614 wantQueries = []*querypb.BoundQuery{{ 615 Sql: "/* leading */ update `user` set a = :a where id = :id /* trailing */", 616 BindVariables: map[string]*querypb.BindVariable{ 617 "a": sqltypes.TestBindVariable(int64(2)), 618 "id": sqltypes.TestBindVariable(int64(1)), 619 }, 620 }} 621 assertQueries(t, sbc1, nil) 622 assertQueries(t, sbc2, wantQueries) 623 sbc2.Queries = nil 624 primarySession.TargetString = "" 625 } 626 627 func TestDeleteEqual(t *testing.T) { 628 executor, sbc, _, sbclookup := createExecutorEnv() 629 630 sbc.SetResults([]*sqltypes.Result{{ 631 Fields: []*querypb.Field{ 632 {Name: "Id", Type: sqltypes.Int64}, 633 {Name: "name", Type: sqltypes.VarChar}, 634 }, 635 RowsAffected: 1, 636 InsertID: 0, 637 Rows: [][]sqltypes.Value{{ 638 sqltypes.NewInt64(1), 639 sqltypes.NewVarChar("myname"), 640 }}, 641 }}) 642 _, err := executorExec(executor, "delete from user where id = 1", nil) 643 require.NoError(t, err) 644 wantQueries := []*querypb.BoundQuery{{ 645 Sql: "select Id, `name` from `user` where id = 1 for update", 646 BindVariables: map[string]*querypb.BindVariable{}, 647 }, { 648 Sql: "delete from `user` where id = 1", 649 BindVariables: map[string]*querypb.BindVariable{}, 650 }} 651 assertQueries(t, sbc, wantQueries) 652 653 wantQueries = []*querypb.BoundQuery{{ 654 Sql: "delete from name_user_map where `name` = :name and user_id = :user_id", 655 BindVariables: map[string]*querypb.BindVariable{ 656 "user_id": sqltypes.Uint64BindVariable(1), 657 "name": sqltypes.ValueBindVariable(sqltypes.NewVarChar("myname")), 658 }, 659 }} 660 assertQueries(t, sbclookup, wantQueries) 661 662 sbc.Queries = nil 663 sbclookup.Queries = nil 664 sbc.SetResults([]*sqltypes.Result{{}}) 665 _, err = executorExec(executor, "delete from user where id = 1", nil) 666 require.NoError(t, err) 667 wantQueries = []*querypb.BoundQuery{{ 668 Sql: "select Id, `name` from `user` where id = 1 for update", 669 BindVariables: map[string]*querypb.BindVariable{}, 670 }, { 671 Sql: "delete from `user` where id = 1", 672 BindVariables: map[string]*querypb.BindVariable{}, 673 }} 674 assertQueries(t, sbc, wantQueries) 675 assertQueries(t, sbclookup, nil) 676 677 sbc.Queries = nil 678 sbclookup.Queries = nil 679 sbclookup.SetResults([]*sqltypes.Result{{}}) 680 _, err = executorExec(executor, "delete from music where id = 1", nil) 681 require.NoError(t, err) 682 vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewInt64(1)}) 683 require.NoError(t, err) 684 wantQueries = []*querypb.BoundQuery{{ 685 Sql: "select music_id, user_id from music_user_map where music_id in ::music_id for update", 686 BindVariables: map[string]*querypb.BindVariable{ 687 "music_id": vars, 688 }, 689 }} 690 assertQueries(t, sbclookup, wantQueries) 691 assertQueries(t, sbc, nil) 692 693 sbc.Queries = nil 694 sbclookup.Queries = nil 695 sbclookup.SetResults([]*sqltypes.Result{{}}) 696 _, err = executorExec(executor, "delete from user_extra where user_id = 1", nil) 697 require.NoError(t, err) 698 wantQueries = []*querypb.BoundQuery{{ 699 Sql: "delete from user_extra where user_id = 1", 700 BindVariables: map[string]*querypb.BindVariable{}, 701 }} 702 assertQueries(t, sbc, wantQueries) 703 assertQueries(t, sbclookup, nil) 704 705 sbc.Queries = nil 706 sbclookup.Queries = nil 707 sbc.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 708 sqltypes.MakeTestFields("id|name|lastname", "int64|int32|varchar"), 709 "1|1|foo", 710 ), 711 }) 712 _, err = executorExec(executor, "delete from user2 where id = 1", nil) 713 require.NoError(t, err) 714 wantQueries = []*querypb.BoundQuery{ 715 { 716 Sql: "select id, `name`, lastname from user2 where id = 1 for update", 717 BindVariables: map[string]*querypb.BindVariable{}, 718 }, 719 { 720 Sql: "delete from user2 where id = 1", 721 BindVariables: map[string]*querypb.BindVariable{}, 722 }, 723 } 724 assertQueries(t, sbc, wantQueries) 725 726 wantQueries = []*querypb.BoundQuery{ 727 { 728 Sql: "delete from name_lastname_keyspace_id_map where `name` = :name and lastname = :lastname and keyspace_id = :keyspace_id", 729 BindVariables: map[string]*querypb.BindVariable{ 730 "lastname": sqltypes.ValueBindVariable(sqltypes.NewVarChar("foo")), 731 "name": sqltypes.Int32BindVariable(1), 732 "keyspace_id": sqltypes.BytesBindVariable([]byte("\x16k@\xb4J\xbaK\xd6")), 733 }, 734 }, 735 } 736 737 assertQueries(t, sbclookup, wantQueries) 738 } 739 740 func TestUpdateScatter(t *testing.T) { 741 executor, sbc1, sbc2, _ := createExecutorEnv() 742 _, err := executorExec(executor, "update user_extra set col = 2", nil) 743 require.NoError(t, err) 744 // Queries get annotatted. 745 wantQueries := []*querypb.BoundQuery{{ 746 Sql: "update user_extra set col = 2", 747 BindVariables: map[string]*querypb.BindVariable{}, 748 }} 749 assertQueries(t, sbc1, wantQueries) 750 assertQueries(t, sbc2, wantQueries) 751 } 752 753 func TestDeleteScatter(t *testing.T) { 754 executor, sbc1, sbc2, _ := createExecutorEnv() 755 _, err := executorExec(executor, "delete from user_extra", nil) 756 require.NoError(t, err) 757 // Queries get annotatted. 758 wantQueries := []*querypb.BoundQuery{{ 759 Sql: "delete from user_extra", 760 BindVariables: map[string]*querypb.BindVariable{}, 761 }} 762 assertQueries(t, sbc1, wantQueries) 763 assertQueries(t, sbc2, wantQueries) 764 } 765 766 func TestUpdateEqualWithMultipleLookupVindex(t *testing.T) { 767 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, nil) 768 769 sbcLookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 770 sqltypes.MakeTestFields("lu_col|keyspace_id", "int64|varbinary"), 771 "1|1", 772 )}) 773 774 sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 775 sqltypes.MakeTestFields( 776 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col|t2_lu_vdx", 777 "int64|int64|int64|int64|int64|int64|int64|int64", 778 ), 779 "1|2|2|2|2|2|1|0", 780 )}) 781 782 _, err := executorExec(executor, "update t2_lookup set lu_col = 5 where wo_lu_col = 2 and lu_col = 1", nil) 783 require.NoError(t, err) 784 wantQueries := []*querypb.BoundQuery{ 785 { 786 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col, lu_col = 5 from t2_lookup where wo_lu_col = 2 and lu_col = 1 for update", 787 BindVariables: map[string]*querypb.BindVariable{}, 788 }, { 789 Sql: "update t2_lookup set lu_col = 5 where wo_lu_col = 2 and lu_col = 1", 790 BindVariables: map[string]*querypb.BindVariable{}, 791 }} 792 793 vars, _ := sqltypes.BuildBindVariable([]any{ 794 sqltypes.NewInt64(1), 795 }) 796 lookWant := []*querypb.BoundQuery{{ 797 Sql: "select lu_col, keyspace_id from lu_idx where lu_col in ::lu_col for update", 798 BindVariables: map[string]*querypb.BindVariable{ 799 "lu_col": vars, 800 }, 801 }, { 802 Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", 803 BindVariables: map[string]*querypb.BindVariable{ 804 "keyspace_id": sqltypes.Uint64BindVariable(1), 805 "lu_col": sqltypes.Int64BindVariable(1), 806 }, 807 }, { 808 Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", 809 BindVariables: map[string]*querypb.BindVariable{ 810 "keyspace_id_0": sqltypes.Uint64BindVariable(1), 811 "lu_col_0": sqltypes.Int64BindVariable(5), 812 }, 813 }} 814 assertQueries(t, sbcLookup, lookWant) 815 assertQueries(t, sbc1, wantQueries) 816 assertQueries(t, sbc2, nil) 817 } 818 819 func TestUpdateUseHigherCostVindexIfBackfilling(t *testing.T) { 820 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, nil) 821 822 sbcLookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 823 sqltypes.MakeTestFields("lu_col|keyspace_id", "int64|varbinary"), 824 "1|1", 825 "2|1", 826 )}) 827 828 sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 829 sqltypes.MakeTestFields( 830 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col|t2_lu_vdx", 831 "int64|int64|int64|int64|int64|int64|int64|int64", 832 ), 833 "1|2|2|2|2|2|1|0", 834 "1|2|2|2|2|2|2|0", 835 )}) 836 837 _, err := executorExec(executor, "update t2_lookup set lu_col = 5 where wo_lu_col = 2 and lu_col in (1, 2)", nil) 838 require.NoError(t, err) 839 wantQueries := []*querypb.BoundQuery{ 840 { 841 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col, lu_col = 5 from t2_lookup where wo_lu_col = 2 and lu_col in (1, 2) for update", 842 BindVariables: map[string]*querypb.BindVariable{}, 843 }, { 844 Sql: "update t2_lookup set lu_col = 5 where wo_lu_col = 2 and lu_col in (1, 2)", 845 BindVariables: map[string]*querypb.BindVariable{}, 846 }} 847 848 vars, _ := sqltypes.BuildBindVariable([]any{ 849 sqltypes.NewInt64(1), 850 sqltypes.NewInt64(2), 851 }) 852 lookWant := []*querypb.BoundQuery{{ 853 Sql: "select lu_col, keyspace_id from lu_idx where lu_col in ::lu_col for update", 854 BindVariables: map[string]*querypb.BindVariable{ 855 "lu_col": vars, 856 }, 857 }, { 858 Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", 859 BindVariables: map[string]*querypb.BindVariable{ 860 "keyspace_id": sqltypes.Uint64BindVariable(1), 861 "lu_col": sqltypes.Int64BindVariable(1), 862 }, 863 }, { 864 Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", 865 BindVariables: map[string]*querypb.BindVariable{ 866 "keyspace_id_0": sqltypes.Uint64BindVariable(1), 867 "lu_col_0": sqltypes.Int64BindVariable(5), 868 }, 869 }, { 870 Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", 871 BindVariables: map[string]*querypb.BindVariable{ 872 "keyspace_id": sqltypes.Uint64BindVariable(1), 873 "lu_col": sqltypes.Int64BindVariable(2), 874 }, 875 }, { 876 Sql: "insert into lu_idx(lu_col, keyspace_id) values (:lu_col_0, :keyspace_id_0)", 877 BindVariables: map[string]*querypb.BindVariable{ 878 "keyspace_id_0": sqltypes.Uint64BindVariable(1), 879 "lu_col_0": sqltypes.Int64BindVariable(5), 880 }, 881 }} 882 assertQueries(t, sbcLookup, lookWant) 883 assertQueries(t, sbc1, wantQueries) 884 assertQueries(t, sbc2, nil) 885 } 886 887 func TestDeleteEqualWithNoVerifyAndWriteOnlyLookupUniqueVindex(t *testing.T) { 888 res := []*sqltypes.Result{sqltypes.MakeTestResult( 889 sqltypes.MakeTestFields( 890 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col", 891 "int64|int64|int64|int64|int64|int64|int64", 892 ), 893 "1|1|1|1|1|1|1", 894 )} 895 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, res) 896 897 _, err := executorExec(executor, "delete from t2_lookup where wo_lu_col = 1", nil) 898 require.NoError(t, err) 899 wantQueries := []*querypb.BoundQuery{ 900 { 901 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col from t2_lookup where wo_lu_col = 1 for update", 902 BindVariables: map[string]*querypb.BindVariable{}, 903 }, { 904 Sql: "delete from t2_lookup where wo_lu_col = 1", 905 BindVariables: map[string]*querypb.BindVariable{}, 906 }} 907 908 bq1 := &querypb.BoundQuery{ 909 Sql: "delete from wo_lu_idx where wo_lu_col = :wo_lu_col and keyspace_id = :keyspace_id", 910 BindVariables: map[string]*querypb.BindVariable{ 911 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 912 "wo_lu_col": sqltypes.Int64BindVariable(1), 913 }, 914 } 915 bq2 := &querypb.BoundQuery{ 916 Sql: "delete from erl_lu_idx where erl_lu_col = :erl_lu_col and keyspace_id = :keyspace_id", 917 BindVariables: map[string]*querypb.BindVariable{ 918 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 919 "erl_lu_col": sqltypes.Int64BindVariable(1), 920 }, 921 } 922 bq3 := &querypb.BoundQuery{ 923 Sql: "delete from srl_lu_idx where srl_lu_col = :srl_lu_col and keyspace_id = :keyspace_id", 924 BindVariables: map[string]*querypb.BindVariable{ 925 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 926 "srl_lu_col": sqltypes.Int64BindVariable(1), 927 }, 928 } 929 bq4 := &querypb.BoundQuery{ 930 Sql: "delete from nrl_lu_idx where nrl_lu_col = :nrl_lu_col and keyspace_id = :keyspace_id", 931 BindVariables: map[string]*querypb.BindVariable{ 932 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 933 "nrl_lu_col": sqltypes.Int64BindVariable(1), 934 }, 935 } 936 bq5 := &querypb.BoundQuery{ 937 Sql: "delete from nv_lu_idx where nv_lu_col = :nv_lu_col and keyspace_id = :keyspace_id", 938 BindVariables: map[string]*querypb.BindVariable{ 939 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 940 "nv_lu_col": sqltypes.Int64BindVariable(1), 941 }, 942 } 943 bq6 := &querypb.BoundQuery{ 944 Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", 945 BindVariables: map[string]*querypb.BindVariable{ 946 "keyspace_id": sqltypes.Uint64BindVariable(1), 947 "lu_col": sqltypes.Int64BindVariable(1), 948 }, 949 } 950 lookWant := []*querypb.BoundQuery{ 951 bq1, bq2, bq3, bq4, bq5, bq6, 952 bq1, bq2, bq3, bq4, bq5, bq6, 953 bq1, bq2, bq3, bq4, bq5, bq6, 954 bq1, bq2, bq3, bq4, bq5, bq6, 955 bq1, bq2, bq3, bq4, bq5, bq6, 956 bq1, bq2, bq3, bq4, bq5, bq6, 957 bq1, bq2, bq3, bq4, bq5, bq6, 958 bq1, bq2, bq3, bq4, bq5, bq6, 959 } 960 assertQueries(t, sbcLookup, lookWant) 961 assertQueries(t, sbc1, wantQueries) 962 assertQueries(t, sbc2, wantQueries) 963 } 964 965 func TestDeleteEqualWithMultipleLookupVindex(t *testing.T) { 966 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, nil) 967 968 sbcLookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 969 sqltypes.MakeTestFields("lu_col|keyspace_id", "int64|varbinary"), 970 "1|1", 971 )}) 972 973 sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 974 sqltypes.MakeTestFields( 975 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col", 976 "int64|int64|int64|int64|int64|int64|int64", 977 ), 978 "1|1|1|1|1|1|1", 979 )}) 980 981 _, err := executorExec(executor, "delete from t2_lookup where wo_lu_col = 1 and lu_col = 1", nil) 982 require.NoError(t, err) 983 wantQueries := []*querypb.BoundQuery{ 984 { 985 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col from t2_lookup where wo_lu_col = 1 and lu_col = 1 for update", 986 BindVariables: map[string]*querypb.BindVariable{}, 987 }, { 988 Sql: "delete from t2_lookup where wo_lu_col = 1 and lu_col = 1", 989 BindVariables: map[string]*querypb.BindVariable{}, 990 }} 991 992 vars, _ := sqltypes.BuildBindVariable([]any{ 993 sqltypes.NewInt64(1), 994 }) 995 lookWant := []*querypb.BoundQuery{{ 996 Sql: "select lu_col, keyspace_id from lu_idx where lu_col in ::lu_col for update", 997 BindVariables: map[string]*querypb.BindVariable{ 998 "lu_col": vars, 999 }, 1000 }, { 1001 Sql: "delete from wo_lu_idx where wo_lu_col = :wo_lu_col and keyspace_id = :keyspace_id", 1002 BindVariables: map[string]*querypb.BindVariable{ 1003 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1004 "wo_lu_col": sqltypes.Int64BindVariable(1), 1005 }, 1006 }, { 1007 Sql: "delete from erl_lu_idx where erl_lu_col = :erl_lu_col and keyspace_id = :keyspace_id", 1008 BindVariables: map[string]*querypb.BindVariable{ 1009 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1010 "erl_lu_col": sqltypes.Int64BindVariable(1), 1011 }, 1012 }, { 1013 Sql: "delete from srl_lu_idx where srl_lu_col = :srl_lu_col and keyspace_id = :keyspace_id", 1014 BindVariables: map[string]*querypb.BindVariable{ 1015 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1016 "srl_lu_col": sqltypes.Int64BindVariable(1), 1017 }, 1018 }, { 1019 Sql: "delete from nrl_lu_idx where nrl_lu_col = :nrl_lu_col and keyspace_id = :keyspace_id", 1020 BindVariables: map[string]*querypb.BindVariable{ 1021 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1022 "nrl_lu_col": sqltypes.Int64BindVariable(1), 1023 }, 1024 }, { 1025 Sql: "delete from nv_lu_idx where nv_lu_col = :nv_lu_col and keyspace_id = :keyspace_id", 1026 BindVariables: map[string]*querypb.BindVariable{ 1027 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1028 "nv_lu_col": sqltypes.Int64BindVariable(1), 1029 }, 1030 }, { 1031 Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", 1032 BindVariables: map[string]*querypb.BindVariable{ 1033 "keyspace_id": sqltypes.Uint64BindVariable(1), 1034 "lu_col": {Type: querypb.Type_INT64, Value: []byte("1")}, 1035 }, 1036 }} 1037 assertQueries(t, sbcLookup, lookWant) 1038 1039 assertQueries(t, sbc1, wantQueries) 1040 assertQueries(t, sbc2, nil) 1041 } 1042 1043 func TestDeleteUseHigherCostVindexIfBackfilling(t *testing.T) { 1044 executor, sbc1, sbc2, sbcLookup := createCustomExecutorSetValues(executorVSchema, nil) 1045 1046 sbcLookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 1047 sqltypes.MakeTestFields("lu_col|keyspace_id", "int64|varbinary"), 1048 "1|1", 1049 "2|1", 1050 )}) 1051 1052 sbc1.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 1053 sqltypes.MakeTestFields( 1054 "id|wo_lu_col|erl_lu_col|srl_lu_col|nrl_lu_col|nv_lu_col|lu_col", 1055 "int64|int64|int64|int64|int64|int64|int64", 1056 ), 1057 "1|1|1|1|1|1|1", 1058 "1|1|1|1|1|1|2", 1059 )}) 1060 1061 _, err := executorExec(executor, "delete from t2_lookup where wo_lu_col = 1 and lu_col in (1, 2)", nil) 1062 require.NoError(t, err) 1063 wantQueries := []*querypb.BoundQuery{ 1064 { 1065 Sql: "select id, wo_lu_col, erl_lu_col, srl_lu_col, nrl_lu_col, nv_lu_col, lu_col from t2_lookup where wo_lu_col = 1 and lu_col in (1, 2) for update", 1066 BindVariables: map[string]*querypb.BindVariable{}, 1067 }, { 1068 Sql: "delete from t2_lookup where wo_lu_col = 1 and lu_col in (1, 2)", 1069 BindVariables: map[string]*querypb.BindVariable{}, 1070 }} 1071 1072 vars, _ := sqltypes.BuildBindVariable([]any{ 1073 sqltypes.NewInt64(1), 1074 sqltypes.NewInt64(2), 1075 }) 1076 lookWant := []*querypb.BoundQuery{{ 1077 Sql: "select lu_col, keyspace_id from lu_idx where lu_col in ::lu_col for update", 1078 BindVariables: map[string]*querypb.BindVariable{ 1079 "lu_col": vars, 1080 }, 1081 }, { 1082 Sql: "delete from wo_lu_idx where wo_lu_col = :wo_lu_col and keyspace_id = :keyspace_id", 1083 BindVariables: map[string]*querypb.BindVariable{ 1084 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1085 "wo_lu_col": sqltypes.Int64BindVariable(1), 1086 }, 1087 }, { 1088 Sql: "delete from erl_lu_idx where erl_lu_col = :erl_lu_col and keyspace_id = :keyspace_id", 1089 BindVariables: map[string]*querypb.BindVariable{ 1090 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1091 "erl_lu_col": sqltypes.Int64BindVariable(1), 1092 }, 1093 }, { 1094 Sql: "delete from srl_lu_idx where srl_lu_col = :srl_lu_col and keyspace_id = :keyspace_id", 1095 BindVariables: map[string]*querypb.BindVariable{ 1096 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1097 "srl_lu_col": sqltypes.Int64BindVariable(1), 1098 }, 1099 }, { 1100 Sql: "delete from nrl_lu_idx where nrl_lu_col = :nrl_lu_col and keyspace_id = :keyspace_id", 1101 BindVariables: map[string]*querypb.BindVariable{ 1102 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1103 "nrl_lu_col": sqltypes.Int64BindVariable(1), 1104 }, 1105 }, { 1106 Sql: "delete from nv_lu_idx where nv_lu_col = :nv_lu_col and keyspace_id = :keyspace_id", 1107 BindVariables: map[string]*querypb.BindVariable{ 1108 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1109 "nv_lu_col": sqltypes.Int64BindVariable(1), 1110 }, 1111 }, { 1112 Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", 1113 BindVariables: map[string]*querypb.BindVariable{ 1114 "keyspace_id": sqltypes.Uint64BindVariable(1), 1115 "lu_col": sqltypes.Int64BindVariable(1), 1116 }, 1117 }, { 1118 Sql: "delete from wo_lu_idx where wo_lu_col = :wo_lu_col and keyspace_id = :keyspace_id", 1119 BindVariables: map[string]*querypb.BindVariable{ 1120 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1121 "wo_lu_col": sqltypes.Int64BindVariable(1), 1122 }, 1123 }, { 1124 Sql: "delete from erl_lu_idx where erl_lu_col = :erl_lu_col and keyspace_id = :keyspace_id", 1125 BindVariables: map[string]*querypb.BindVariable{ 1126 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1127 "erl_lu_col": sqltypes.Int64BindVariable(1), 1128 }, 1129 }, { 1130 Sql: "delete from srl_lu_idx where srl_lu_col = :srl_lu_col and keyspace_id = :keyspace_id", 1131 BindVariables: map[string]*querypb.BindVariable{ 1132 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1133 "srl_lu_col": sqltypes.Int64BindVariable(1), 1134 }, 1135 }, { 1136 Sql: "delete from nrl_lu_idx where nrl_lu_col = :nrl_lu_col and keyspace_id = :keyspace_id", 1137 BindVariables: map[string]*querypb.BindVariable{ 1138 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1139 "nrl_lu_col": sqltypes.Int64BindVariable(1), 1140 }, 1141 }, { 1142 Sql: "delete from nv_lu_idx where nv_lu_col = :nv_lu_col and keyspace_id = :keyspace_id", 1143 BindVariables: map[string]*querypb.BindVariable{ 1144 "keyspace_id": {Type: querypb.Type_VARBINARY, Value: []byte("\x16k@\xb4J\xbaK\xd6")}, 1145 "nv_lu_col": sqltypes.Int64BindVariable(1), 1146 }, 1147 }, { 1148 Sql: "delete from lu_idx where lu_col = :lu_col and keyspace_id = :keyspace_id", 1149 BindVariables: map[string]*querypb.BindVariable{ 1150 "keyspace_id": sqltypes.Uint64BindVariable(1), 1151 "lu_col": sqltypes.Int64BindVariable(2), 1152 }, 1153 }} 1154 assertQueries(t, sbcLookup, lookWant) 1155 1156 assertQueries(t, sbc1, wantQueries) 1157 assertQueries(t, sbc2, nil) 1158 } 1159 1160 func TestDeleteByDestination(t *testing.T) { 1161 executor, sbc1, sbc2, _ := createExecutorEnv() 1162 // This query is not supported in v3, so we know for sure is taking the DeleteByDestination route 1163 _, err := executorExec(executor, "delete from `TestExecutor[-]`.user_extra limit 10", nil) 1164 require.NoError(t, err) 1165 // Queries get annotatted. 1166 wantQueries := []*querypb.BoundQuery{{ 1167 Sql: "delete from user_extra limit 10", 1168 BindVariables: map[string]*querypb.BindVariable{}, 1169 }} 1170 assertQueries(t, sbc1, wantQueries) 1171 assertQueries(t, sbc2, wantQueries) 1172 } 1173 1174 func TestDeleteComments(t *testing.T) { 1175 executor, sbc, _, sbclookup := createExecutorEnv() 1176 1177 sbc.SetResults([]*sqltypes.Result{{ 1178 Fields: []*querypb.Field{ 1179 {Name: "Id", Type: sqltypes.Int64}, 1180 {Name: "name", Type: sqltypes.VarChar}, 1181 }, 1182 RowsAffected: 1, 1183 InsertID: 0, 1184 Rows: [][]sqltypes.Value{{ 1185 sqltypes.NewInt64(1), 1186 sqltypes.NewVarChar("myname"), 1187 }}, 1188 }}) 1189 _, err := executorExec(executor, "delete from user where id = 1 /* trailing */", nil) 1190 require.NoError(t, err) 1191 wantQueries := []*querypb.BoundQuery{{ 1192 Sql: "select Id, `name` from `user` where id = 1 for update /* trailing */", 1193 BindVariables: map[string]*querypb.BindVariable{}, 1194 }, { 1195 Sql: "delete from `user` where id = 1 /* trailing */", 1196 BindVariables: map[string]*querypb.BindVariable{}, 1197 }} 1198 assertQueries(t, sbc, wantQueries) 1199 1200 wantQueries = []*querypb.BoundQuery{{ 1201 Sql: "delete from name_user_map where `name` = :name and user_id = :user_id /* trailing */", 1202 BindVariables: map[string]*querypb.BindVariable{ 1203 "user_id": sqltypes.Uint64BindVariable(1), 1204 "name": sqltypes.ValueBindVariable(sqltypes.NewVarChar("myname")), 1205 }, 1206 }} 1207 assertQueries(t, sbclookup, wantQueries) 1208 } 1209 1210 func TestInsertSharded(t *testing.T) { 1211 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 1212 1213 logChan := QueryLogger.Subscribe("Test") 1214 defer QueryLogger.Unsubscribe(logChan) 1215 1216 _, err := executorExec(executor, "insert into user(id, v, name) values (1, 2, 'myname')", nil) 1217 require.NoError(t, err) 1218 wantQueries := []*querypb.BoundQuery{{ 1219 Sql: "insert into `user`(id, v, `name`) values (:_Id_0, 2, :_name_0)", 1220 BindVariables: map[string]*querypb.BindVariable{ 1221 "_Id_0": sqltypes.Int64BindVariable(1), 1222 "_name_0": sqltypes.StringBindVariable("myname"), 1223 "__seq0": sqltypes.Int64BindVariable(1), 1224 }, 1225 }} 1226 assertQueries(t, sbc1, wantQueries) 1227 assertQueries(t, sbc2, nil) 1228 wantQueries = []*querypb.BoundQuery{{ 1229 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0)", 1230 BindVariables: map[string]*querypb.BindVariable{ 1231 "name_0": sqltypes.StringBindVariable("myname"), 1232 "user_id_0": sqltypes.Uint64BindVariable(1), 1233 }, 1234 }} 1235 assertQueries(t, sbclookup, wantQueries) 1236 1237 testQueryLog(t, logChan, "MarkSavepoint", "SAVEPOINT", "savepoint x", 0) 1238 testQueryLog(t, logChan, "VindexCreate", "INSERT", "insert into name_user_map(name, user_id) values(:name_0, :user_id_0)", 1) 1239 testQueryLog(t, logChan, "TestExecute", "INSERT", "insert into user(id, v, name) values (1, 2, 'myname')", 1) 1240 1241 sbc1.Queries = nil 1242 sbclookup.Queries = nil 1243 _, err = executorExec(executor, "insert into user(id, v, name) values (3, 2, 'myname2')", nil) 1244 require.NoError(t, err) 1245 wantQueries = []*querypb.BoundQuery{{ 1246 Sql: "insert into `user`(id, v, `name`) values (:_Id_0, 2, :_name_0)", 1247 BindVariables: map[string]*querypb.BindVariable{ 1248 "_Id_0": sqltypes.Int64BindVariable(3), 1249 "__seq0": sqltypes.Int64BindVariable(3), 1250 "_name_0": sqltypes.StringBindVariable("myname2"), 1251 }, 1252 }} 1253 assertQueries(t, sbc2, wantQueries) 1254 assertQueries(t, sbc1, nil) 1255 wantQueries = []*querypb.BoundQuery{{ 1256 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0)", 1257 BindVariables: map[string]*querypb.BindVariable{ 1258 "name_0": sqltypes.StringBindVariable("myname2"), 1259 "user_id_0": sqltypes.Uint64BindVariable(3), 1260 }, 1261 }} 1262 assertQueries(t, sbclookup, wantQueries) 1263 testQueryLog(t, logChan, "MarkSavepoint", "SAVEPOINT", "savepoint x", 2) 1264 testQueryLog(t, logChan, "VindexCreate", "INSERT", "insert into name_user_map(name, user_id) values(:name_0, :user_id_0)", 1) 1265 testQueryLog(t, logChan, "TestExecute", "INSERT", "insert into user(id, v, name) values (3, 2, 'myname2')", 1) 1266 1267 sbc1.Queries = nil 1268 _, err = executorExec(executor, "insert into user2(id, name, lastname) values (2, 'myname', 'mylastname')", nil) 1269 require.NoError(t, err) 1270 wantQueries = []*querypb.BoundQuery{{ 1271 Sql: "insert into user2(id, `name`, lastname) values (:_id_0, :_name_0, :_lastname_0)", 1272 BindVariables: map[string]*querypb.BindVariable{ 1273 "_id_0": sqltypes.Int64BindVariable(2), 1274 "_name_0": sqltypes.StringBindVariable("myname"), 1275 "_lastname_0": sqltypes.StringBindVariable("mylastname"), 1276 }, 1277 }} 1278 assertQueries(t, sbc1, wantQueries) 1279 testQueryLog(t, logChan, "MarkSavepoint", "SAVEPOINT", "savepoint x", 3) 1280 testQueryLog(t, logChan, "VindexCreate", "INSERT", "insert into name_lastname_keyspace_id_map(name, lastname, keyspace_id) values(:name_0, :lastname_0, :keyspace_id_0)", 1) 1281 testQueryLog(t, logChan, "TestExecute", "INSERT", "insert into user2(id, name, lastname) values (2, 'myname', 'mylastname')", 1) 1282 1283 // insert with binary values 1284 executor.normalize = true 1285 sbc1.Queries = nil 1286 sbc2.Queries = nil 1287 sbclookup.Queries = nil 1288 _, err = executorExec(executor, "insert into user(id, v, name) values (1, 2, _binary 'myname')", nil) 1289 require.NoError(t, err) 1290 wantQueries = []*querypb.BoundQuery{{ 1291 Sql: "insert into `user`(id, v, `name`) values (:_Id_0, :vtg2, :_name_0)", 1292 BindVariables: map[string]*querypb.BindVariable{ 1293 "_Id_0": sqltypes.Int64BindVariable(1), 1294 "_name_0": sqltypes.BytesBindVariable([]byte("myname")), 1295 "__seq0": sqltypes.Int64BindVariable(1), 1296 "vtg1": sqltypes.Int64BindVariable(1), 1297 "vtg2": sqltypes.Int64BindVariable(2), 1298 "vtg3": sqltypes.StringBindVariable("myname"), 1299 }, 1300 }} 1301 assertQueries(t, sbc1, wantQueries) 1302 assertQueries(t, sbc2, nil) 1303 wantQueries = []*querypb.BoundQuery{{ 1304 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0)", 1305 BindVariables: map[string]*querypb.BindVariable{ 1306 "name_0": sqltypes.BytesBindVariable([]byte("myname")), 1307 "user_id_0": sqltypes.Uint64BindVariable(1), 1308 }, 1309 }} 1310 assertQueries(t, sbclookup, wantQueries) 1311 1312 testQueryLog(t, logChan, "MarkSavepoint", "SAVEPOINT", "savepoint x", 3) 1313 testQueryLog(t, logChan, "VindexCreate", "INSERT", "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0)", 1) 1314 testQueryLog(t, logChan, "TestExecute", "INSERT", "insert into `user`(id, v, `name`) values (:vtg1, :vtg2, _binary :vtg3)", 1) 1315 } 1316 1317 func TestInsertShardedKeyrange(t *testing.T) { 1318 executor, _, _, _ := createExecutorEnv() 1319 1320 // If a unique vindex returns a keyrange, we fail the insert 1321 _, err := executorExec(executor, "insert into keyrange_table(krcol_unique, krcol) values(1, 1)", nil) 1322 require.EqualError(t, err, "could not map [INT64(1)] to a unique keyspace id: DestinationKeyRange(-10)") 1323 } 1324 1325 func TestInsertShardedAutocommitLookup(t *testing.T) { 1326 1327 vschema := ` 1328 { 1329 "sharded": true, 1330 "vindexes": { 1331 "hash_index": { 1332 "type": "hash" 1333 }, 1334 "name_user_map": { 1335 "type": "lookup_hash", 1336 "owner": "user", 1337 "params": { 1338 "table": "name_user_map", 1339 "from": "name", 1340 "to": "user_id", 1341 "autocommit": "true" 1342 } 1343 }, 1344 "music_user_map": { 1345 "type": "lookup_hash", 1346 "owner": "user", 1347 "params": { 1348 "table": "music_user_map", 1349 "from": "music", 1350 "to": "user_id", 1351 "multi_shard_autocommit": "true" 1352 } 1353 } 1354 }, 1355 "tables": { 1356 "user": { 1357 "column_vindexes": [ 1358 { 1359 "column": "Id", 1360 "name": "hash_index" 1361 }, 1362 { 1363 "column": "name", 1364 "name": "name_user_map" 1365 }, 1366 { 1367 "column": "music", 1368 "name": "music_user_map" 1369 } 1370 ], 1371 "auto_increment": { 1372 "column": "id", 1373 "sequence": "user_seq" 1374 }, 1375 "columns": [ 1376 { 1377 "name": "textcol", 1378 "type": "VARCHAR" 1379 } 1380 ] 1381 } 1382 } 1383 } 1384 ` 1385 executor, sbc1, sbc2, sbclookup := createCustomExecutor(vschema) 1386 1387 _, err := executorExecSession(executor, "insert into user(id, v, name, music) values (1, 2, 'myname', 'star')", nil, &vtgatepb.Session{}) 1388 require.NoError(t, err) 1389 wantQueries := []*querypb.BoundQuery{{ 1390 Sql: "insert into `user`(id, v, `name`, music) values (:_Id_0, 2, :_name_0, :_music_0)", 1391 BindVariables: map[string]*querypb.BindVariable{ 1392 "_Id_0": sqltypes.Int64BindVariable(1), 1393 "_music_0": sqltypes.StringBindVariable("star"), 1394 "_name_0": sqltypes.StringBindVariable("myname"), 1395 "__seq0": sqltypes.Int64BindVariable(1), 1396 }, 1397 }} 1398 assertQueries(t, sbc1, wantQueries) 1399 assertQueries(t, sbc2, nil) 1400 wantQueries = []*querypb.BoundQuery{{ 1401 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0) on duplicate key update `name` = values(`name`), user_id = values(user_id)", 1402 BindVariables: map[string]*querypb.BindVariable{ 1403 "name_0": sqltypes.StringBindVariable("myname"), 1404 "user_id_0": sqltypes.Uint64BindVariable(1), 1405 }, 1406 }, { 1407 Sql: "insert /*vt+ MULTI_SHARD_AUTOCOMMIT=1 */ into music_user_map(music, user_id) values (:music_0, :user_id_0) on duplicate key update music = values(music), user_id = values(user_id)", 1408 BindVariables: map[string]*querypb.BindVariable{ 1409 "music_0": sqltypes.StringBindVariable("star"), 1410 "user_id_0": sqltypes.Uint64BindVariable(1), 1411 }, 1412 }} 1413 // autocommit should go as ExecuteBatch 1414 assertQueries(t, sbclookup, wantQueries) 1415 } 1416 1417 func TestInsertShardedIgnore(t *testing.T) { 1418 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 1419 1420 // Build the sequence of responses for sbclookup. This should 1421 // match the sequence of queries we validate below. 1422 fields := sqltypes.MakeTestFields("b|a", "int64|int64") 1423 field := sqltypes.MakeTestFields("a", "int64") 1424 sbclookup.SetResults([]*sqltypes.Result{ 1425 // select music_id 1426 sqltypes.MakeTestResult(fields, "1|1", "3|1", "4|1", "5|1", "6|3"), 1427 // insert ins_lookup 1428 {}, 1429 // select ins_lookup 1 1430 sqltypes.MakeTestResult(field, "1"), 1431 // select ins_lookup 3 1432 {}, 1433 // select ins_lookup 4 1434 sqltypes.MakeTestResult(field, "4"), 1435 // select ins_lookup 5 1436 sqltypes.MakeTestResult(field, "5"), 1437 // select ins_lookup 6 1438 sqltypes.MakeTestResult(field, "6"), 1439 }) 1440 // First row: first shard. 1441 // Second row: will fail because primary vindex will fail to map. 1442 // Third row: will fail because verification will fail on owned vindex after Create. 1443 // Fourth row: will fail because verification will fail on unowned hash vindex. 1444 // Fifth row: first shard. 1445 // Sixth row: second shard (because 3 hash maps to 40-60). 1446 query := "insert ignore into insert_ignore_test(pv, owned, verify) values (1, 1, 1), (2, 2, 2), (3, 3, 1), (4, 4, 4), (5, 5, 1), (6, 6, 3)" 1447 _, err := executorExec(executor, query, nil) 1448 require.NoError(t, err) 1449 wantQueries := []*querypb.BoundQuery{{ 1450 Sql: "insert ignore into insert_ignore_test(pv, owned, verify) values (:_pv_0, :_owned_0, :_verify_0),(:_pv_4, :_owned_4, :_verify_4)", 1451 BindVariables: map[string]*querypb.BindVariable{ 1452 "_pv_0": sqltypes.Int64BindVariable(1), 1453 "_pv_4": sqltypes.Int64BindVariable(5), 1454 "_pv_5": sqltypes.Int64BindVariable(6), 1455 "_owned_0": sqltypes.Int64BindVariable(1), 1456 "_owned_4": sqltypes.Int64BindVariable(5), 1457 "_owned_5": sqltypes.Int64BindVariable(6), 1458 "_verify_0": sqltypes.Int64BindVariable(1), 1459 "_verify_4": sqltypes.Int64BindVariable(1), 1460 "_verify_5": sqltypes.Int64BindVariable(3), 1461 }, 1462 }} 1463 assertQueries(t, sbc1, wantQueries) 1464 wantQueries = []*querypb.BoundQuery{{ 1465 Sql: "insert ignore into insert_ignore_test(pv, owned, verify) values (:_pv_5, :_owned_5, :_verify_5)", 1466 BindVariables: map[string]*querypb.BindVariable{ 1467 "_pv_0": sqltypes.Int64BindVariable(1), 1468 "_pv_4": sqltypes.Int64BindVariable(5), 1469 "_pv_5": sqltypes.Int64BindVariable(6), 1470 "_owned_0": sqltypes.Int64BindVariable(1), 1471 "_owned_4": sqltypes.Int64BindVariable(5), 1472 "_owned_5": sqltypes.Int64BindVariable(6), 1473 "_verify_0": sqltypes.Int64BindVariable(1), 1474 "_verify_4": sqltypes.Int64BindVariable(1), 1475 "_verify_5": sqltypes.Int64BindVariable(3), 1476 }, 1477 }} 1478 assertQueries(t, sbc2, wantQueries) 1479 1480 vars, err := sqltypes.BuildBindVariable([]any{ 1481 sqltypes.NewInt64(1), 1482 sqltypes.NewInt64(2), 1483 sqltypes.NewInt64(3), 1484 sqltypes.NewInt64(4), 1485 sqltypes.NewInt64(5), 1486 sqltypes.NewInt64(6), 1487 }) 1488 require.NoError(t, err) 1489 wantQueries = []*querypb.BoundQuery{{ 1490 Sql: "select music_id, user_id from music_user_map where music_id in ::music_id for update", 1491 BindVariables: map[string]*querypb.BindVariable{ 1492 "music_id": vars, 1493 }, 1494 }, { 1495 Sql: "insert ignore into ins_lookup(fromcol, tocol) values (:fromcol_0, :tocol_0), (:fromcol_1, :tocol_1), (:fromcol_2, :tocol_2), (:fromcol_3, :tocol_3), (:fromcol_4, :tocol_4)", 1496 BindVariables: map[string]*querypb.BindVariable{ 1497 "fromcol_0": sqltypes.Int64BindVariable(1), 1498 "tocol_0": sqltypes.Uint64BindVariable(1), 1499 "fromcol_1": sqltypes.Int64BindVariable(3), 1500 "tocol_1": sqltypes.Uint64BindVariable(1), 1501 "fromcol_2": sqltypes.Int64BindVariable(4), 1502 "tocol_2": sqltypes.Uint64BindVariable(1), 1503 "fromcol_3": sqltypes.Int64BindVariable(5), 1504 "tocol_3": sqltypes.Uint64BindVariable(1), 1505 "fromcol_4": sqltypes.Int64BindVariable(6), 1506 "tocol_4": sqltypes.Uint64BindVariable(3), 1507 }, 1508 }, { 1509 Sql: "select fromcol from ins_lookup where fromcol = :fromcol and tocol = :tocol", 1510 BindVariables: map[string]*querypb.BindVariable{ 1511 "fromcol": sqltypes.Int64BindVariable(1), 1512 "tocol": sqltypes.Uint64BindVariable(1), 1513 }, 1514 }, { 1515 Sql: "select fromcol from ins_lookup where fromcol = :fromcol and tocol = :tocol", 1516 BindVariables: map[string]*querypb.BindVariable{ 1517 "fromcol": sqltypes.Int64BindVariable(3), 1518 "tocol": sqltypes.Uint64BindVariable(1), 1519 }, 1520 }, { 1521 Sql: "select fromcol from ins_lookup where fromcol = :fromcol and tocol = :tocol", 1522 BindVariables: map[string]*querypb.BindVariable{ 1523 "fromcol": sqltypes.Int64BindVariable(4), 1524 "tocol": sqltypes.Uint64BindVariable(1), 1525 }, 1526 }, { 1527 Sql: "select fromcol from ins_lookup where fromcol = :fromcol and tocol = :tocol", 1528 BindVariables: map[string]*querypb.BindVariable{ 1529 "fromcol": sqltypes.Int64BindVariable(5), 1530 "tocol": sqltypes.Uint64BindVariable(1), 1531 }, 1532 }, { 1533 Sql: "select fromcol from ins_lookup where fromcol = :fromcol and tocol = :tocol", 1534 BindVariables: map[string]*querypb.BindVariable{ 1535 "fromcol": sqltypes.Int64BindVariable(6), 1536 "tocol": sqltypes.Uint64BindVariable(3), 1537 }, 1538 }} 1539 assertQueries(t, sbclookup, wantQueries) 1540 1541 // Test the 0 rows case, 1542 sbc1.Queries = nil 1543 sbc2.Queries = nil 1544 sbclookup.Queries = nil 1545 sbclookup.SetResults([]*sqltypes.Result{ 1546 {}, 1547 }) 1548 query = "insert ignore into insert_ignore_test(pv, owned, verify) values (1, 1, 1)" 1549 qr, err := executorExec(executor, query, nil) 1550 require.NoError(t, err) 1551 if !qr.Equal(&sqltypes.Result{}) { 1552 t.Errorf("qr: %v, want empty result", qr) 1553 } 1554 assertQueries(t, sbc1, nil) 1555 assertQueries(t, sbc2, nil) 1556 vars, err = sqltypes.BuildBindVariable([]any{sqltypes.NewInt64(1)}) 1557 require.NoError(t, err) 1558 wantQueries = []*querypb.BoundQuery{{ 1559 Sql: "select music_id, user_id from music_user_map where music_id in ::music_id for update", 1560 BindVariables: map[string]*querypb.BindVariable{ 1561 "music_id": vars, 1562 }, 1563 }} 1564 assertQueries(t, sbclookup, wantQueries) 1565 } 1566 1567 func TestInsertOnDupKey(t *testing.T) { 1568 // This test just sanity checks that the statement is getting passed through 1569 // correctly. The full set of use cases are covered by TestInsertShardedIgnore. 1570 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 1571 sbclookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 1572 sqltypes.MakeTestFields("b|a", "int64|varbinary"), 1573 "1|1", 1574 )}) 1575 query := "insert into insert_ignore_test(pv, owned, verify) values (1, 1, 1) on duplicate key update col = 2" 1576 _, err := executorExec(executor, query, nil) 1577 require.NoError(t, err) 1578 wantQueries := []*querypb.BoundQuery{{ 1579 Sql: "insert into insert_ignore_test(pv, owned, verify) values (:_pv_0, :_owned_0, :_verify_0) on duplicate key update col = 2", 1580 BindVariables: map[string]*querypb.BindVariable{ 1581 "_pv_0": sqltypes.Int64BindVariable(1), 1582 "_owned_0": sqltypes.Int64BindVariable(1), 1583 "_verify_0": sqltypes.Int64BindVariable(1), 1584 }, 1585 }} 1586 assertQueries(t, sbc1, wantQueries) 1587 assertQueries(t, sbc2, nil) 1588 vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewInt64(1)}) 1589 require.NoError(t, err) 1590 wantQueries = []*querypb.BoundQuery{{ 1591 Sql: "select music_id, user_id from music_user_map where music_id in ::music_id for update", 1592 BindVariables: map[string]*querypb.BindVariable{ 1593 "music_id": vars, 1594 }, 1595 }, { 1596 Sql: "insert ignore into ins_lookup(fromcol, tocol) values (:fromcol_0, :tocol_0)", 1597 BindVariables: map[string]*querypb.BindVariable{ 1598 "fromcol_0": sqltypes.Int64BindVariable(1), 1599 "tocol_0": sqltypes.Uint64BindVariable(1), 1600 }, 1601 }, { 1602 Sql: "select fromcol from ins_lookup where fromcol = :fromcol and tocol = :tocol", 1603 BindVariables: map[string]*querypb.BindVariable{ 1604 "fromcol": sqltypes.Int64BindVariable(1), 1605 "tocol": sqltypes.Uint64BindVariable(1), 1606 }, 1607 }} 1608 assertQueries(t, sbclookup, wantQueries) 1609 } 1610 1611 func TestAutocommitFail(t *testing.T) { 1612 executor, sbc1, _, _ := createExecutorEnv() 1613 1614 query := "insert into user (id) values (1)" 1615 sbc1.MustFailCodes[vtrpcpb.Code_ALREADY_EXISTS] = 1 1616 primarySession.Reset() 1617 primarySession.Autocommit = true 1618 defer func() { 1619 primarySession.Autocommit = false 1620 }() 1621 _, err := executorExec(executor, query, nil) 1622 require.Error(t, err) 1623 1624 // make sure we have closed and rolled back any transactions started 1625 assert.False(t, primarySession.InTransaction, "left with tx open") 1626 } 1627 1628 func TestInsertComments(t *testing.T) { 1629 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 1630 1631 _, err := executorExec(executor, "insert into user(id, v, name) values (1, 2, 'myname') /* trailing */", nil) 1632 require.NoError(t, err) 1633 wantQueries := []*querypb.BoundQuery{{ 1634 Sql: "insert into `user`(id, v, `name`) values (:_Id_0, 2, :_name_0) /* trailing */", 1635 BindVariables: map[string]*querypb.BindVariable{ 1636 "_Id_0": sqltypes.Int64BindVariable(1), 1637 "_name_0": sqltypes.StringBindVariable("myname"), 1638 "__seq0": sqltypes.Int64BindVariable(1), 1639 }, 1640 }} 1641 assertQueries(t, sbc1, wantQueries) 1642 assertQueries(t, sbc2, nil) 1643 wantQueries = []*querypb.BoundQuery{{ 1644 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0) /* trailing */", 1645 BindVariables: map[string]*querypb.BindVariable{ 1646 "name_0": sqltypes.StringBindVariable("myname"), 1647 "user_id_0": sqltypes.Uint64BindVariable(1), 1648 }, 1649 }} 1650 assertQueries(t, sbclookup, wantQueries) 1651 } 1652 1653 func TestInsertGeneratorSharded(t *testing.T) { 1654 executor, sbc, _, sbclookup := createExecutorEnv() 1655 1656 sbclookup.SetResults([]*sqltypes.Result{{ 1657 Rows: [][]sqltypes.Value{{ 1658 sqltypes.NewInt64(1), 1659 }}, 1660 RowsAffected: 1, 1661 InsertID: 1, 1662 }}) 1663 result, err := executorExec(executor, "insert into user(v, `name`) values (2, 'myname')", nil) 1664 require.NoError(t, err) 1665 wantQueries := []*querypb.BoundQuery{{ 1666 Sql: "insert into `user`(v, `name`, id) values (2, :_name_0, :_Id_0)", 1667 BindVariables: map[string]*querypb.BindVariable{ 1668 "_Id_0": sqltypes.Int64BindVariable(1), 1669 "__seq0": sqltypes.Int64BindVariable(1), 1670 "_name_0": sqltypes.StringBindVariable("myname"), 1671 }, 1672 }} 1673 assertQueries(t, sbc, wantQueries) 1674 wantQueries = []*querypb.BoundQuery{{ 1675 Sql: "select next :n values from user_seq", 1676 BindVariables: map[string]*querypb.BindVariable{"n": sqltypes.Int64BindVariable(1)}, 1677 }, { 1678 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0)", 1679 BindVariables: map[string]*querypb.BindVariable{ 1680 "name_0": sqltypes.StringBindVariable("myname"), 1681 "user_id_0": sqltypes.Uint64BindVariable(1), 1682 }, 1683 }} 1684 assertQueries(t, sbclookup, wantQueries) 1685 wantResult := &sqltypes.Result{ 1686 InsertID: 1, 1687 RowsAffected: 1, 1688 } 1689 utils.MustMatch(t, wantResult, result) 1690 } 1691 1692 func TestInsertAutoincSharded(t *testing.T) { 1693 router, sbc, _, _ := createExecutorEnv() 1694 1695 // Fake a mysql auto-inc response. 1696 wantResult := &sqltypes.Result{ 1697 Rows: [][]sqltypes.Value{{ 1698 sqltypes.NewInt64(1), 1699 }}, 1700 RowsAffected: 1, 1701 InsertID: 2, 1702 } 1703 sbc.SetResults([]*sqltypes.Result{wantResult}) 1704 result, err := executorExec(router, "insert into user_extra(user_id) values (2)", nil) 1705 require.NoError(t, err) 1706 wantQueries := []*querypb.BoundQuery{{ 1707 Sql: "insert into user_extra(user_id) values (:_user_id_0)", 1708 BindVariables: map[string]*querypb.BindVariable{ 1709 "_user_id_0": sqltypes.Int64BindVariable(2), 1710 }, 1711 }} 1712 assertQueries(t, sbc, wantQueries) 1713 if !result.Equal(wantResult) { 1714 t.Errorf("result: %+v, want %+v", result, wantResult) 1715 } 1716 assert.EqualValues(t, 2, primarySession.LastInsertId) 1717 } 1718 1719 func TestInsertGeneratorUnsharded(t *testing.T) { 1720 executor, _, _, sbclookup := createExecutorEnv() 1721 result, err := executorExec(executor, "insert into main1(id, name) values (null, 'myname')", nil) 1722 require.NoError(t, err) 1723 wantQueries := []*querypb.BoundQuery{{ 1724 Sql: "select next :n values from user_seq", 1725 BindVariables: map[string]*querypb.BindVariable{"n": sqltypes.Int64BindVariable(1)}, 1726 }, { 1727 Sql: "insert into main1(id, `name`) values (:__seq0, 'myname')", 1728 BindVariables: map[string]*querypb.BindVariable{ 1729 "__seq0": sqltypes.Int64BindVariable(1), 1730 }, 1731 }} 1732 assertQueries(t, sbclookup, wantQueries) 1733 wantResult := &sqltypes.Result{ 1734 InsertID: 1, 1735 RowsAffected: 1, 1736 } 1737 utils.MustMatch(t, wantResult, result) 1738 } 1739 1740 func TestInsertAutoincUnsharded(t *testing.T) { 1741 router, _, _, sbclookup := createExecutorEnv() 1742 1743 logChan := QueryLogger.Subscribe("Test") 1744 defer QueryLogger.Unsubscribe(logChan) 1745 1746 // Fake a mysql auto-inc response. 1747 query := "insert into `simple`(val) values ('val')" 1748 wantResult := &sqltypes.Result{ 1749 Rows: [][]sqltypes.Value{{ 1750 sqltypes.NewInt64(1), 1751 }}, 1752 RowsAffected: 1, 1753 InsertID: 2, 1754 } 1755 sbclookup.SetResults([]*sqltypes.Result{wantResult}) 1756 1757 result, err := executorExec(router, query, nil) 1758 require.NoError(t, err) 1759 wantQueries := []*querypb.BoundQuery{{ 1760 Sql: query, 1761 BindVariables: map[string]*querypb.BindVariable{}, 1762 }} 1763 assertQueries(t, sbclookup, wantQueries) 1764 assert.Equal(t, result, wantResult) 1765 1766 testQueryLog(t, logChan, "TestExecute", "INSERT", "insert into `simple`(val) values ('val')", 1) 1767 } 1768 1769 func TestInsertLookupOwned(t *testing.T) { 1770 executor, sbc, _, sbclookup := createExecutorEnv() 1771 1772 _, err := executorExec(executor, "insert into music(user_id, id) values (2, 3)", nil) 1773 require.NoError(t, err) 1774 wantQueries := []*querypb.BoundQuery{{ 1775 Sql: "insert into music(user_id, id) values (:_user_id_0, :_id_0)", 1776 BindVariables: map[string]*querypb.BindVariable{ 1777 "_user_id_0": sqltypes.Int64BindVariable(2), 1778 "_id_0": sqltypes.Int64BindVariable(3), 1779 "__seq0": sqltypes.Int64BindVariable(3), 1780 }, 1781 }} 1782 assertQueries(t, sbc, wantQueries) 1783 wantQueries = []*querypb.BoundQuery{{ 1784 Sql: "insert into music_user_map(music_id, user_id) values (:music_id_0, :user_id_0)", 1785 BindVariables: map[string]*querypb.BindVariable{ 1786 "music_id_0": sqltypes.Int64BindVariable(3), 1787 "user_id_0": sqltypes.Uint64BindVariable(2), 1788 }, 1789 }} 1790 assertQueries(t, sbclookup, wantQueries) 1791 } 1792 1793 func TestInsertLookupOwnedGenerator(t *testing.T) { 1794 executor, sbc, _, sbclookup := createExecutorEnv() 1795 1796 sbclookup.SetResults([]*sqltypes.Result{{ 1797 Rows: [][]sqltypes.Value{{ 1798 sqltypes.NewInt64(4), 1799 }}, 1800 RowsAffected: 1, 1801 InsertID: 1, 1802 }}) 1803 result, err := executorExec(executor, "insert into music(user_id) values (2)", nil) 1804 require.NoError(t, err) 1805 wantQueries := []*querypb.BoundQuery{{ 1806 Sql: "insert into music(user_id, id) values (:_user_id_0, :_id_0)", 1807 BindVariables: map[string]*querypb.BindVariable{ 1808 "_user_id_0": sqltypes.Int64BindVariable(2), 1809 "_id_0": sqltypes.Int64BindVariable(4), 1810 "__seq0": sqltypes.Int64BindVariable(4), 1811 }, 1812 }} 1813 assertQueries(t, sbc, wantQueries) 1814 wantQueries = []*querypb.BoundQuery{{ 1815 Sql: "select next :n values from user_seq", 1816 BindVariables: map[string]*querypb.BindVariable{"n": sqltypes.Int64BindVariable(1)}, 1817 }, { 1818 Sql: "insert into music_user_map(music_id, user_id) values (:music_id_0, :user_id_0)", 1819 BindVariables: map[string]*querypb.BindVariable{ 1820 "music_id_0": sqltypes.Int64BindVariable(4), 1821 "user_id_0": sqltypes.Uint64BindVariable(2), 1822 }, 1823 }} 1824 assertQueries(t, sbclookup, wantQueries) 1825 wantResult := &sqltypes.Result{ 1826 InsertID: 4, 1827 RowsAffected: 1, 1828 } 1829 utils.MustMatch(t, wantResult, result) 1830 } 1831 1832 func TestInsertLookupUnowned(t *testing.T) { 1833 executor, sbc, _, sbclookup := createExecutorEnv() 1834 1835 _, err := executorExec(executor, "insert into music_extra(user_id, music_id) values (2, 3)", nil) 1836 require.NoError(t, err) 1837 wantQueries := []*querypb.BoundQuery{{ 1838 Sql: "insert into music_extra(user_id, music_id) values (:_user_id_0, :_music_id_0)", 1839 BindVariables: map[string]*querypb.BindVariable{ 1840 "_user_id_0": sqltypes.Int64BindVariable(2), 1841 "_music_id_0": sqltypes.Int64BindVariable(3), 1842 }, 1843 }} 1844 assertQueries(t, sbc, wantQueries) 1845 wantQueries = []*querypb.BoundQuery{{ 1846 Sql: "select music_id from music_user_map where music_id = :music_id and user_id = :user_id", 1847 BindVariables: map[string]*querypb.BindVariable{ 1848 "music_id": sqltypes.Int64BindVariable(3), 1849 "user_id": sqltypes.Uint64BindVariable(2), 1850 }, 1851 }} 1852 assertQueries(t, sbclookup, wantQueries) 1853 } 1854 1855 func TestInsertLookupUnownedUnsupplied(t *testing.T) { 1856 executor, sbc, _, sbclookup := createExecutorEnv() 1857 sbclookup.SetResults([]*sqltypes.Result{sqltypes.MakeTestResult( 1858 sqltypes.MakeTestFields("b|a", "int64|varbinary"), 1859 "3|1", 1860 )}) 1861 _, err := executorExec(executor, "insert into music_extra_reversed(music_id) values (3)", nil) 1862 require.NoError(t, err) 1863 wantQueries := []*querypb.BoundQuery{{ 1864 Sql: "insert into music_extra_reversed(music_id, user_id) values (:_music_id_0, :_user_id_0)", 1865 BindVariables: map[string]*querypb.BindVariable{ 1866 "_user_id_0": sqltypes.Uint64BindVariable(1), 1867 "_music_id_0": sqltypes.Int64BindVariable(3), 1868 }, 1869 }} 1870 assertQueries(t, sbc, wantQueries) 1871 vars, err := sqltypes.BuildBindVariable([]any{sqltypes.NewInt64(3)}) 1872 require.NoError(t, err) 1873 wantQueries = []*querypb.BoundQuery{{ 1874 Sql: "select music_id, user_id from music_user_map where music_id in ::music_id for update", 1875 BindVariables: map[string]*querypb.BindVariable{ 1876 "music_id": vars, 1877 }, 1878 }} 1879 assertQueries(t, sbclookup, wantQueries) 1880 } 1881 1882 // If a statement gets broken up into two, and the first one fails, 1883 // then an error should be returned normally. 1884 func TestInsertPartialFail1(t *testing.T) { 1885 executor, _, _, sbclookup := createExecutorEnv() 1886 1887 // Make the first DML fail, there should be no rollback. 1888 sbclookup.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 1889 1890 _, err := executor.Execute( 1891 context.Background(), 1892 "TestExecute", 1893 NewSafeSession(&vtgatepb.Session{InTransaction: true}), 1894 "insert into user(id, v, name) values (1, 2, 'myname')", 1895 nil, 1896 ) 1897 require.Error(t, err) 1898 } 1899 1900 // If a statement gets broken up into two, and the second one fails 1901 // after successful execution of the first, then the transaction must 1902 // be rolled back due to partial execution. 1903 func TestInsertPartialFail2(t *testing.T) { 1904 executor, sbc1, _, _ := createExecutorEnv() 1905 1906 // Make the second DML fail, it should result in a rollback. 1907 sbc1.MustFailExecute[sqlparser.StmtInsert] = 1 1908 1909 safeSession := NewSafeSession(&vtgatepb.Session{InTransaction: true}) 1910 _, err := executor.Execute( 1911 context.Background(), 1912 "TestExecute", 1913 safeSession, 1914 "insert into user(id, v, name) values (1, 2, 'myname')", 1915 nil, 1916 ) 1917 1918 want := "reverted partial DML execution failure" 1919 if err == nil || !strings.HasPrefix(err.Error(), want) { 1920 t.Errorf("insert first DML fail: %v, must start with %s", err, want) 1921 } 1922 1923 assert.True(t, safeSession.InTransaction()) 1924 wantQueries := []*querypb.BoundQuery{ 1925 { 1926 Sql: "savepoint x", 1927 BindVariables: map[string]*querypb.BindVariable{}, 1928 }, { 1929 Sql: "insert into `user`(id, v, `name`) values (:_Id_0, 2, :_name_0)", 1930 BindVariables: map[string]*querypb.BindVariable{ 1931 "_Id_0": sqltypes.Int64BindVariable(1), 1932 "__seq0": sqltypes.Int64BindVariable(1), 1933 "_name_0": sqltypes.StringBindVariable("myname"), 1934 }, 1935 }, { 1936 Sql: "rollback to x", 1937 BindVariables: map[string]*querypb.BindVariable{}, 1938 }} 1939 assertQueriesWithSavepoint(t, sbc1, wantQueries) 1940 } 1941 1942 func TestMultiInsertSharded(t *testing.T) { 1943 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 1944 1945 _, err := executorExec(executor, "insert into user(id, v, name) values (1, 1, 'myname1'),(3, 3, 'myname3')", nil) 1946 require.NoError(t, err) 1947 wantQueries1 := []*querypb.BoundQuery{{ 1948 Sql: "insert into `user`(id, v, `name`) values (:_Id_0, 1, :_name_0)", 1949 BindVariables: map[string]*querypb.BindVariable{ 1950 "_Id_0": sqltypes.Int64BindVariable(1), 1951 "_name_0": sqltypes.StringBindVariable("myname1"), 1952 "__seq0": sqltypes.Int64BindVariable(1), 1953 "_Id_1": sqltypes.Int64BindVariable(3), 1954 "_name_1": sqltypes.StringBindVariable("myname3"), 1955 "__seq1": sqltypes.Int64BindVariable(3), 1956 }, 1957 }} 1958 1959 wantQueries2 := []*querypb.BoundQuery{{ 1960 Sql: "insert into `user`(id, v, `name`) values (:_Id_1, 3, :_name_1)", 1961 BindVariables: map[string]*querypb.BindVariable{ 1962 "_Id_0": sqltypes.Int64BindVariable(1), 1963 "_name_0": sqltypes.StringBindVariable("myname1"), 1964 "__seq0": sqltypes.Int64BindVariable(1), 1965 "_Id_1": sqltypes.Int64BindVariable(3), 1966 "_name_1": sqltypes.StringBindVariable("myname3"), 1967 "__seq1": sqltypes.Int64BindVariable(3), 1968 }, 1969 }} 1970 assertQueries(t, sbc1, wantQueries1) 1971 assertQueries(t, sbc2, wantQueries2) 1972 1973 wantQueries1 = []*querypb.BoundQuery{{ 1974 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0), (:name_1, :user_id_1)", 1975 BindVariables: map[string]*querypb.BindVariable{ 1976 "name_0": sqltypes.StringBindVariable("myname1"), 1977 "user_id_0": sqltypes.Uint64BindVariable(1), 1978 "name_1": sqltypes.StringBindVariable("myname3"), 1979 "user_id_1": sqltypes.Uint64BindVariable(3), 1980 }, 1981 }} 1982 assertQueries(t, sbclookup, wantQueries1) 1983 1984 sbc1.Queries = nil 1985 sbclookup.Queries = nil 1986 sbc2.Queries = nil 1987 _, err = executorExec(executor, "insert into user(id, v, name) values (1, 1, 'myname1'),(2, 2, 'myname2')", nil) 1988 require.NoError(t, err) 1989 wantQueries := []*querypb.BoundQuery{{ 1990 Sql: "insert into `user`(id, v, `name`) values (:_Id_0, 1, :_name_0),(:_Id_1, 2, :_name_1)", 1991 BindVariables: map[string]*querypb.BindVariable{ 1992 "_Id_0": sqltypes.Int64BindVariable(1), 1993 "__seq0": sqltypes.Int64BindVariable(1), 1994 "_name_0": sqltypes.StringBindVariable("myname1"), 1995 "_Id_1": sqltypes.Int64BindVariable(2), 1996 "__seq1": sqltypes.Int64BindVariable(2), 1997 "_name_1": sqltypes.StringBindVariable("myname2"), 1998 }, 1999 }} 2000 2001 assertQueries(t, sbc1, wantQueries) 2002 assertQueries(t, sbc2, nil) 2003 wantQueries = []*querypb.BoundQuery{{ 2004 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0), (:name_1, :user_id_1)", 2005 BindVariables: map[string]*querypb.BindVariable{ 2006 "name_0": sqltypes.StringBindVariable("myname1"), 2007 "user_id_0": sqltypes.Uint64BindVariable(1), 2008 "name_1": sqltypes.StringBindVariable("myname2"), 2009 "user_id_1": sqltypes.Uint64BindVariable(2), 2010 }, 2011 }} 2012 assertQueries(t, sbclookup, wantQueries) 2013 2014 // Insert multiple rows in a multi column vindex 2015 sbc1.Queries = nil 2016 sbclookup.Queries = nil 2017 sbc2.Queries = nil 2018 _, err = executorExec(executor, "insert into user2(id, `name`, lastname) values (2, 'myname', 'mylastname'), (3, 'myname2', 'mylastname2')", nil) 2019 require.NoError(t, err) 2020 wantQueries = []*querypb.BoundQuery{{ 2021 Sql: "insert into user2(id, `name`, lastname) values (:_id_0, :_name_0, :_lastname_0)", 2022 BindVariables: map[string]*querypb.BindVariable{ 2023 "_id_0": sqltypes.Int64BindVariable(2), 2024 "_name_0": sqltypes.StringBindVariable("myname"), 2025 "_lastname_0": sqltypes.StringBindVariable("mylastname"), 2026 "_id_1": sqltypes.Int64BindVariable(3), 2027 "_name_1": sqltypes.StringBindVariable("myname2"), 2028 "_lastname_1": sqltypes.StringBindVariable("mylastname2"), 2029 }, 2030 }} 2031 assertQueries(t, sbc1, wantQueries) 2032 wantQueries = []*querypb.BoundQuery{{ 2033 Sql: "insert into name_lastname_keyspace_id_map(`name`, lastname, keyspace_id) values (:name_0, :lastname_0, :keyspace_id_0), (:name_1, :lastname_1, :keyspace_id_1)", 2034 BindVariables: map[string]*querypb.BindVariable{ 2035 "name_0": sqltypes.StringBindVariable("myname"), 2036 "lastname_0": sqltypes.StringBindVariable("mylastname"), 2037 "keyspace_id_0": sqltypes.BytesBindVariable([]byte("\x06\xe7\xea\"Βp\x8f")), 2038 "name_1": sqltypes.StringBindVariable("myname2"), 2039 "lastname_1": sqltypes.StringBindVariable("mylastname2"), 2040 "keyspace_id_1": sqltypes.BytesBindVariable([]byte("N\xb1\x90ɢ\xfa\x16\x9c")), 2041 }, 2042 }} 2043 assertQueries(t, sbclookup, wantQueries) 2044 } 2045 2046 func TestMultiInsertGenerator(t *testing.T) { 2047 executor, sbc, _, sbclookup := createExecutorEnv() 2048 2049 sbclookup.SetResults([]*sqltypes.Result{{ 2050 Rows: [][]sqltypes.Value{{ 2051 sqltypes.NewInt64(1), 2052 }}, 2053 RowsAffected: 1, 2054 InsertID: 1, 2055 }}) 2056 result, err := executorExec(executor, "insert into music(user_id, `name`) values (:u, 'myname1'),(:u, 'myname2')", map[string]*querypb.BindVariable{"u": sqltypes.Int64BindVariable(2)}) 2057 require.NoError(t, err) 2058 wantQueries := []*querypb.BoundQuery{{ 2059 Sql: "insert into music(user_id, `name`, id) values (:_user_id_0, 'myname1', :_id_0),(:_user_id_1, 'myname2', :_id_1)", 2060 BindVariables: map[string]*querypb.BindVariable{ 2061 "u": sqltypes.Int64BindVariable(2), 2062 "_id_0": sqltypes.Int64BindVariable(1), 2063 "__seq0": sqltypes.Int64BindVariable(1), 2064 "_user_id_0": sqltypes.Int64BindVariable(2), 2065 "_id_1": sqltypes.Int64BindVariable(2), 2066 "__seq1": sqltypes.Int64BindVariable(2), 2067 "_user_id_1": sqltypes.Int64BindVariable(2), 2068 }, 2069 }} 2070 assertQueries(t, sbc, wantQueries) 2071 wantQueries = []*querypb.BoundQuery{{ 2072 Sql: "select next :n values from user_seq", 2073 BindVariables: map[string]*querypb.BindVariable{"n": sqltypes.Int64BindVariable(2)}, 2074 }, { 2075 Sql: "insert into music_user_map(music_id, user_id) values (:music_id_0, :user_id_0), (:music_id_1, :user_id_1)", 2076 BindVariables: map[string]*querypb.BindVariable{ 2077 "user_id_0": sqltypes.Uint64BindVariable(2), 2078 "music_id_0": sqltypes.Int64BindVariable(1), 2079 "user_id_1": sqltypes.Uint64BindVariable(2), 2080 "music_id_1": sqltypes.Int64BindVariable(2), 2081 }, 2082 }} 2083 assertQueries(t, sbclookup, wantQueries) 2084 wantResult := &sqltypes.Result{ 2085 InsertID: 1, 2086 RowsAffected: 1, 2087 } 2088 utils.MustMatch(t, wantResult, result) 2089 } 2090 2091 func TestMultiInsertGeneratorSparse(t *testing.T) { 2092 executor, sbc, _, sbclookup := createExecutorEnv() 2093 2094 sbclookup.SetResults([]*sqltypes.Result{{ 2095 Rows: [][]sqltypes.Value{{ 2096 sqltypes.NewInt64(1), 2097 }}, 2098 RowsAffected: 1, 2099 InsertID: 1, 2100 }}) 2101 result, err := executorExec(executor, "insert into music(id, user_id, name) values (NULL, :u, 'myname1'),(2, :u, 'myname2'), (NULL, :u, 'myname3')", map[string]*querypb.BindVariable{"u": sqltypes.Int64BindVariable(2)}) 2102 require.NoError(t, err) 2103 wantQueries := []*querypb.BoundQuery{{ 2104 Sql: "insert into music(id, user_id, `name`) values (:_id_0, :_user_id_0, 'myname1'),(:_id_1, :_user_id_1, 'myname2'),(:_id_2, :_user_id_2, 'myname3')", 2105 BindVariables: map[string]*querypb.BindVariable{ 2106 "u": sqltypes.Int64BindVariable(2), 2107 "_id_0": sqltypes.Int64BindVariable(1), 2108 "__seq0": sqltypes.Int64BindVariable(1), 2109 "_user_id_0": sqltypes.Int64BindVariable(2), 2110 "_id_1": sqltypes.Int64BindVariable(2), 2111 "__seq1": sqltypes.Int64BindVariable(2), 2112 "_user_id_1": sqltypes.Int64BindVariable(2), 2113 "_id_2": sqltypes.Int64BindVariable(2), 2114 "__seq2": sqltypes.Int64BindVariable(2), 2115 "_user_id_2": sqltypes.Int64BindVariable(2), 2116 }, 2117 }} 2118 assertQueries(t, sbc, wantQueries) 2119 wantQueries = []*querypb.BoundQuery{{ 2120 Sql: "select next :n values from user_seq", 2121 BindVariables: map[string]*querypb.BindVariable{"n": sqltypes.Int64BindVariable(2)}, 2122 }, { 2123 Sql: "insert into music_user_map(music_id, user_id) values (:music_id_0, :user_id_0), (:music_id_1, :user_id_1), (:music_id_2, :user_id_2)", 2124 BindVariables: map[string]*querypb.BindVariable{ 2125 "user_id_0": sqltypes.Uint64BindVariable(2), 2126 "music_id_0": sqltypes.Int64BindVariable(1), 2127 "user_id_1": sqltypes.Uint64BindVariable(2), 2128 "music_id_1": sqltypes.Int64BindVariable(2), 2129 "user_id_2": sqltypes.Uint64BindVariable(2), 2130 "music_id_2": sqltypes.Int64BindVariable(2), 2131 }, 2132 }} 2133 assertQueries(t, sbclookup, wantQueries) 2134 wantResult := &sqltypes.Result{ 2135 InsertID: 1, 2136 RowsAffected: 1, 2137 } 2138 utils.MustMatch(t, wantResult, result) 2139 } 2140 2141 func TestInsertBadAutoInc(t *testing.T) { 2142 vschema := ` 2143 { 2144 "sharded": true, 2145 "vindexes": { 2146 "hash_index": { 2147 "type": "hash" 2148 } 2149 }, 2150 "tables": { 2151 "bad_auto": { 2152 "column_vindexes": [ 2153 { 2154 "column": "id", 2155 "name": "hash_index" 2156 } 2157 ], 2158 "auto_increment": { 2159 "column": "id", 2160 "sequence": "absent" 2161 } 2162 } 2163 } 2164 } 2165 ` 2166 executor, _, _, _ := createCustomExecutor(vschema) 2167 2168 // If auto inc table cannot be found, the table should not be added to vschema. 2169 _, err := executorExec(executor, "insert into bad_auto(v, name) values (1, 'myname')", nil) 2170 want := "table bad_auto not found" 2171 if err == nil || err.Error() != want { 2172 t.Errorf("bad auto inc err: %v, want %v", err, want) 2173 } 2174 } 2175 2176 func TestKeyDestRangeQuery(t *testing.T) { 2177 2178 type testCase struct { 2179 inputQuery, targetString string 2180 expectedSbc1Query string 2181 expectedSbc2Query string 2182 } 2183 deleteInput := "DELETE FROM sharded_user_msgs LIMIT 1000" 2184 deleteOutput := "delete from sharded_user_msgs limit 1000" 2185 2186 selectInput := "SELECT * FROM sharded_user_msgs LIMIT 1" 2187 selectOutput := "select * from sharded_user_msgs limit 1" 2188 updateInput := "UPDATE sharded_user_msgs set message='test' LIMIT 1" 2189 updateOutput := "update sharded_user_msgs set message = 'test' limit 1" 2190 insertInput := "INSERT INTO sharded_user_msgs(message) VALUES('test')" 2191 insertOutput := "insert into sharded_user_msgs(message) values ('test')" 2192 tests := []testCase{ 2193 { 2194 inputQuery: deleteInput, 2195 targetString: "TestExecutor[-60]", 2196 expectedSbc1Query: deleteOutput, 2197 expectedSbc2Query: deleteOutput, 2198 }, 2199 { 2200 inputQuery: deleteInput, 2201 targetString: "TestExecutor[40-60]", 2202 expectedSbc2Query: deleteOutput, 2203 }, 2204 { 2205 inputQuery: deleteInput, 2206 targetString: "TestExecutor[-]", 2207 expectedSbc1Query: deleteOutput, 2208 expectedSbc2Query: deleteOutput, 2209 }, 2210 { 2211 inputQuery: selectInput, 2212 targetString: "TestExecutor[-]", 2213 expectedSbc1Query: selectOutput, 2214 expectedSbc2Query: selectOutput, 2215 }, 2216 { 2217 inputQuery: updateInput, 2218 targetString: "TestExecutor[-]", 2219 expectedSbc1Query: updateOutput, 2220 expectedSbc2Query: updateOutput, 2221 }, 2222 { 2223 inputQuery: insertInput, 2224 targetString: "TestExecutor:40-60", 2225 expectedSbc2Query: insertOutput, 2226 }, 2227 { 2228 inputQuery: insertInput, 2229 targetString: "TestExecutor:-20", 2230 expectedSbc1Query: insertOutput, 2231 }, 2232 } 2233 2234 for _, tc := range tests { 2235 t.Run(tc.targetString+" - "+tc.inputQuery, func(t *testing.T) { 2236 executor, sbc1, sbc2, _ := createExecutorEnv() 2237 2238 primarySession.TargetString = tc.targetString 2239 _, err := executorExec(executor, tc.inputQuery, nil) 2240 require.NoError(t, err) 2241 2242 if tc.expectedSbc1Query == "" { 2243 require.Empty(t, sbc1.BatchQueries, "sbc1") 2244 } else { 2245 assertQueriesContain(t, tc.expectedSbc1Query, "sbc1", sbc1) 2246 } 2247 2248 if tc.expectedSbc2Query == "" { 2249 require.Empty(t, sbc2.BatchQueries) 2250 } else { 2251 assertQueriesContain(t, tc.expectedSbc2Query, "sbc2", sbc2) 2252 } 2253 }) 2254 } 2255 2256 // it does not work for inserts 2257 executor, _, _, _ := createExecutorEnv() 2258 primarySession.TargetString = "TestExecutor[-]" 2259 _, err := executorExec(executor, insertInput, nil) 2260 2261 require.EqualError(t, err, "VT03023: INSERT not supported when targeting a key range: TestExecutor[-]") 2262 2263 primarySession.TargetString = "" 2264 } 2265 2266 func assertQueriesContain(t *testing.T, sql, sbcName string, sbc *sandboxconn.SandboxConn) { 2267 t.Helper() 2268 expectedQuery := []*querypb.BoundQuery{{ 2269 Sql: sql, 2270 BindVariables: map[string]*querypb.BindVariable{}, 2271 }} 2272 assertQueries(t, sbc, expectedQuery) 2273 } 2274 2275 // Prepared statement tests 2276 func TestUpdateEqualWithPrepare(t *testing.T) { 2277 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 2278 2279 logChan := QueryLogger.Subscribe("Test") 2280 defer QueryLogger.Unsubscribe(logChan) 2281 2282 _, err := executorPrepare(executor, "update music set a = :a0 where id = :id0", map[string]*querypb.BindVariable{ 2283 "a0": sqltypes.Int64BindVariable(3), 2284 "id0": sqltypes.Int64BindVariable(2), 2285 }) 2286 require.NoError(t, err) 2287 2288 var wantQueries []*querypb.BoundQuery 2289 2290 assertQueries(t, sbclookup, wantQueries) 2291 assertQueries(t, sbc2, nil) 2292 assertQueries(t, sbc1, nil) 2293 } 2294 func TestInsertShardedWithPrepare(t *testing.T) { 2295 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 2296 2297 logChan := QueryLogger.Subscribe("Test") 2298 defer QueryLogger.Unsubscribe(logChan) 2299 2300 _, err := executorPrepare(executor, "insert into user(id, v, name) values (:_Id0, 2, ':_name_0')", map[string]*querypb.BindVariable{ 2301 "_Id0": sqltypes.Int64BindVariable(1), 2302 "_name_0": sqltypes.BytesBindVariable([]byte("myname")), 2303 "__seq0": sqltypes.Int64BindVariable(1), 2304 }) 2305 require.NoError(t, err) 2306 2307 var wantQueries []*querypb.BoundQuery 2308 2309 assertQueries(t, sbc1, wantQueries) 2310 assertQueries(t, sbc2, nil) 2311 2312 assertQueries(t, sbclookup, wantQueries) 2313 } 2314 2315 func TestDeleteEqualWithPrepare(t *testing.T) { 2316 executor, sbc, _, sbclookup := createExecutorEnv() 2317 _, err := executorPrepare(executor, "delete from user where id = :id0", map[string]*querypb.BindVariable{ 2318 "id0": sqltypes.Int64BindVariable(1), 2319 }) 2320 require.NoError(t, err) 2321 2322 var wantQueries []*querypb.BoundQuery 2323 2324 assertQueries(t, sbc, wantQueries) 2325 2326 assertQueries(t, sbclookup, wantQueries) 2327 } 2328 2329 func TestUpdateLastInsertID(t *testing.T) { 2330 executor, sbc1, _, _ := createExecutorEnv() 2331 executor.normalize = true 2332 2333 sql := "update user set a = last_insert_id() where id = 1" 2334 primarySession.LastInsertId = 43 2335 _, err := executorExec(executor, sql, map[string]*querypb.BindVariable{}) 2336 require.NoError(t, err) 2337 wantQueries := []*querypb.BoundQuery{{ 2338 Sql: "update `user` set a = :__lastInsertId where id = :id", 2339 BindVariables: map[string]*querypb.BindVariable{ 2340 "__lastInsertId": sqltypes.Uint64BindVariable(43), 2341 "id": sqltypes.Int64BindVariable(1)}, 2342 }} 2343 2344 assertQueries(t, sbc1, wantQueries) 2345 } 2346 2347 func TestUpdateReference(t *testing.T) { 2348 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 2349 2350 logChan := QueryLogger.Subscribe("Test") 2351 defer QueryLogger.Unsubscribe(logChan) 2352 2353 _, err := executorExec(executor, "update zip_detail set status = 'CLOSED' where id = 1", nil) 2354 require.NoError(t, err) 2355 wantQueries := []*querypb.BoundQuery{{ 2356 Sql: "update zip_detail set `status` = 'CLOSED' where id = 1", 2357 BindVariables: map[string]*querypb.BindVariable{}, 2358 }} 2359 assertQueries(t, sbc1, nil) 2360 assertQueries(t, sbc2, nil) 2361 assertQueries(t, sbclookup, wantQueries) 2362 2363 testQueryLog(t, logChan, "TestExecute", "UPDATE", "update zip_detail set status = 'CLOSED' where id = 1", 1) 2364 2365 sbclookup.Queries = nil 2366 2367 _, err = executorExec(executor, "update TestUnsharded.zip_detail set status = 'CLOSED' where id = 1", nil) 2368 require.NoError(t, err) 2369 wantQueries = []*querypb.BoundQuery{{ 2370 Sql: "update zip_detail set `status` = 'CLOSED' where id = 1", 2371 BindVariables: map[string]*querypb.BindVariable{}, 2372 }} 2373 assertQueries(t, sbc1, nil) 2374 assertQueries(t, sbc2, nil) 2375 assertQueries(t, sbclookup, wantQueries) 2376 2377 testQueryLog(t, logChan, "TestExecute", "UPDATE", 2378 "update TestUnsharded.zip_detail set status = 'CLOSED' where id = 1", 1) 2379 2380 sbclookup.Queries = nil 2381 2382 _, err = executorExec(executor, "update TestExecutor.zip_detail set status = 'CLOSED' where id = 1", nil) 2383 require.Error(t, err) 2384 } 2385 2386 func TestDeleteLookupOwnedEqual(t *testing.T) { 2387 executor, sbc1, sbc2, _ := createExecutorEnv() 2388 2389 sbc1.SetResults([]*sqltypes.Result{ 2390 sqltypes.MakeTestResult(sqltypes.MakeTestFields("uniq_col|keyspace_id", "int64|varbinary"), "1|N±\u0090ɢú\u0016\u009C"), 2391 }) 2392 _, err := executorExec(executor, "delete from t1 where unq_col = 1", nil) 2393 require.NoError(t, err) 2394 tupleBindVar, _ := sqltypes.BuildBindVariable([]int64{1}) 2395 sbc1wantQueries := []*querypb.BoundQuery{{ 2396 Sql: "select unq_col, keyspace_id from t1_lkp_idx where unq_col in ::__vals for update", 2397 BindVariables: map[string]*querypb.BindVariable{ 2398 "__vals": tupleBindVar, 2399 "unq_col": tupleBindVar, 2400 }, 2401 }} 2402 sbc2wantQueries := []*querypb.BoundQuery{{ 2403 Sql: "select id, unq_col from t1 where unq_col = 1 for update", 2404 BindVariables: map[string]*querypb.BindVariable{}, 2405 }, { 2406 Sql: "delete from t1 where unq_col = 1", 2407 BindVariables: map[string]*querypb.BindVariable{}, 2408 }} 2409 assertQueries(t, sbc1, sbc1wantQueries) 2410 assertQueries(t, sbc2, sbc2wantQueries) 2411 } 2412 2413 func TestDeleteReference(t *testing.T) { 2414 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 2415 2416 logChan := QueryLogger.Subscribe("Test") 2417 defer QueryLogger.Unsubscribe(logChan) 2418 2419 _, err := executorExec(executor, "delete from zip_detail where id = 1", nil) 2420 require.NoError(t, err) 2421 wantQueries := []*querypb.BoundQuery{{ 2422 Sql: "delete from zip_detail where id = 1", 2423 BindVariables: map[string]*querypb.BindVariable{}, 2424 }} 2425 assertQueries(t, sbc1, nil) 2426 assertQueries(t, sbc2, nil) 2427 assertQueries(t, sbclookup, wantQueries) 2428 2429 testQueryLog(t, logChan, "TestExecute", "DELETE", "delete from zip_detail where id = 1", 1) 2430 2431 sbclookup.Queries = nil 2432 2433 _, err = executorExec(executor, "delete from zip_detail where id = 1", nil) 2434 require.NoError(t, err) 2435 wantQueries = []*querypb.BoundQuery{{ 2436 Sql: "delete from zip_detail where id = 1", 2437 BindVariables: map[string]*querypb.BindVariable{}, 2438 }} 2439 assertQueries(t, sbc1, nil) 2440 assertQueries(t, sbc2, nil) 2441 assertQueries(t, sbclookup, wantQueries) 2442 2443 testQueryLog(t, logChan, "TestExecute", "DELETE", "delete from zip_detail where id = 1", 1) 2444 2445 sbclookup.Queries = nil 2446 2447 _, err = executorExec(executor, "delete from TestExecutor.zip_detail where id = 1", nil) 2448 require.Error(t, err) 2449 } 2450 2451 func TestReservedConnDML(t *testing.T) { 2452 executor, _, _, sbc := createExecutorEnv() 2453 2454 logChan := QueryLogger.Subscribe("TestReservedConnDML") 2455 defer QueryLogger.Unsubscribe(logChan) 2456 2457 ctx := context.Background() 2458 session := NewAutocommitSession(&vtgatepb.Session{EnableSystemSettings: true}) 2459 2460 _, err := executor.Execute(ctx, "TestReservedConnDML", session, "use "+KsTestUnsharded, nil) 2461 require.NoError(t, err) 2462 2463 wantQueries := []*querypb.BoundQuery{ 2464 {Sql: "select 1 from dual where @@default_week_format != 1", BindVariables: map[string]*querypb.BindVariable{}}, 2465 } 2466 sbc.SetResults([]*sqltypes.Result{ 2467 sqltypes.MakeTestResult(sqltypes.MakeTestFields("id", "int64"), "1"), 2468 }) 2469 _, err = executor.Execute(ctx, "TestReservedConnDML", session, "set default_week_format = 1", nil) 2470 require.NoError(t, err) 2471 assertQueries(t, sbc, wantQueries) 2472 2473 _, err = executor.Execute(ctx, "TestReservedConnDML", session, "begin", nil) 2474 require.NoError(t, err) 2475 2476 wantQueries = append(wantQueries, 2477 &querypb.BoundQuery{Sql: "set default_week_format = 1", BindVariables: map[string]*querypb.BindVariable{}}, 2478 &querypb.BoundQuery{Sql: "insert into `simple`() values ()", BindVariables: map[string]*querypb.BindVariable{}}) 2479 _, err = executor.Execute(ctx, "TestReservedConnDML", session, "insert into `simple`() values ()", nil) 2480 require.NoError(t, err) 2481 assertQueries(t, sbc, wantQueries) 2482 2483 _, err = executor.Execute(ctx, "TestReservedConnDML", session, "commit", nil) 2484 require.NoError(t, err) 2485 2486 _, err = executor.Execute(ctx, "TestReservedConnDML", session, "begin", nil) 2487 require.NoError(t, err) 2488 2489 sbc.EphemeralShardErr = mysql.NewSQLError(mysql.CRServerGone, mysql.SSNetError, "connection gone") 2490 // as the first time the query fails due to connection loss i.e. reserved conn lost. It will be recreated to set statement will be executed again. 2491 wantQueries = append(wantQueries, 2492 &querypb.BoundQuery{Sql: "set default_week_format = 1", BindVariables: map[string]*querypb.BindVariable{}}, 2493 &querypb.BoundQuery{Sql: "insert into `simple`() values ()", BindVariables: map[string]*querypb.BindVariable{}}) 2494 _, err = executor.Execute(ctx, "TestReservedConnDML", session, "insert into `simple`() values ()", nil) 2495 require.NoError(t, err) 2496 assertQueries(t, sbc, wantQueries) 2497 2498 _, err = executor.Execute(ctx, "TestReservedConnDML", session, "commit", nil) 2499 require.NoError(t, err) 2500 } 2501 2502 func TestStreamingDML(t *testing.T) { 2503 method := "TestStreamingDML" 2504 2505 executor, _, _, sbc := createExecutorEnv() 2506 2507 logChan := QueryLogger.Subscribe(method) 2508 defer QueryLogger.Unsubscribe(logChan) 2509 2510 ctx := context.Background() 2511 session := NewAutocommitSession(&vtgatepb.Session{}) 2512 2513 tcases := []struct { 2514 query string 2515 result *sqltypes.Result 2516 2517 inTx bool 2518 openTx bool 2519 changedRows int 2520 commitCount int 2521 expQuery []*querypb.BoundQuery 2522 }{{ 2523 query: "begin", 2524 2525 inTx: true, 2526 expQuery: []*querypb.BoundQuery{}, 2527 }, { 2528 query: "insert into `simple`() values ()", 2529 result: &sqltypes.Result{RowsAffected: 1}, 2530 2531 inTx: true, 2532 openTx: true, 2533 changedRows: 1, 2534 expQuery: []*querypb.BoundQuery{{ 2535 Sql: "insert into `simple`() values ()", 2536 BindVariables: map[string]*querypb.BindVariable{}, 2537 }}, 2538 }, { 2539 query: "update `simple` set name = 'V' where col = 2", 2540 result: &sqltypes.Result{RowsAffected: 3}, 2541 2542 inTx: true, 2543 openTx: true, 2544 changedRows: 3, 2545 expQuery: []*querypb.BoundQuery{{ 2546 Sql: "update `simple` set `name` = 'V' where col = 2", 2547 BindVariables: map[string]*querypb.BindVariable{}, 2548 }}, 2549 }, { 2550 query: "delete from `simple`", 2551 result: &sqltypes.Result{RowsAffected: 12}, 2552 2553 inTx: true, 2554 openTx: true, 2555 changedRows: 12, 2556 expQuery: []*querypb.BoundQuery{{ 2557 Sql: "delete from `simple`", 2558 BindVariables: map[string]*querypb.BindVariable{}, 2559 }}, 2560 }, { 2561 query: "commit", 2562 2563 commitCount: 1, 2564 expQuery: []*querypb.BoundQuery{}, 2565 }} 2566 2567 var qr *sqltypes.Result 2568 for _, tcase := range tcases { 2569 sbc.Queries = nil 2570 sbc.SetResults([]*sqltypes.Result{tcase.result}) 2571 err := executor.StreamExecute(ctx, method, session, tcase.query, nil, func(result *sqltypes.Result) error { 2572 qr = result 2573 return nil 2574 }) 2575 require.NoError(t, err) 2576 // should tx start 2577 assert.Equal(t, tcase.inTx, session.GetInTransaction()) 2578 // open transaction 2579 assert.Equal(t, tcase.openTx, len(session.ShardSessions) > 0) 2580 // row affected as returned by result 2581 assert.EqualValues(t, tcase.changedRows, qr.RowsAffected) 2582 // match the query received on tablet 2583 assertQueries(t, sbc, tcase.expQuery) 2584 2585 assert.EqualValues(t, tcase.commitCount, sbc.CommitCount.Get()) 2586 } 2587 } 2588 2589 func TestPartialVindexInsertQueryFailure(t *testing.T) { 2590 executor, sbc1, sbc2, _ := createExecutorEnv() 2591 2592 logChan := QueryLogger.Subscribe("Test") 2593 defer QueryLogger.Unsubscribe(logChan) 2594 2595 session := NewAutocommitSession(&vtgatepb.Session{}) 2596 require.True(t, session.GetAutocommit()) 2597 require.False(t, session.InTransaction()) 2598 2599 _, err := executorExecSession(executor, "begin", nil, session.Session) 2600 require.NoError(t, err) 2601 require.True(t, session.GetAutocommit()) 2602 require.True(t, session.InTransaction()) 2603 2604 // fail the second lookup insert query i.e t1_lkp_idx(3, ksid) 2605 sbc2.MustFailExecute[sqlparser.StmtInsert] = 1 2606 wantQ := []*querypb.BoundQuery{{ 2607 Sql: "savepoint x", 2608 BindVariables: map[string]*querypb.BindVariable{}, 2609 }, { 2610 Sql: "insert into t1_lkp_idx(unq_col, keyspace_id) values (:_unq_col_0, :keyspace_id_0)", 2611 BindVariables: map[string]*querypb.BindVariable{ 2612 "unq_col_0": sqltypes.Int64BindVariable(1), 2613 "keyspace_id_0": sqltypes.BytesBindVariable([]byte("\x16k@\xb4J\xbaK\xd6")), 2614 "unq_col_1": sqltypes.Int64BindVariable(3), 2615 "keyspace_id_1": sqltypes.BytesBindVariable([]byte("\x06\xe7\xea\"Βp\x8f")), 2616 "_unq_col_0": sqltypes.Int64BindVariable(1), 2617 "_unq_col_1": sqltypes.Int64BindVariable(3), 2618 }, 2619 }, { 2620 Sql: "rollback to x", 2621 BindVariables: map[string]*querypb.BindVariable{}, 2622 }} 2623 2624 _, err = executorExecSession(executor, "insert into t1(id, unq_col) values (1, 1), (2, 3)", nil, session.Session) 2625 require.Error(t, err) 2626 require.Contains(t, err.Error(), "reverted partial DML execution failure") 2627 require.True(t, session.GetAutocommit()) 2628 require.True(t, session.InTransaction()) 2629 2630 assertQueriesWithSavepoint(t, sbc1, wantQ) 2631 2632 // only parameter in expected query changes 2633 wantQ[1].Sql = "insert into t1_lkp_idx(unq_col, keyspace_id) values (:_unq_col_1, :keyspace_id_1)" 2634 assertQueriesWithSavepoint(t, sbc2, wantQ) 2635 2636 testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) 2637 testQueryLog(t, logChan, "MarkSavepoint", "SAVEPOINT", "savepoint x", 0) 2638 testQueryLog(t, logChan, "VindexCreate", "SAVEPOINT_ROLLBACK", "rollback to x", 0) 2639 testQueryLog(t, logChan, "TestExecute", "INSERT", "insert into t1(id, unq_col) values (1, 1), (2, 3)", 0) 2640 } 2641 2642 func TestPartialVindexInsertQueryFailureAutoCommit(t *testing.T) { 2643 executor, sbc1, sbc2, _ := createExecutorEnv() 2644 2645 logChan := QueryLogger.Subscribe("Test") 2646 defer QueryLogger.Unsubscribe(logChan) 2647 2648 session := NewAutocommitSession(&vtgatepb.Session{}) 2649 require.True(t, session.GetAutocommit()) 2650 require.False(t, session.InTransaction()) 2651 2652 // fail the second lookup insert query i.e t1_lkp_idx(3, ksid) 2653 sbc2.MustFailExecute[sqlparser.StmtInsert] = 1 2654 wantQ := []*querypb.BoundQuery{{ 2655 Sql: "insert into t1_lkp_idx(unq_col, keyspace_id) values (:_unq_col_0, :keyspace_id_0)", 2656 BindVariables: map[string]*querypb.BindVariable{ 2657 "unq_col_0": sqltypes.Int64BindVariable(1), 2658 "keyspace_id_0": sqltypes.BytesBindVariable([]byte("\x16k@\xb4J\xbaK\xd6")), 2659 "unq_col_1": sqltypes.Int64BindVariable(3), 2660 "keyspace_id_1": sqltypes.BytesBindVariable([]byte("\x06\xe7\xea\"Βp\x8f")), 2661 "_unq_col_0": sqltypes.Int64BindVariable(1), 2662 "_unq_col_1": sqltypes.Int64BindVariable(3), 2663 }, 2664 }} 2665 2666 _, err := executorExecSession(executor, "insert into t1(id, unq_col) values (1, 1), (2, 3)", nil, session.Session) 2667 require.Error(t, err) 2668 assert.Contains(t, err.Error(), "transaction rolled back to reverse changes of partial DML execution") 2669 assert.True(t, session.GetAutocommit()) 2670 assert.False(t, session.InTransaction()) 2671 2672 assertQueriesWithSavepoint(t, sbc1, wantQ) 2673 2674 // only parameter in expected query changes 2675 wantQ[0].Sql = "insert into t1_lkp_idx(unq_col, keyspace_id) values (:_unq_col_1, :keyspace_id_1)" 2676 assertQueriesWithSavepoint(t, sbc2, wantQ) 2677 2678 testQueryLog(t, logChan, "VindexCreate", "INSERT", "insert into t1_lkp_idx(unq_col, keyspace_id) values(:unq_col_0, :keyspace_id_0), (:unq_col_1, :keyspace_id_1)", 2) 2679 testQueryLog(t, logChan, "TestExecute", "INSERT", "insert into t1(id, unq_col) values (1, 1), (2, 3)", 0) 2680 } 2681 2682 // TestMultiInternalSavepoint shows that the internal savepoint created for rolling back any partial dml changes on a failure is not removed from the savepoint list. 2683 // Any new transaction opened on a different shard will apply those savepoints as well. 2684 // The change for it cannot be done as the executor level and will be made at the VTGate entry point. 2685 // Test TestMultiInternalSavepointVtGate shows that it fixes the behaviour. 2686 func TestMultiInternalSavepoint(t *testing.T) { 2687 executor, sbc1, sbc2, _ := createExecutorEnv() 2688 2689 session := NewAutocommitSession(&vtgatepb.Session{}) 2690 _, err := executorExecSession(executor, "begin", nil, session.Session) 2691 require.NoError(t, err) 2692 2693 // this query goes to multiple shards so internal savepoint will be created. 2694 _, err = executorExecSession(executor, "insert into user_extra(user_id) values (1), (4)", nil, session.Session) 2695 require.NoError(t, err) 2696 2697 wantQ := []*querypb.BoundQuery{{ 2698 Sql: "savepoint x", 2699 BindVariables: map[string]*querypb.BindVariable{}, 2700 }, { 2701 Sql: "insert into user_extra(user_id) values (:_user_id_0)", 2702 BindVariables: map[string]*querypb.BindVariable{ 2703 "_user_id_0": sqltypes.Int64BindVariable(1), 2704 "_user_id_1": sqltypes.Int64BindVariable(4), 2705 }, 2706 }} 2707 assertQueriesWithSavepoint(t, sbc1, wantQ) 2708 require.Len(t, sbc2.Queries, 0) 2709 sbc1.Queries = nil 2710 2711 _, err = executorExecSession(executor, "insert into user_extra(user_id) values (3), (6)", nil, session.Session) 2712 require.NoError(t, err) 2713 wantQ = []*querypb.BoundQuery{{ 2714 Sql: "savepoint x", 2715 BindVariables: map[string]*querypb.BindVariable{}, 2716 }, { 2717 Sql: "savepoint y", 2718 BindVariables: map[string]*querypb.BindVariable{}, 2719 }, { 2720 Sql: "insert into user_extra(user_id) values (:_user_id_0)", 2721 BindVariables: map[string]*querypb.BindVariable{ 2722 "_user_id_0": sqltypes.Int64BindVariable(3), 2723 "_user_id_1": sqltypes.Int64BindVariable(6), 2724 }, 2725 }} 2726 assertQueriesWithSavepoint(t, sbc2, wantQ) 2727 wantQ = []*querypb.BoundQuery{{ 2728 Sql: "savepoint y", 2729 BindVariables: map[string]*querypb.BindVariable{}, 2730 }} 2731 assertQueriesWithSavepoint(t, sbc1, wantQ) 2732 } 2733 2734 func TestInsertSelectFromDual(t *testing.T) { 2735 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 2736 2737 logChan := QueryLogger.Subscribe("TestInsertSelect") 2738 defer QueryLogger.Unsubscribe(logChan) 2739 2740 session := NewAutocommitSession(&vtgatepb.Session{}) 2741 2742 query := "insert into user(id, v, name) select 1, 2, 'myname' from dual" 2743 wantQueries := []*querypb.BoundQuery{{ 2744 Sql: "insert into `user`(id, v, `name`) values (:_c0_0, :_c0_1, :_c0_2)", 2745 BindVariables: map[string]*querypb.BindVariable{ 2746 "_c0_0": sqltypes.Int64BindVariable(1), 2747 "_c0_1": sqltypes.Int64BindVariable(2), 2748 "_c0_2": sqltypes.StringBindVariable("myname"), 2749 }, 2750 }} 2751 2752 wantlkpQueries := []*querypb.BoundQuery{{ 2753 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0)", 2754 BindVariables: map[string]*querypb.BindVariable{ 2755 "name_0": sqltypes.StringBindVariable("myname"), 2756 "user_id_0": sqltypes.Uint64BindVariable(1), 2757 }, 2758 }} 2759 2760 for _, workload := range []string{"olap", "oltp"} { 2761 sbc1.Queries = nil 2762 sbc2.Queries = nil 2763 sbclookup.Queries = nil 2764 wQuery := fmt.Sprintf("set @@workload = %s", workload) 2765 _, err := executor.Execute(context.Background(), "TestInsertSelect", session, wQuery, nil) 2766 require.NoError(t, err) 2767 2768 _, err = executor.Execute(context.Background(), "TestInsertSelect", session, query, nil) 2769 require.NoError(t, err) 2770 2771 assertQueries(t, sbc1, wantQueries) 2772 assertQueries(t, sbc2, nil) 2773 assertQueries(t, sbclookup, wantlkpQueries) 2774 2775 testQueryLog(t, logChan, "TestInsertSelect", "SET", wQuery, 0) 2776 testQueryLog(t, logChan, "VindexCreate", "INSERT", "insert into name_user_map(name, user_id) values(:name_0, :user_id_0)", 1) 2777 testQueryLog(t, logChan, "TestInsertSelect", "INSERT", "insert into user(id, v, name) select 1, 2, 'myname' from dual", 1) 2778 } 2779 } 2780 2781 func TestInsertSelectFromTable(t *testing.T) { 2782 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 2783 2784 logChan := QueryLogger.Subscribe("TestInsertSelect") 2785 defer QueryLogger.Unsubscribe(logChan) 2786 2787 session := NewAutocommitSession(&vtgatepb.Session{}) 2788 2789 query := "insert into user(id, name) select c1, c2 from music" 2790 wantQueries := []*querypb.BoundQuery{{ 2791 Sql: "select c1, c2 from music for update", 2792 BindVariables: map[string]*querypb.BindVariable{}, 2793 }, { 2794 Sql: "insert into `user`(id, `name`) values (:_c0_0, :_c0_1), (:_c1_0, :_c1_1), (:_c2_0, :_c2_1), (:_c3_0, :_c3_1), (:_c4_0, :_c4_1), (:_c5_0, :_c5_1), (:_c6_0, :_c6_1), (:_c7_0, :_c7_1)", 2795 BindVariables: map[string]*querypb.BindVariable{ 2796 "_c0_0": sqltypes.Int32BindVariable(1), "_c0_1": sqltypes.StringBindVariable("foo"), 2797 "_c1_0": sqltypes.Int32BindVariable(1), "_c1_1": sqltypes.StringBindVariable("foo"), 2798 "_c2_0": sqltypes.Int32BindVariable(1), "_c2_1": sqltypes.StringBindVariable("foo"), 2799 "_c3_0": sqltypes.Int32BindVariable(1), "_c3_1": sqltypes.StringBindVariable("foo"), 2800 "_c4_0": sqltypes.Int32BindVariable(1), "_c4_1": sqltypes.StringBindVariable("foo"), 2801 "_c5_0": sqltypes.Int32BindVariable(1), "_c5_1": sqltypes.StringBindVariable("foo"), 2802 "_c6_0": sqltypes.Int32BindVariable(1), "_c6_1": sqltypes.StringBindVariable("foo"), 2803 "_c7_0": sqltypes.Int32BindVariable(1), "_c7_1": sqltypes.StringBindVariable("foo"), 2804 }, 2805 }} 2806 2807 wantlkpQueries := []*querypb.BoundQuery{{ 2808 Sql: "insert into name_user_map(`name`, user_id) values (:name_0, :user_id_0), (:name_1, :user_id_1), (:name_2, :user_id_2), (:name_3, :user_id_3), (:name_4, :user_id_4), (:name_5, :user_id_5), (:name_6, :user_id_6), (:name_7, :user_id_7)", 2809 BindVariables: map[string]*querypb.BindVariable{ 2810 "name_0": sqltypes.StringBindVariable("foo"), "user_id_0": sqltypes.Uint64BindVariable(1), 2811 "name_1": sqltypes.StringBindVariable("foo"), "user_id_1": sqltypes.Uint64BindVariable(1), 2812 "name_2": sqltypes.StringBindVariable("foo"), "user_id_2": sqltypes.Uint64BindVariable(1), 2813 "name_3": sqltypes.StringBindVariable("foo"), "user_id_3": sqltypes.Uint64BindVariable(1), 2814 "name_4": sqltypes.StringBindVariable("foo"), "user_id_4": sqltypes.Uint64BindVariable(1), 2815 "name_5": sqltypes.StringBindVariable("foo"), "user_id_5": sqltypes.Uint64BindVariable(1), 2816 "name_6": sqltypes.StringBindVariable("foo"), "user_id_6": sqltypes.Uint64BindVariable(1), 2817 "name_7": sqltypes.StringBindVariable("foo"), "user_id_7": sqltypes.Uint64BindVariable(1), 2818 }, 2819 }} 2820 2821 for _, workload := range []string{"olap", "oltp"} { 2822 sbc1.Queries = nil 2823 sbc2.Queries = nil 2824 sbclookup.Queries = nil 2825 wQuery := fmt.Sprintf("set @@workload = %s", workload) 2826 _, err := executor.Execute(context.Background(), "TestInsertSelect", session, wQuery, nil) 2827 require.NoError(t, err) 2828 2829 _, err = executor.Execute(context.Background(), "TestInsertSelect", session, query, nil) 2830 require.NoError(t, err) 2831 2832 assertQueries(t, sbc1, wantQueries) 2833 assertQueries(t, sbc2, wantQueries[:1]) // select scatter query went scatter. 2834 assertQueries(t, sbclookup, wantlkpQueries) 2835 2836 testQueryLog(t, logChan, "TestInsertSelect", "SET", wQuery, 0) 2837 testQueryLog(t, logChan, "VindexCreate", "INSERT", "insert into name_user_map(name, user_id) values(:name_0, :user_id_0), (:name_1, :user_id_1), (:name_2, :user_id_2), (:name_3, :user_id_3), (:name_4, :user_id_4), (:name_5, :user_id_5), (:name_6, :user_id_6), (:name_7, :user_id_7)", 1) 2838 testQueryLog(t, logChan, "TestInsertSelect", "INSERT", "insert into user(id, name) select c1, c2 from music", 9) // 8 from select and 1 from insert. 2839 } 2840 } 2841 2842 func TestInsertReference(t *testing.T) { 2843 executor, sbc1, sbc2, sbclookup := createExecutorEnv() 2844 2845 logChan := QueryLogger.Subscribe("Test") 2846 defer QueryLogger.Unsubscribe(logChan) 2847 2848 _, err := executorExec(executor, "insert into zip_detail(id, status) values (1, 'CLOSED')", nil) 2849 require.NoError(t, err) 2850 wantQueries := []*querypb.BoundQuery{{ 2851 Sql: "insert into zip_detail(id, `status`) values (1, 'CLOSED')", 2852 BindVariables: map[string]*querypb.BindVariable{}, 2853 }} 2854 assertQueries(t, sbc1, nil) 2855 assertQueries(t, sbc2, nil) 2856 assertQueries(t, sbclookup, wantQueries) 2857 2858 testQueryLog(t, logChan, "TestExecute", "INSERT", "insert into zip_detail(id, status) values (1, 'CLOSED')", 1) 2859 2860 sbclookup.Queries = nil 2861 2862 _, err = executorExec(executor, "insert into TestUnsharded.zip_detail(id, status) values (1, 'CLOSED')", nil) 2863 require.NoError(t, err) 2864 wantQueries = []*querypb.BoundQuery{{ 2865 Sql: "insert into zip_detail(id, `status`) values (1, 'CLOSED')", 2866 BindVariables: map[string]*querypb.BindVariable{}, 2867 }} 2868 assertQueries(t, sbc1, nil) 2869 assertQueries(t, sbc2, nil) 2870 assertQueries(t, sbclookup, wantQueries) 2871 2872 testQueryLog(t, logChan, "TestExecute", "INSERT", 2873 "insert into TestUnsharded.zip_detail(id, status) values (1, 'CLOSED')", 1) 2874 2875 sbclookup.Queries = nil 2876 2877 _, err = executorExec(executor, "insert into TestExecutor.zip_detail(id, status) values (1, 'CLOSED')", nil) 2878 require.Error(t, err) 2879 }