github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/rowexec/processors_test.go (about) 1 // Copyright 2017 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package rowexec 12 13 import ( 14 "context" 15 "fmt" 16 "net/url" 17 "strconv" 18 "strings" 19 "sync" 20 "sync/atomic" 21 "testing" 22 23 "github.com/cockroachdb/cockroach/pkg/base" 24 "github.com/cockroachdb/cockroach/pkg/kv/kvserver" 25 "github.com/cockroachdb/cockroach/pkg/roachpb" 26 "github.com/cockroachdb/cockroach/pkg/security" 27 "github.com/cockroachdb/cockroach/pkg/settings/cluster" 28 "github.com/cockroachdb/cockroach/pkg/sql/execinfra" 29 "github.com/cockroachdb/cockroach/pkg/sql/execinfrapb" 30 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 31 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 32 "github.com/cockroachdb/cockroach/pkg/sql/types" 33 "github.com/cockroachdb/cockroach/pkg/testutils" 34 "github.com/cockroachdb/cockroach/pkg/testutils/distsqlutils" 35 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 36 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 37 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 38 "github.com/cockroachdb/cockroach/pkg/util/syncutil" 39 "github.com/jackc/pgx" 40 ) 41 42 func TestPostProcess(t *testing.T) { 43 defer leaktest.AfterTest(t)() 44 45 v := [10]sqlbase.EncDatum{} 46 for i := range v { 47 v[i] = sqlbase.DatumToEncDatum(types.Int, tree.NewDInt(tree.DInt(i))) 48 } 49 50 // We run the same input rows through various PostProcessSpecs. 51 input := sqlbase.EncDatumRows{ 52 {v[0], v[1], v[2]}, 53 {v[0], v[1], v[3]}, 54 {v[0], v[1], v[4]}, 55 {v[0], v[2], v[3]}, 56 {v[0], v[2], v[4]}, 57 {v[0], v[3], v[4]}, 58 {v[1], v[2], v[3]}, 59 {v[1], v[2], v[4]}, 60 {v[1], v[3], v[4]}, 61 {v[2], v[3], v[4]}, 62 } 63 64 testCases := []struct { 65 post execinfrapb.PostProcessSpec 66 outputTypes []*types.T 67 expNeededCols []int 68 expected string 69 }{ 70 { 71 post: execinfrapb.PostProcessSpec{}, 72 outputTypes: sqlbase.ThreeIntCols, 73 expNeededCols: []int{0, 1, 2}, 74 expected: "[[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]]", 75 }, 76 77 // Filter. 78 { 79 post: execinfrapb.PostProcessSpec{ 80 Filter: execinfrapb.Expression{Expr: "@1 = 1"}, 81 }, 82 outputTypes: sqlbase.ThreeIntCols, 83 expNeededCols: []int{0, 1, 2}, 84 expected: "[[1 2 3] [1 2 4] [1 3 4]]", 85 }, 86 87 // Projection. 88 { 89 post: execinfrapb.PostProcessSpec{ 90 Projection: true, 91 OutputColumns: []uint32{0, 2}, 92 }, 93 outputTypes: sqlbase.TwoIntCols, 94 expNeededCols: []int{0, 2}, 95 expected: "[[0 2] [0 3] [0 4] [0 3] [0 4] [0 4] [1 3] [1 4] [1 4] [2 4]]", 96 }, 97 98 // Filter and projection; filter only refers to projected column. 99 { 100 post: execinfrapb.PostProcessSpec{ 101 Filter: execinfrapb.Expression{Expr: "@1 = 1"}, 102 Projection: true, 103 OutputColumns: []uint32{0, 2}, 104 }, 105 outputTypes: sqlbase.TwoIntCols, 106 expNeededCols: []int{0, 2}, 107 expected: "[[1 3] [1 4] [1 4]]", 108 }, 109 110 // Filter and projection; filter refers to non-projected column. 111 { 112 post: execinfrapb.PostProcessSpec{ 113 Filter: execinfrapb.Expression{Expr: "@2 = 2"}, 114 Projection: true, 115 OutputColumns: []uint32{0, 2}, 116 }, 117 outputTypes: sqlbase.TwoIntCols, 118 expNeededCols: []int{0, 1, 2}, 119 expected: "[[0 3] [0 4] [1 3] [1 4]]", 120 }, 121 122 // Rendering. 123 { 124 post: execinfrapb.PostProcessSpec{ 125 RenderExprs: []execinfrapb.Expression{{Expr: "@1"}, {Expr: "@2"}, {Expr: "@1 + @2"}}, 126 }, 127 outputTypes: sqlbase.ThreeIntCols, 128 expNeededCols: []int{0, 1}, 129 expected: "[[0 1 1] [0 1 1] [0 1 1] [0 2 2] [0 2 2] [0 3 3] [1 2 3] [1 2 3] [1 3 4] [2 3 5]]", 130 }, 131 132 // Rendering and filtering; filter refers to column used in rendering. 133 { 134 post: execinfrapb.PostProcessSpec{ 135 Filter: execinfrapb.Expression{Expr: "@2 = 2"}, 136 RenderExprs: []execinfrapb.Expression{{Expr: "@1"}, {Expr: "@2"}, {Expr: "@1 + @2"}}, 137 }, 138 outputTypes: sqlbase.ThreeIntCols, 139 expNeededCols: []int{0, 1}, 140 expected: "[[0 2 2] [0 2 2] [1 2 3] [1 2 3]]", 141 }, 142 143 // Rendering and filtering; filter refers to column not used in rendering. 144 { 145 post: execinfrapb.PostProcessSpec{ 146 Filter: execinfrapb.Expression{Expr: "@3 = 4"}, 147 RenderExprs: []execinfrapb.Expression{{Expr: "@1"}, {Expr: "@2"}, {Expr: "@1 + @2"}}, 148 }, 149 outputTypes: sqlbase.ThreeIntCols, 150 expNeededCols: []int{0, 1, 2}, 151 expected: "[[0 1 1] [0 2 2] [0 3 3] [1 2 3] [1 3 4] [2 3 5]]", 152 }, 153 154 // More complex rendering expressions. 155 { 156 post: execinfrapb.PostProcessSpec{ 157 RenderExprs: []execinfrapb.Expression{ 158 {Expr: "@1 - @2"}, 159 {Expr: "@1 + @2 * @3"}, 160 {Expr: "@1 >= 2"}, 161 {Expr: "((@1 = @2 - 1))"}, 162 {Expr: "@1 = @2 - 1 OR @1 = @3 - 2"}, 163 {Expr: "@1 = @2 - 1 AND @1 = @3 - 2"}, 164 }, 165 }, 166 outputTypes: []*types.T{types.Int, types.Int, types.Bool, types.Bool, types.Bool, types.Bool}, 167 expNeededCols: []int{0, 1, 2}, 168 expected: "[" + strings.Join([]string{ 169 /* 0 1 2 */ "[-1 2 false true true true]", 170 /* 0 1 3 */ "[-1 3 false true true false]", 171 /* 0 1 4 */ "[-1 4 false true true false]", 172 /* 0 2 3 */ "[-2 6 false false false false]", 173 /* 0 2 4 */ "[-2 8 false false false false]", 174 /* 0 3 4 */ "[-3 12 false false false false]", 175 /* 1 2 3 */ "[-1 7 false true true true]", 176 /* 1 2 4 */ "[-1 9 false true true false]", 177 /* 1 3 4 */ "[-2 13 false false false false]", 178 /* 2 3 4 */ "[-1 14 true true true true]", 179 }, " ") + "]", 180 }, 181 182 // Offset. 183 { 184 post: execinfrapb.PostProcessSpec{Offset: 3}, 185 outputTypes: sqlbase.ThreeIntCols, 186 expNeededCols: []int{0, 1, 2}, 187 expected: "[[0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]]", 188 }, 189 190 // Limit. 191 { 192 post: execinfrapb.PostProcessSpec{Limit: 3}, 193 outputTypes: sqlbase.ThreeIntCols, 194 expNeededCols: []int{0, 1, 2}, 195 expected: "[[0 1 2] [0 1 3] [0 1 4]]", 196 }, 197 { 198 post: execinfrapb.PostProcessSpec{Limit: 9}, 199 outputTypes: sqlbase.ThreeIntCols, 200 expNeededCols: []int{0, 1, 2}, 201 expected: "[[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4]]", 202 }, 203 { 204 post: execinfrapb.PostProcessSpec{Limit: 10}, 205 outputTypes: sqlbase.ThreeIntCols, 206 expNeededCols: []int{0, 1, 2}, 207 expected: "[[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]]", 208 }, 209 { 210 post: execinfrapb.PostProcessSpec{Limit: 11}, 211 outputTypes: sqlbase.ThreeIntCols, 212 expNeededCols: []int{0, 1, 2}, 213 expected: "[[0 1 2] [0 1 3] [0 1 4] [0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]]", 214 }, 215 216 // Offset + limit. 217 { 218 post: execinfrapb.PostProcessSpec{Offset: 3, Limit: 2}, 219 outputTypes: sqlbase.ThreeIntCols, 220 expNeededCols: []int{0, 1, 2}, 221 expected: "[[0 2 3] [0 2 4]]", 222 }, 223 { 224 post: execinfrapb.PostProcessSpec{Offset: 3, Limit: 6}, 225 outputTypes: sqlbase.ThreeIntCols, 226 expNeededCols: []int{0, 1, 2}, 227 expected: "[[0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4]]", 228 }, 229 { 230 post: execinfrapb.PostProcessSpec{Offset: 3, Limit: 7}, 231 outputTypes: sqlbase.ThreeIntCols, 232 expNeededCols: []int{0, 1, 2}, 233 expected: "[[0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]]", 234 }, 235 { 236 post: execinfrapb.PostProcessSpec{Offset: 3, Limit: 8}, 237 outputTypes: sqlbase.ThreeIntCols, 238 expNeededCols: []int{0, 1, 2}, 239 expected: "[[0 2 3] [0 2 4] [0 3 4] [1 2 3] [1 2 4] [1 3 4] [2 3 4]]", 240 }, 241 242 // Filter + offset. 243 { 244 post: execinfrapb.PostProcessSpec{ 245 Filter: execinfrapb.Expression{Expr: "@1 = 1"}, 246 Offset: 1, 247 }, 248 outputTypes: sqlbase.ThreeIntCols, 249 expNeededCols: []int{0, 1, 2}, 250 expected: "[[1 2 4] [1 3 4]]", 251 }, 252 253 // Filter + limit. 254 { 255 post: execinfrapb.PostProcessSpec{ 256 Filter: execinfrapb.Expression{Expr: "@1 = 1"}, 257 Limit: 2, 258 }, 259 outputTypes: sqlbase.ThreeIntCols, 260 expNeededCols: []int{0, 1, 2}, 261 expected: "[[1 2 3] [1 2 4]]", 262 }, 263 } 264 265 for tcIdx, tc := range testCases { 266 t.Run(strconv.Itoa(tcIdx), func(t *testing.T) { 267 inBuf := distsqlutils.NewRowBuffer(sqlbase.ThreeIntCols, input, distsqlutils.RowBufferArgs{}) 268 outBuf := &distsqlutils.RowBuffer{} 269 270 var out execinfra.ProcOutputHelper 271 evalCtx := tree.NewTestingEvalContext(cluster.MakeTestingClusterSettings()) 272 defer evalCtx.Stop(context.Background()) 273 if err := out.Init(&tc.post, inBuf.OutputTypes(), evalCtx, outBuf); err != nil { 274 t.Fatal(err) 275 } 276 277 // Verify NeededColumns(). 278 count := 0 279 neededCols := out.NeededColumns() 280 neededCols.ForEach(func(_ int) { 281 count++ 282 }) 283 if count != len(tc.expNeededCols) { 284 t.Fatalf("invalid neededCols length %d, expected %d", count, len(tc.expNeededCols)) 285 } 286 for _, col := range tc.expNeededCols { 287 if !neededCols.Contains(col) { 288 t.Errorf("column %d not found in neededCols", col) 289 } 290 } 291 // Run the rows through the helper. 292 for i := range input { 293 status, err := out.EmitRow(context.Background(), input[i]) 294 if err != nil { 295 t.Fatal(err) 296 } 297 if status != execinfra.NeedMoreRows { 298 out.Close() 299 break 300 } 301 } 302 var res sqlbase.EncDatumRows 303 for { 304 row := outBuf.NextNoMeta(t) 305 if row == nil { 306 break 307 } 308 res = append(res, row) 309 } 310 311 if str := res.String(tc.outputTypes); str != tc.expected { 312 t.Errorf("expected output:\n %s\ngot:\n %s\n", tc.expected, str) 313 } 314 }) 315 } 316 } 317 318 func TestAggregatorSpecAggregationEquals(t *testing.T) { 319 defer leaktest.AfterTest(t)() 320 321 // Used for FilterColIdx *uint32. 322 colIdx1 := uint32(0) 323 colIdx2 := uint32(1) 324 325 for i, tc := range []struct { 326 a, b execinfrapb.AggregatorSpec_Aggregation 327 expected bool 328 }{ 329 // Func tests. 330 { 331 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL}, 332 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL}, 333 expected: true, 334 }, 335 { 336 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL}, 337 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_AVG}, 338 expected: false, 339 }, 340 341 // ColIdx tests. 342 { 343 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, ColIdx: []uint32{1, 2}}, 344 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, ColIdx: []uint32{1, 2}}, 345 expected: true, 346 }, 347 { 348 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, ColIdx: []uint32{1}}, 349 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, ColIdx: []uint32{1, 3}}, 350 expected: false, 351 }, 352 { 353 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, ColIdx: []uint32{1, 2}}, 354 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, ColIdx: []uint32{1, 3}}, 355 expected: false, 356 }, 357 358 // FilterColIdx tests. 359 { 360 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, FilterColIdx: &colIdx1}, 361 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, FilterColIdx: &colIdx1}, 362 expected: true, 363 }, 364 { 365 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, FilterColIdx: &colIdx1}, 366 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL}, 367 expected: false, 368 }, 369 { 370 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, FilterColIdx: &colIdx1}, 371 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, FilterColIdx: &colIdx2}, 372 expected: false, 373 }, 374 375 // Distinct tests. 376 { 377 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, Distinct: true}, 378 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, Distinct: true}, 379 expected: true, 380 }, 381 { 382 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, Distinct: false}, 383 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, Distinct: false}, 384 expected: true, 385 }, 386 { 387 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, Distinct: false}, 388 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL}, 389 expected: true, 390 }, 391 { 392 a: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL, Distinct: true}, 393 b: execinfrapb.AggregatorSpec_Aggregation{Func: execinfrapb.AggregatorSpec_ANY_NOT_NULL}, 394 expected: false, 395 }, 396 } { 397 if actual := tc.a.Equals(tc.b); tc.expected != actual { 398 t.Fatalf("case %d: incorrect result from %#v.Equals(%#v), expected %t, actual %t", i, tc.a, tc.b, tc.expected, actual) 399 } 400 401 // Reflexive case. 402 if actual := tc.b.Equals(tc.a); tc.expected != actual { 403 t.Fatalf("case %d: incorrect result from %#v.Equals(%#v), expected %t, actual %t", i, tc.b, tc.a, tc.expected, actual) 404 } 405 } 406 } 407 408 func TestProcessorBaseContext(t *testing.T) { 409 defer leaktest.AfterTest(t)() 410 411 ctx := context.Background() 412 st := cluster.MakeTestingClusterSettings() 413 414 runTest := func(t *testing.T, f func(noop *noopProcessor)) { 415 evalCtx := tree.MakeTestingEvalContext(st) 416 flowCtx := &execinfra.FlowCtx{ 417 Cfg: &execinfra.ServerConfig{Settings: st}, 418 EvalCtx: &evalCtx, 419 } 420 defer flowCtx.EvalCtx.Stop(ctx) 421 422 input := execinfra.NewRepeatableRowSource(sqlbase.OneIntCol, sqlbase.MakeIntRows(10, 1)) 423 noop, err := newNoopProcessor(flowCtx, 0 /* processorID */, input, &execinfrapb.PostProcessSpec{}, &rowDisposer{}) 424 if err != nil { 425 t.Fatal(err) 426 } 427 noop.Start(ctx) 428 origCtx := noop.Ctx 429 430 // The context should be valid after Start but before Next is called in case 431 // ConsumerDone or ConsumerClosed are called without calling Next. 432 if noop.Ctx == nil { 433 t.Fatalf("ProcessorBase.ctx not initialized") 434 } 435 f(noop) 436 // The context should be reset after ConsumerClosed is called so that any 437 // subsequent logging calls will not operate on closed spans. 438 if noop.Ctx != origCtx { 439 t.Fatalf("ProcessorBase.ctx not reset on close") 440 } 441 } 442 443 t.Run("next-close", func(t *testing.T) { 444 runTest(t, func(noop *noopProcessor) { 445 // The normal case: a call to Next followed by the processor being closed. 446 noop.Next() 447 noop.ConsumerClosed() 448 }) 449 }) 450 451 t.Run("close-without-next", func(t *testing.T) { 452 runTest(t, func(noop *noopProcessor) { 453 // A processor can be closed without Next ever being called. 454 noop.ConsumerClosed() 455 }) 456 }) 457 458 t.Run("close-next", func(t *testing.T) { 459 runTest(t, func(noop *noopProcessor) { 460 // After the processor is closed, it can't be opened via a call to Next. 461 noop.ConsumerClosed() 462 noop.Next() 463 }) 464 }) 465 466 t.Run("next-close-next", func(t *testing.T) { 467 runTest(t, func(noop *noopProcessor) { 468 // A spurious call to Next after the processor is closed. 469 noop.Next() 470 noop.ConsumerClosed() 471 noop.Next() 472 }) 473 }) 474 475 t.Run("next-close-close", func(t *testing.T) { 476 runTest(t, func(noop *noopProcessor) { 477 // Close should be idempotent. 478 noop.Next() 479 noop.ConsumerClosed() 480 noop.ConsumerClosed() 481 }) 482 }) 483 } 484 485 // Test that processors swallow ReadWithinUncertaintyIntervalErrors once they 486 // started draining. The code that this test is checking is in ProcessorBase. 487 // The test is written using high-level interfaces since what's truly 488 // interesting to test is the integration between DistSQL and KV. 489 func TestDrainingProcessorSwallowsUncertaintyError(t *testing.T) { 490 defer leaktest.AfterTest(t)() 491 492 // We're going to test by running a query that selects rows 1..10 with limit 493 // 5. Out of these, rows 1..5 are on node 1, 6..10 on node 2. We're going to 494 // block the read on node 1 until the client gets the 5 rows from node 2. Then 495 // we're going to inject an uncertainty error in the blocked read. The point 496 // of the test is to check that the error is swallowed, because the processor 497 // on the gateway is already draining. 498 // We need to construct this scenario with multiple nodes since you can't have 499 // uncertainty errors if all the data is on the gateway. Then, we'll use a 500 // UNION query to force DistSQL to plan multiple TableReaders (otherwise it 501 // plans just one for LIMIT queries). The point of the test is to force one 502 // extra batch to be read without its rows actually being needed. This is not 503 // entirely easy to cause given the current implementation details. 504 505 var ( 506 // trapRead is set, atomically, once the test wants to block a read on the 507 // first node. 508 trapRead int64 509 blockedRead struct { 510 syncutil.Mutex 511 unblockCond *sync.Cond 512 shouldUnblock bool 513 } 514 ) 515 516 blockedRead.unblockCond = sync.NewCond(&blockedRead.Mutex) 517 518 tc := serverutils.StartTestCluster(t, 3, /* numNodes */ 519 base.TestClusterArgs{ 520 ReplicationMode: base.ReplicationManual, 521 ServerArgs: base.TestServerArgs{ 522 UseDatabase: "test", 523 }, 524 ServerArgsPerNode: map[int]base.TestServerArgs{ 525 0: { 526 Knobs: base.TestingKnobs{ 527 Store: &kvserver.StoreTestingKnobs{ 528 TestingRequestFilter: func(_ context.Context, ba roachpb.BatchRequest) *roachpb.Error { 529 if atomic.LoadInt64(&trapRead) == 0 { 530 return nil 531 } 532 // We're going to trap a read for the rows [1,5]. 533 req, ok := ba.GetArg(roachpb.Scan) 534 if !ok { 535 return nil 536 } 537 key := req.(*roachpb.ScanRequest).Key.String() 538 endKey := req.(*roachpb.ScanRequest).EndKey.String() 539 if strings.Contains(key, "/1") && strings.Contains(endKey, "5/") { 540 blockedRead.Lock() 541 for !blockedRead.shouldUnblock { 542 blockedRead.unblockCond.Wait() 543 } 544 blockedRead.Unlock() 545 return roachpb.NewError( 546 roachpb.NewReadWithinUncertaintyIntervalError( 547 ba.Timestamp, /* readTs */ 548 ba.Timestamp.Add(1, 0), /* existingTs */ 549 ba.Txn)) 550 } 551 return nil 552 }, 553 }, 554 }, 555 UseDatabase: "test", 556 }, 557 }, 558 }) 559 defer tc.Stopper().Stop(context.Background()) 560 561 origDB0 := tc.ServerConn(0) 562 sqlutils.CreateTable(t, origDB0, "t", 563 "x INT PRIMARY KEY", 564 10, /* numRows */ 565 sqlutils.ToRowFn(sqlutils.RowIdxFn)) 566 567 // Split the table and move half of the rows to the 2nd node. We'll block the 568 // read on the first node, and so the rows we're going to be expecting are the 569 // ones from the second node. 570 _, err := origDB0.Exec(fmt.Sprintf(` 571 ALTER TABLE "t" SPLIT AT VALUES (6); 572 ALTER TABLE "t" EXPERIMENTAL_RELOCATE VALUES (ARRAY[%d], 0), (ARRAY[%d], 6); 573 `, 574 tc.Server(0).GetFirstStoreID(), 575 tc.Server(1).GetFirstStoreID())) 576 if err != nil { 577 t.Fatal(err) 578 } 579 580 // Ensure that the range cache is populated. 581 if _, err = origDB0.Exec(`SELECT count(1) FROM t`); err != nil { 582 t.Fatal(err) 583 } 584 585 // Disable results buffering - we want to ensure that the server doesn't do 586 // any automatic retries, and also we use the client to know when to unblock 587 // the read. 588 if _, err := origDB0.Exec( 589 `SET CLUSTER SETTING sql.defaults.results_buffer.size = '0'`, 590 ); err != nil { 591 t.Fatal(err) 592 } 593 594 pgURL, cleanup := sqlutils.PGUrl( 595 t, tc.Server(0).ServingSQLAddr(), t.Name(), url.User(security.RootUser)) 596 defer cleanup() 597 pgURL.Path = `test` 598 pgxConfig, err := pgx.ParseConnectionString(pgURL.String()) 599 if err != nil { 600 t.Fatal(err) 601 } 602 conn, err := pgx.Connect(pgxConfig) 603 if err != nil { 604 t.Fatal(err) 605 } 606 607 atomic.StoreInt64(&trapRead, 1) 608 609 // Run with the vectorize off and on. 610 testutils.RunTrueAndFalse(t, "vectorize", func(t *testing.T, vectorize bool) { 611 // We're going to run the test twice in each vectorize configuration. Once 612 // in "dummy" node, which just verifies that the test is not fooling itself 613 // by increasing the limit from 5 to 6 and checking that we get the injected 614 // error in that case. 615 testutils.RunTrueAndFalse(t, "dummy", func(t *testing.T, dummy bool) { 616 // Reset the blocking condition. 617 blockedRead.Lock() 618 blockedRead.shouldUnblock = false 619 blockedRead.Unlock() 620 // Force DistSQL to distribute the query. Otherwise, as of Nov 2018, it's hard 621 // to convince it to distribute a query that uses an index. 622 if _, err := conn.Exec("set distsql='always'"); err != nil { 623 t.Fatal(err) 624 } 625 vectorizeMode := "off" 626 if vectorize { 627 vectorizeMode = "on" 628 } 629 630 if _, err := conn.Exec(fmt.Sprintf("set vectorize='%s'; set vectorize_row_count_threshold=0", vectorizeMode)); err != nil { 631 t.Fatal(err) 632 } 633 634 limit := 5 635 if dummy { 636 limit = 6 637 } 638 query := fmt.Sprintf( 639 "select x from t where x <= 5 union all select x from t where x > 5 limit %d", 640 limit) 641 rows, err := conn.Query(query) 642 if err != nil { 643 t.Fatal(err) 644 } 645 defer rows.Close() 646 i := 6 647 for rows.Next() { 648 var n int 649 if err := rows.Scan(&n); err != nil { 650 t.Fatal(err) 651 } 652 if n != i { 653 t.Fatalf("expected row: %d but got: %d", i, n) 654 } 655 i++ 656 // After we've gotten all the rows from the second node, let the first node 657 // return an uncertainty error. 658 if n == 10 { 659 blockedRead.Lock() 660 // Set shouldUnblock to true to have any reads that would block return 661 // an uncertainty error. Signal the cond to wake up any reads that have 662 // already been blocked. 663 blockedRead.shouldUnblock = true 664 blockedRead.unblockCond.Signal() 665 blockedRead.Unlock() 666 } 667 } 668 err = rows.Err() 669 if !dummy { 670 if err != nil { 671 t.Fatal(err) 672 } 673 } else { 674 if !testutils.IsError(err, "ReadWithinUncertaintyIntervalError") { 675 t.Fatalf("expected injected error, got: %v", err) 676 } 677 } 678 }) 679 }) 680 }