vitess.io/vitess@v0.16.2/go/vt/vtgate/engine/fake_vcursor_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 engine 18 19 import ( 20 "bytes" 21 "context" 22 "fmt" 23 "reflect" 24 "sort" 25 "strings" 26 "sync" 27 "testing" 28 29 "vitess.io/vitess/go/mysql/collations" 30 "vitess.io/vitess/go/sqltypes" 31 "vitess.io/vitess/go/test/utils" 32 "vitess.io/vitess/go/vt/key" 33 "vitess.io/vitess/go/vt/sqlparser" 34 "vitess.io/vitess/go/vt/srvtopo" 35 "vitess.io/vitess/go/vt/vtgate/vindexes" 36 37 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 38 querypb "vitess.io/vitess/go/vt/proto/query" 39 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 40 vtgatepb "vitess.io/vitess/go/vt/proto/vtgate" 41 ) 42 43 var testMaxMemoryRows = 100 44 var testIgnoreMaxMemoryRows = false 45 46 var _ VCursor = (*noopVCursor)(nil) 47 var _ SessionActions = (*noopVCursor)(nil) 48 49 // noopVCursor is used to build other vcursors. 50 type noopVCursor struct { 51 } 52 53 func (t *noopVCursor) InTransaction() bool { 54 return false 55 } 56 57 func (t *noopVCursor) SetCommitOrder(co vtgatepb.CommitOrder) { 58 //TODO implement me 59 panic("implement me") 60 } 61 62 func (t *noopVCursor) StreamExecutePrimitiveStandalone(ctx context.Context, primitive Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(result *sqltypes.Result) error) error { 63 return primitive.TryStreamExecute(ctx, t, bindVars, wantfields, callback) 64 } 65 66 func (t *noopVCursor) AnyAdvisoryLockTaken() bool { 67 // TODO implement me 68 panic("implement me") 69 } 70 71 func (t *noopVCursor) AddAdvisoryLock(name string) { 72 // TODO implement me 73 panic("implement me") 74 } 75 76 func (t *noopVCursor) RemoveAdvisoryLock(name string) { 77 // TODO implement me 78 panic("implement me") 79 } 80 81 func (t *noopVCursor) ReleaseLock(context.Context) error { 82 // TODO implement me 83 panic("implement me") 84 } 85 86 func (t *noopVCursor) SetExec(ctx context.Context, name string, value string) error { 87 panic("implement me") 88 } 89 90 func (t *noopVCursor) ShowExec(ctx context.Context, command sqlparser.ShowCommandType, filter *sqlparser.ShowFilter) (*sqltypes.Result, error) { 91 panic("implement me") 92 } 93 94 // SetContextWithValue implements VCursor interface. 95 func (t *noopVCursor) SetContextWithValue(key, value interface{}) func() { 96 return func() {} 97 } 98 99 // ConnCollation implements VCursor 100 func (t *noopVCursor) ConnCollation() collations.ID { 101 return collations.CollationUtf8mb4ID 102 } 103 104 func (t *noopVCursor) ExecutePrimitive(ctx context.Context, primitive Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { 105 return primitive.TryExecute(ctx, t, bindVars, wantfields) 106 } 107 108 func (t *noopVCursor) ExecutePrimitiveStandalone(ctx context.Context, primitive Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { 109 return primitive.TryExecute(ctx, t, bindVars, wantfields) 110 } 111 112 func (t *noopVCursor) StreamExecutePrimitive(ctx context.Context, primitive Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error { 113 return primitive.TryStreamExecute(ctx, t, bindVars, wantfields, callback) 114 } 115 116 func (t *noopVCursor) HasSystemVariables() bool { 117 panic("implement me") 118 } 119 120 func (t *noopVCursor) GetSystemVariables(func(k string, v string)) { 121 panic("implement me") 122 } 123 124 func (t *noopVCursor) GetWarnings() []*querypb.QueryWarning { 125 panic("implement me") 126 } 127 128 func (t *noopVCursor) VStream(ctx context.Context, rss []*srvtopo.ResolvedShard, filter *binlogdatapb.Filter, gtid string, callback func(evs []*binlogdatapb.VEvent) error) error { 129 panic("implement me") 130 } 131 132 func (t *noopVCursor) MessageStream(ctx context.Context, rss []*srvtopo.ResolvedShard, tableName string, callback func(*sqltypes.Result) error) error { 133 panic("implement me") 134 } 135 136 func (t *noopVCursor) KeyspaceAvailable(ks string) bool { 137 panic("implement me") 138 } 139 140 func (t *noopVCursor) SetDDLStrategy(strategy string) { 141 panic("implement me") 142 } 143 144 func (t *noopVCursor) GetDDLStrategy() string { 145 panic("implement me") 146 } 147 148 func (t *noopVCursor) GetSessionUUID() string { 149 panic("implement me") 150 } 151 152 func (t *noopVCursor) SetReadAfterWriteGTID(s string) { 153 panic("implement me") 154 } 155 156 func (t *noopVCursor) SetSessionEnableSystemSettings(ctx context.Context, allow bool) error { 157 panic("implement me") 158 } 159 160 func (t *noopVCursor) GetSessionEnableSystemSettings() bool { 161 panic("implement me") 162 } 163 164 func (t *noopVCursor) CanUseSetVar() bool { 165 panic("implement me") 166 } 167 168 func (t *noopVCursor) SetReadAfterWriteTimeout(f float64) { 169 panic("implement me") 170 } 171 172 func (t *noopVCursor) SetSessionTrackGTIDs(b bool) { 173 panic("implement me") 174 } 175 176 func (t *noopVCursor) HasCreatedTempTable() { 177 panic("implement me") 178 } 179 180 func (t *noopVCursor) LookupRowLockShardSession() vtgatepb.CommitOrder { 181 panic("implement me") 182 } 183 184 func (t *noopVCursor) SetFoundRows(u uint64) { 185 panic("implement me") 186 } 187 188 func (t *noopVCursor) InTransactionAndIsDML() bool { 189 panic("implement me") 190 } 191 192 func (t *noopVCursor) FindRoutedTable(sqlparser.TableName) (*vindexes.Table, error) { 193 panic("implement me") 194 } 195 196 func (t *noopVCursor) ExecuteLock(ctx context.Context, rs *srvtopo.ResolvedShard, query *querypb.BoundQuery, lockFuncType sqlparser.LockingFuncType) (*sqltypes.Result, error) { 197 panic("implement me") 198 } 199 200 func (t *noopVCursor) NeedsReservedConn() { 201 } 202 203 func (t *noopVCursor) SetUDV(key string, value any) error { 204 panic("implement me") 205 } 206 207 func (t *noopVCursor) SetSysVar(name string, expr string) { 208 // panic("implement me") 209 } 210 211 func (t *noopVCursor) InReservedConn() bool { 212 panic("implement me") 213 } 214 215 func (t *noopVCursor) ShardSession() []*srvtopo.ResolvedShard { 216 panic("implement me") 217 } 218 219 func (t *noopVCursor) ExecuteVSchema(ctx context.Context, keyspace string, vschemaDDL *sqlparser.AlterVschema) error { 220 panic("implement me") 221 } 222 223 func (t *noopVCursor) Session() SessionActions { 224 return t 225 } 226 227 func (t *noopVCursor) SetAutocommit(context.Context, bool) error { 228 panic("implement me") 229 } 230 231 func (t *noopVCursor) SetClientFoundRows(context.Context, bool) error { 232 panic("implement me") 233 } 234 235 func (t *noopVCursor) SetQueryTimeout(maxExecutionTime int64) { 236 } 237 238 func (t *noopVCursor) GetQueryTimeout(queryTimeoutFromComments int) int { 239 return queryTimeoutFromComments 240 } 241 242 func (t *noopVCursor) SetSkipQueryPlanCache(context.Context, bool) error { 243 panic("implement me") 244 } 245 246 func (t *noopVCursor) SetSQLSelectLimit(int64) error { 247 panic("implement me") 248 } 249 250 func (t *noopVCursor) SetTransactionMode(vtgatepb.TransactionMode) { 251 panic("implement me") 252 } 253 254 func (t *noopVCursor) SetWorkload(querypb.ExecuteOptions_Workload) { 255 panic("implement me") 256 } 257 258 func (t *noopVCursor) SetPlannerVersion(querypb.ExecuteOptions_PlannerVersion) { 259 panic("implement me") 260 } 261 262 func (t *noopVCursor) SetConsolidator(querypb.ExecuteOptions_Consolidator) { 263 panic("implement me") 264 } 265 266 func (t *noopVCursor) SetTarget(string) error { 267 panic("implement me") 268 } 269 270 func (t *noopVCursor) MaxMemoryRows() int { 271 return testMaxMemoryRows 272 } 273 274 func (t *noopVCursor) ExceedsMaxMemoryRows(numRows int) bool { 275 return !testIgnoreMaxMemoryRows && numRows > testMaxMemoryRows 276 } 277 278 func (t *noopVCursor) GetKeyspace() string { 279 return "" 280 } 281 282 func (t *noopVCursor) RecordWarning(warning *querypb.QueryWarning) { 283 } 284 285 func (t *noopVCursor) Execute(ctx context.Context, method string, query string, bindvars map[string]*querypb.BindVariable, rollbackOnError bool, co vtgatepb.CommitOrder) (*sqltypes.Result, error) { 286 panic("unimplemented") 287 } 288 289 func (t *noopVCursor) ExecuteMultiShard(ctx context.Context, primitive Primitive, rss []*srvtopo.ResolvedShard, queries []*querypb.BoundQuery, rollbackOnError, canAutocommit bool) (*sqltypes.Result, []error) { 290 panic("unimplemented") 291 } 292 293 func (t *noopVCursor) AutocommitApproval() bool { 294 panic("unimplemented") 295 } 296 297 func (t *noopVCursor) ExecuteStandalone(ctx context.Context, primitive Primitive, query string, bindvars map[string]*querypb.BindVariable, rs *srvtopo.ResolvedShard) (*sqltypes.Result, error) { 298 panic("unimplemented") 299 } 300 301 func (t *noopVCursor) StreamExecuteMulti(ctx context.Context, primitive Primitive, query string, rss []*srvtopo.ResolvedShard, bindVars []map[string]*querypb.BindVariable, rollbackOnError bool, autocommit bool, callback func(reply *sqltypes.Result) error) []error { 302 panic("unimplemented") 303 } 304 305 func (t *noopVCursor) ExecuteKeyspaceID(ctx context.Context, keyspace string, ksid []byte, query string, bindVars map[string]*querypb.BindVariable, rollbackOnError, autocommit bool) (*sqltypes.Result, error) { 306 panic("unimplemented") 307 } 308 309 func (t *noopVCursor) ResolveDestinations(ctx context.Context, keyspace string, ids []*querypb.Value, destinations []key.Destination) ([]*srvtopo.ResolvedShard, [][]*querypb.Value, error) { 310 return nil, nil, nil 311 } 312 313 func (t *noopVCursor) ResolveDestinationsMultiCol(ctx context.Context, keyspace string, ids [][]sqltypes.Value, destinations []key.Destination) ([]*srvtopo.ResolvedShard, [][][]sqltypes.Value, error) { 314 panic("unimplemented") 315 } 316 317 func (t *noopVCursor) GetDBDDLPluginName() string { 318 panic("unimplemented") 319 } 320 321 var _ VCursor = (*loggingVCursor)(nil) 322 var _ SessionActions = (*loggingVCursor)(nil) 323 324 // loggingVCursor logs requests and allows you to verify 325 // that the correct requests were made. 326 type loggingVCursor struct { 327 noopVCursor 328 329 shards []string 330 shardForKsid []string 331 curShardForKsid int 332 shardErr error 333 334 results []*sqltypes.Result 335 curResult int 336 resultErr error 337 338 warnings []*querypb.QueryWarning 339 340 // Optional errors that can be returned from nextResult() alongside the results for 341 // multi-shard queries 342 multiShardErrs []error 343 344 log []string 345 mu sync.Mutex 346 347 resolvedTargetTabletType topodatapb.TabletType 348 349 tableRoutes tableRoutes 350 dbDDLPlugin string 351 ksAvailable bool 352 inReservedConn bool 353 systemVariables map[string]string 354 disableSetVar bool 355 356 // map different shards to keyspaces in the test. 357 ksShardMap map[string][]string 358 359 shardSession []*srvtopo.ResolvedShard 360 } 361 362 type tableRoutes struct { 363 tbl *vindexes.Table 364 } 365 366 func (f *loggingVCursor) ExecutePrimitive(ctx context.Context, primitive Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { 367 return primitive.TryExecute(ctx, f, bindVars, wantfields) 368 } 369 370 func (f *loggingVCursor) ExecutePrimitiveStandalone(ctx context.Context, primitive Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { 371 return primitive.TryExecute(ctx, f, bindVars, wantfields) 372 } 373 374 func (f *loggingVCursor) StreamExecutePrimitive(ctx context.Context, primitive Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error { 375 return primitive.TryStreamExecute(ctx, f, bindVars, wantfields, callback) 376 } 377 378 func (f *loggingVCursor) StreamExecutePrimitiveStandalone(ctx context.Context, primitive Primitive, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(result *sqltypes.Result) error) error { 379 return primitive.TryStreamExecute(ctx, f, bindVars, wantfields, callback) 380 } 381 382 func (f *loggingVCursor) KeyspaceAvailable(ks string) bool { 383 return f.ksAvailable 384 } 385 386 func (f *loggingVCursor) HasSystemVariables() bool { 387 return len(f.systemVariables) > 0 388 } 389 390 func (f *loggingVCursor) GetSystemVariables(func(k string, v string)) { 391 panic("implement me") 392 } 393 394 func (f *loggingVCursor) SetFoundRows(u uint64) { 395 panic("implement me") 396 } 397 398 func (f *loggingVCursor) InTransactionAndIsDML() bool { 399 return false 400 } 401 402 func (f *loggingVCursor) LookupRowLockShardSession() vtgatepb.CommitOrder { 403 panic("implement me") 404 } 405 406 func (f *loggingVCursor) SetUDV(key string, value any) error { 407 f.log = append(f.log, fmt.Sprintf("UDV set with (%s,%v)", key, value)) 408 return nil 409 } 410 411 func (f *loggingVCursor) SetSysVar(name string, expr string) { 412 f.log = append(f.log, fmt.Sprintf("SysVar set with (%s,%v)", name, expr)) 413 } 414 415 func (f *loggingVCursor) NeedsReservedConn() { 416 f.log = append(f.log, "Needs Reserved Conn") 417 f.inReservedConn = true 418 } 419 420 func (f *loggingVCursor) InReservedConn() bool { 421 return f.inReservedConn 422 } 423 424 func (f *loggingVCursor) ShardSession() []*srvtopo.ResolvedShard { 425 return f.shardSession 426 } 427 428 func (f *loggingVCursor) ExecuteVSchema(context.Context, string, *sqlparser.AlterVschema) error { 429 panic("implement me") 430 } 431 432 func (f *loggingVCursor) Session() SessionActions { 433 return f 434 } 435 436 func (f *loggingVCursor) SetTarget(target string) error { 437 f.log = append(f.log, fmt.Sprintf("Target set to %s", target)) 438 return nil 439 } 440 441 func (f *loggingVCursor) GetKeyspace() string { 442 return "" 443 } 444 445 func (f *loggingVCursor) RecordWarning(warning *querypb.QueryWarning) { 446 f.warnings = append(f.warnings, warning) 447 } 448 449 func (f *loggingVCursor) Execute(ctx context.Context, method string, query string, bindvars map[string]*querypb.BindVariable, rollbackOnError bool, co vtgatepb.CommitOrder) (*sqltypes.Result, error) { 450 name := "Unknown" 451 switch co { 452 case vtgatepb.CommitOrder_NORMAL: 453 name = "Execute" 454 case vtgatepb.CommitOrder_PRE: 455 name = "ExecutePre" 456 case vtgatepb.CommitOrder_POST: 457 name = "ExecutePost" 458 case vtgatepb.CommitOrder_AUTOCOMMIT: 459 name = "ExecuteAutocommit" 460 } 461 f.log = append(f.log, fmt.Sprintf("%s %s %v %v", name, query, printBindVars(bindvars), rollbackOnError)) 462 return f.nextResult() 463 } 464 465 func (f *loggingVCursor) ExecuteMultiShard(ctx context.Context, primitive Primitive, rss []*srvtopo.ResolvedShard, queries []*querypb.BoundQuery, rollbackOnError, canAutocommit bool) (*sqltypes.Result, []error) { 466 f.log = append(f.log, fmt.Sprintf("ExecuteMultiShard %v%v %v", printResolvedShardQueries(rss, queries), rollbackOnError, canAutocommit)) 467 res, err := f.nextResult() 468 if err != nil { 469 return nil, []error{err} 470 } 471 472 return res, f.multiShardErrs 473 } 474 475 func (f *loggingVCursor) AutocommitApproval() bool { 476 return true 477 } 478 479 func (f *loggingVCursor) ExecuteStandalone(ctx context.Context, primitive Primitive, query string, bindvars map[string]*querypb.BindVariable, rs *srvtopo.ResolvedShard) (*sqltypes.Result, error) { 480 f.log = append(f.log, fmt.Sprintf("ExecuteStandalone %s %v %s %s", query, printBindVars(bindvars), rs.Target.Keyspace, rs.Target.Shard)) 481 return f.nextResult() 482 } 483 484 func (f *loggingVCursor) StreamExecuteMulti(ctx context.Context, primitive Primitive, query string, rss []*srvtopo.ResolvedShard, bindVars []map[string]*querypb.BindVariable, rollbackOnError bool, autocommit bool, callback func(reply *sqltypes.Result) error) []error { 485 f.mu.Lock() 486 f.log = append(f.log, fmt.Sprintf("StreamExecuteMulti %s %s", query, printResolvedShardsBindVars(rss, bindVars))) 487 r, err := f.nextResult() 488 f.mu.Unlock() 489 if err != nil { 490 return []error{err} 491 } 492 493 return []error{callback(r)} 494 } 495 496 func (f *loggingVCursor) ResolveDestinations(ctx context.Context, keyspace string, ids []*querypb.Value, destinations []key.Destination) ([]*srvtopo.ResolvedShard, [][]*querypb.Value, error) { 497 f.log = append(f.log, fmt.Sprintf("ResolveDestinations %v %v %v", keyspace, ids, key.DestinationsString(destinations))) 498 if f.shardErr != nil { 499 return nil, nil, f.shardErr 500 } 501 502 var rss []*srvtopo.ResolvedShard 503 var values [][]*querypb.Value 504 visited := make(map[string]int) 505 for i, destination := range destinations { 506 var shards []string 507 508 switch d := destination.(type) { 509 case key.DestinationAllShards: 510 if f.ksShardMap != nil { 511 if ksShards, exists := f.ksShardMap[keyspace]; exists { 512 shards = ksShards 513 break 514 } 515 } 516 shards = f.shards 517 case key.DestinationKeyRange: 518 shards = f.shardForKsid 519 case key.DestinationKeyspaceID: 520 if f.shardForKsid == nil || f.curShardForKsid >= len(f.shardForKsid) { 521 shards = []string{"-20"} 522 } else { 523 shards = []string{f.shardForKsid[f.curShardForKsid]} 524 f.curShardForKsid++ 525 } 526 case key.DestinationKeyspaceIDs: 527 for _, ksid := range d { 528 if string(ksid) < "\x20" { 529 shards = append(shards, "-20") 530 } else { 531 shards = append(shards, "20-") 532 } 533 } 534 case key.DestinationAnyShard: 535 // Take the first shard. 536 shards = f.shards[:1] 537 case key.DestinationNone: 538 // Nothing to do here. 539 case key.DestinationShard: 540 shards = []string{destination.String()} 541 default: 542 return nil, nil, fmt.Errorf("unsupported destination: %v", destination) 543 } 544 545 for _, shard := range shards { 546 vi, ok := visited[shard] 547 if !ok { 548 vi = len(rss) 549 visited[shard] = vi 550 rss = append(rss, &srvtopo.ResolvedShard{ 551 Target: &querypb.Target{ 552 Keyspace: keyspace, 553 Shard: shard, 554 TabletType: f.resolvedTargetTabletType, 555 }, 556 }) 557 if ids != nil { 558 values = append(values, nil) 559 } 560 } 561 if ids != nil { 562 values[vi] = append(values[vi], ids[i]) 563 } 564 } 565 } 566 return rss, values, nil 567 } 568 569 func (f *loggingVCursor) ResolveDestinationsMultiCol(ctx context.Context, keyspace string, ids [][]sqltypes.Value, destinations []key.Destination) ([]*srvtopo.ResolvedShard, [][][]sqltypes.Value, error) { 570 f.log = append(f.log, fmt.Sprintf("ResolveDestinationsMultiCol %v %v %v", keyspace, ids, key.DestinationsString(destinations))) 571 if f.shardErr != nil { 572 return nil, nil, f.shardErr 573 } 574 575 var rss []*srvtopo.ResolvedShard 576 var values [][][]sqltypes.Value 577 visited := make(map[string]int) 578 for i, destination := range destinations { 579 var shards []string 580 581 switch d := destination.(type) { 582 case key.DestinationAllShards: 583 shards = f.shards 584 case key.DestinationKeyRange: 585 shards = f.shardForKsid 586 case key.DestinationKeyspaceID: 587 if f.shardForKsid == nil || f.curShardForKsid >= len(f.shardForKsid) { 588 shards = []string{"-20"} 589 } else { 590 shards = []string{f.shardForKsid[f.curShardForKsid]} 591 f.curShardForKsid++ 592 } 593 case key.DestinationKeyspaceIDs: 594 for _, ksid := range d { 595 if string(ksid) < "\x20" { 596 shards = append(shards, "-20") 597 } else { 598 shards = append(shards, "20-") 599 } 600 } 601 case key.DestinationAnyShard: 602 // Take the first shard. 603 shards = f.shards[:1] 604 case key.DestinationNone: 605 // Nothing to do here. 606 case key.DestinationShard: 607 shards = []string{destination.String()} 608 default: 609 return nil, nil, fmt.Errorf("unsupported destination: %v", destination) 610 } 611 612 for _, shard := range shards { 613 vi, ok := visited[shard] 614 if !ok { 615 vi = len(rss) 616 visited[shard] = vi 617 rss = append(rss, &srvtopo.ResolvedShard{ 618 Target: &querypb.Target{ 619 Keyspace: keyspace, 620 Shard: shard, 621 TabletType: f.resolvedTargetTabletType, 622 }, 623 }) 624 if ids != nil { 625 values = append(values, nil) 626 } 627 } 628 if ids != nil { 629 values[vi] = append(values[vi], ids[i]) 630 } 631 } 632 } 633 return rss, values, nil 634 } 635 636 func (f *loggingVCursor) ExpectLog(t *testing.T, want []string) { 637 t.Helper() 638 if len(f.log) == 0 && len(want) == 0 { 639 return 640 } 641 if !reflect.DeepEqual(f.log, want) { 642 t.Errorf("got:\n%s\nwant:\n%s", strings.Join(f.log, "\n"), strings.Join(want, "\n")) 643 } 644 utils.MustMatch(t, want, f.log, "") 645 } 646 647 func (f *loggingVCursor) ExpectWarnings(t *testing.T, want []*querypb.QueryWarning) { 648 t.Helper() 649 if !reflect.DeepEqual(f.warnings, want) { 650 t.Errorf("vc.warnings:\n%+v\nwant:\n%+v", f.warnings, want) 651 } 652 } 653 654 func (f *loggingVCursor) Rewind() { 655 f.curShardForKsid = 0 656 f.curResult = 0 657 f.log = nil 658 f.warnings = nil 659 } 660 661 func (f *loggingVCursor) SetAutocommit(context.Context, bool) error { 662 panic("implement me") 663 } 664 665 func (f *loggingVCursor) SetClientFoundRows(context.Context, bool) error { 666 panic("implement me") 667 } 668 669 func (f *loggingVCursor) SetSkipQueryPlanCache(context.Context, bool) error { 670 panic("implement me") 671 } 672 673 func (f *loggingVCursor) SetSQLSelectLimit(int64) error { 674 panic("implement me") 675 } 676 677 func (f *loggingVCursor) SetTransactionMode(vtgatepb.TransactionMode) { 678 panic("implement me") 679 } 680 681 func (f *loggingVCursor) SetWorkload(querypb.ExecuteOptions_Workload) { 682 panic("implement me") 683 } 684 685 func (f *loggingVCursor) SetPlannerVersion(querypb.ExecuteOptions_PlannerVersion) { 686 panic("implement me") 687 } 688 689 func (f *loggingVCursor) FindRoutedTable(tbl sqlparser.TableName) (*vindexes.Table, error) { 690 f.log = append(f.log, fmt.Sprintf("FindTable(%s)", sqlparser.String(tbl))) 691 return f.tableRoutes.tbl, nil 692 } 693 694 func (f *loggingVCursor) GetDBDDLPluginName() string { 695 return f.dbDDLPlugin 696 } 697 698 func (f *loggingVCursor) nextResult() (*sqltypes.Result, error) { 699 if f.results == nil || f.curResult >= len(f.results) { 700 return &sqltypes.Result{}, f.resultErr 701 } 702 703 r := f.results[f.curResult] 704 f.curResult++ 705 if r == nil { 706 return &sqltypes.Result{}, f.resultErr 707 } 708 return r, nil 709 } 710 711 func (f *loggingVCursor) CanUseSetVar() bool { 712 useSetVar := sqlparser.IsMySQL80AndAbove() && !f.disableSetVar 713 if useSetVar { 714 f.log = append(f.log, "SET_VAR can be used") 715 } 716 return useSetVar 717 } 718 719 func (t *noopVCursor) VExplainLogging() {} 720 func (t *noopVCursor) DisableLogging() {} 721 func (t *noopVCursor) GetVExplainLogs() []ExecuteEntry { 722 return nil 723 } 724 func (t *noopVCursor) GetLogs() ([]ExecuteEntry, error) { 725 return nil, nil 726 } 727 728 func expectResult(t *testing.T, msg string, result, want *sqltypes.Result) { 729 t.Helper() 730 if !reflect.DeepEqual(result, want) { 731 t.Errorf("%s:\n%v\nwant:\n%v", msg, result, want) 732 } 733 } 734 735 func printBindVars(bindvars map[string]*querypb.BindVariable) string { 736 var keys []string 737 for k := range bindvars { 738 keys = append(keys, k) 739 } 740 sort.Strings(keys) 741 buf := &bytes.Buffer{} 742 for i, k := range keys { 743 if i > 0 { 744 fmt.Fprintf(buf, " ") 745 } 746 fmt.Fprintf(buf, "%s: %v", k, bindvars[k]) 747 } 748 return buf.String() 749 } 750 751 func printResolvedShardQueries(rss []*srvtopo.ResolvedShard, queries []*querypb.BoundQuery) string { 752 buf := &bytes.Buffer{} 753 for i, rs := range rss { 754 fmt.Fprintf(buf, "%s.%s: %s {%s} ", rs.Target.Keyspace, rs.Target.Shard, queries[i].Sql, printBindVars(queries[i].BindVariables)) 755 } 756 return buf.String() 757 } 758 759 func printResolvedShardsBindVars(rss []*srvtopo.ResolvedShard, bvs []map[string]*querypb.BindVariable) string { 760 buf := &bytes.Buffer{} 761 for i, rs := range rss { 762 fmt.Fprintf(buf, "%s.%s: {%v} ", rs.Target.Keyspace, rs.Target.Shard, printBindVars(bvs[i])) 763 } 764 return buf.String() 765 }