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  }