github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/conn_io_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 sql
    12  
    13  import (
    14  	"context"
    15  	"fmt"
    16  	"io"
    17  	"testing"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    20  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    21  )
    22  
    23  func assertStmt(t *testing.T, cmd Command, exp string) {
    24  	t.Helper()
    25  	stmt, ok := cmd.(ExecStmt)
    26  	if !ok {
    27  		t.Fatalf("expected ExecStmt, got %T", cmd)
    28  	}
    29  	if stmt.AST.String() != exp {
    30  		t.Fatalf("expected statement %s, got %s", exp, stmt)
    31  	}
    32  }
    33  
    34  func assertPrepareStmt(t *testing.T, cmd Command, expName string) {
    35  	t.Helper()
    36  	ps, ok := cmd.(PrepareStmt)
    37  	if !ok {
    38  		t.Fatalf("expected PrepareStmt, got %T", cmd)
    39  	}
    40  	if ps.Name != expName {
    41  		t.Fatalf("expected name %s, got %s", expName, ps.Name)
    42  	}
    43  }
    44  
    45  func mustPush(ctx context.Context, t *testing.T, buf *StmtBuf, cmd Command) {
    46  	t.Helper()
    47  	if err := buf.Push(ctx, cmd); err != nil {
    48  		t.Fatalf("%s", err)
    49  	}
    50  }
    51  
    52  func TestStmtBuf(t *testing.T) {
    53  	defer leaktest.AfterTest(t)()
    54  
    55  	ctx := context.Background()
    56  	s1, err := parser.ParseOne("SELECT 1")
    57  	if err != nil {
    58  		t.Fatal(err)
    59  	}
    60  	s2, err := parser.ParseOne("SELECT 2")
    61  	if err != nil {
    62  		t.Fatal(err)
    63  	}
    64  	s3, err := parser.ParseOne("SELECT 3")
    65  	if err != nil {
    66  		t.Fatal(err)
    67  	}
    68  	s4, err := parser.ParseOne("SELECT 4")
    69  	if err != nil {
    70  		t.Fatal(err)
    71  	}
    72  	buf := NewStmtBuf()
    73  	mustPush(ctx, t, buf, ExecStmt{Statement: s1})
    74  	mustPush(ctx, t, buf, ExecStmt{Statement: s2})
    75  	mustPush(ctx, t, buf, ExecStmt{Statement: s3})
    76  	mustPush(ctx, t, buf, ExecStmt{Statement: s4})
    77  
    78  	// Check that, while we don't manually advance the cursor, we keep getting the
    79  	// same statement.
    80  	expPos := CmdPos(0)
    81  	for i := 0; i < 2; i++ {
    82  		cmd, pos, err := buf.CurCmd()
    83  		if err != nil {
    84  			t.Fatal(err)
    85  		}
    86  		if pos != expPos {
    87  			t.Fatalf("expected pos to be %d, got: %d", expPos, pos)
    88  		}
    89  		assertStmt(t, cmd, "SELECT 1")
    90  	}
    91  
    92  	buf.AdvanceOne()
    93  	expPos++
    94  	cmd, pos, err := buf.CurCmd()
    95  	if err != nil {
    96  		t.Fatal(err)
    97  	}
    98  	if pos != expPos {
    99  		t.Fatalf("expected pos to be %d, got: %d", expPos, pos)
   100  	}
   101  	assertStmt(t, cmd, "SELECT 2")
   102  
   103  	buf.AdvanceOne()
   104  	expPos++
   105  	cmd, pos, err = buf.CurCmd()
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  	if pos != expPos {
   110  		t.Fatalf("expected pos to be %d, got: %d", expPos, pos)
   111  	}
   112  	assertStmt(t, cmd, "SELECT 3")
   113  
   114  	buf.AdvanceOne()
   115  	expPos++
   116  	cmd, pos, err = buf.CurCmd()
   117  	if err != nil {
   118  		t.Fatal(err)
   119  	}
   120  	if pos != expPos {
   121  		t.Fatalf("expected pos to be %d, got: %d", expPos, pos)
   122  	}
   123  	assertStmt(t, cmd, "SELECT 4")
   124  
   125  	// Now rewind.
   126  	expPos = 1
   127  	buf.Rewind(ctx, expPos)
   128  	cmd, pos, err = buf.CurCmd()
   129  	if err != nil {
   130  		t.Fatal(err)
   131  	}
   132  	if pos != expPos {
   133  		t.Fatalf("expected pos to be %d, got: %d", expPos, pos)
   134  	}
   135  	assertStmt(t, cmd, "SELECT 2")
   136  }
   137  
   138  // Test that a reader blocked for an incoming statement is unblocked when that
   139  // statement arrives.
   140  func TestStmtBufSignal(t *testing.T) {
   141  	defer leaktest.AfterTest(t)()
   142  
   143  	ctx := context.Background()
   144  	buf := NewStmtBuf()
   145  	s1, err := parser.ParseOne("SELECT 1")
   146  	if err != nil {
   147  		t.Fatal(err)
   148  	}
   149  	go func() {
   150  		_ = buf.Push(ctx, ExecStmt{Statement: s1})
   151  	}()
   152  
   153  	expPos := CmdPos(0)
   154  	cmd, pos, err := buf.CurCmd()
   155  	if err != nil {
   156  		t.Fatal(err)
   157  	}
   158  	if pos != expPos {
   159  		t.Fatalf("expected pos to be %d, got: %d", expPos, pos)
   160  	}
   161  	assertStmt(t, cmd, "SELECT 1")
   162  }
   163  
   164  func TestStmtBufLtrim(t *testing.T) {
   165  	defer leaktest.AfterTest(t)()
   166  
   167  	ctx := context.Background()
   168  	buf := NewStmtBuf()
   169  	for i := 0; i < 5; i++ {
   170  		stmt, err := parser.ParseOne(
   171  			fmt.Sprintf("SELECT %d", i))
   172  		if err != nil {
   173  			t.Fatal(err)
   174  		}
   175  		mustPush(ctx, t, buf, ExecStmt{Statement: stmt})
   176  	}
   177  	// Advance the cursor so that we can trim.
   178  	buf.AdvanceOne()
   179  	buf.AdvanceOne()
   180  	trimPos := CmdPos(2)
   181  	buf.ltrim(ctx, trimPos)
   182  	if l := buf.mu.data.Len(); l != 3 {
   183  		t.Fatalf("expected 3 left, got: %d", l)
   184  	}
   185  	if s := buf.mu.startPos; s != 2 {
   186  		t.Fatalf("expected start pos 2, got: %d", s)
   187  	}
   188  }
   189  
   190  // Test that, after Close() is called, buf.CurCmd() returns io.EOF even if
   191  // there were commands queued up.
   192  func TestStmtBufClose(t *testing.T) {
   193  	defer leaktest.AfterTest(t)()
   194  
   195  	ctx := context.Background()
   196  	buf := NewStmtBuf()
   197  	stmt, err := parser.ParseOne("SELECT 1")
   198  	if err != nil {
   199  		t.Fatal(err)
   200  	}
   201  	mustPush(ctx, t, buf, ExecStmt{Statement: stmt})
   202  	buf.Close()
   203  
   204  	_, _, err = buf.CurCmd()
   205  	if err != io.EOF {
   206  		t.Fatalf("expected EOF, got: %v", err)
   207  	}
   208  }
   209  
   210  // Test that a call to Close() unblocks a CurCmd() call.
   211  func TestStmtBufCloseUnblocksReader(t *testing.T) {
   212  	defer leaktest.AfterTest(t)()
   213  
   214  	buf := NewStmtBuf()
   215  
   216  	go func() {
   217  		buf.Close()
   218  	}()
   219  
   220  	_, _, err := buf.CurCmd()
   221  	if err != io.EOF {
   222  		t.Fatalf("expected EOF, got: %v", err)
   223  	}
   224  }
   225  
   226  // Test that the buffer can hold and return other kinds of commands intermixed
   227  // with ExecStmt.
   228  func TestStmtBufPreparedStmt(t *testing.T) {
   229  	defer leaktest.AfterTest(t)()
   230  
   231  	buf := NewStmtBuf()
   232  	ctx := context.Background()
   233  
   234  	s1, err := parser.ParseOne("SELECT 1")
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  	mustPush(ctx, t, buf, ExecStmt{Statement: s1})
   239  	mustPush(ctx, t, buf, PrepareStmt{Name: "p1"})
   240  	mustPush(ctx, t, buf, PrepareStmt{Name: "p2"})
   241  
   242  	cmd, _, err := buf.CurCmd()
   243  	if err != nil {
   244  		t.Fatal(err)
   245  	}
   246  	assertStmt(t, cmd, "SELECT 1")
   247  
   248  	buf.AdvanceOne()
   249  	cmd, _, err = buf.CurCmd()
   250  	if err != nil {
   251  		t.Fatal(err)
   252  	}
   253  	assertPrepareStmt(t, cmd, "p1")
   254  
   255  	buf.AdvanceOne()
   256  	cmd, _, err = buf.CurCmd()
   257  	if err != nil {
   258  		t.Fatal(err)
   259  	}
   260  	assertPrepareStmt(t, cmd, "p2")
   261  
   262  	// Rewind to the first prepared stmt.
   263  	buf.Rewind(ctx, CmdPos(1))
   264  	cmd, _, err = buf.CurCmd()
   265  	if err != nil {
   266  		t.Fatal(err)
   267  	}
   268  	assertPrepareStmt(t, cmd, "p1")
   269  }
   270  
   271  func TestStmtBufBatching(t *testing.T) {
   272  	defer leaktest.AfterTest(t)()
   273  
   274  	buf := NewStmtBuf()
   275  	ctx := context.Background()
   276  
   277  	s1, err := parser.ParseOne("SELECT 1")
   278  	if err != nil {
   279  		t.Fatal(err)
   280  	}
   281  
   282  	// Start a new batch.
   283  	mustPush(ctx, t, buf, Sync{})
   284  
   285  	mustPush(ctx, t, buf, ExecStmt{Statement: s1})
   286  	mustPush(ctx, t, buf, ExecStmt{Statement: s1})
   287  
   288  	// Start a new batch.
   289  	mustPush(ctx, t, buf, Sync{})
   290  
   291  	mustPush(ctx, t, buf, ExecStmt{Statement: s1})
   292  	mustPush(ctx, t, buf, ExecStmt{Statement: s1})
   293  	mustPush(ctx, t, buf, ExecStmt{Statement: s1})
   294  
   295  	// Start a new batch.
   296  	mustPush(ctx, t, buf, Sync{})
   297  
   298  	mustPush(ctx, t, buf, ExecStmt{Statement: s1})
   299  
   300  	// Go to 2nd batch.
   301  	if err := buf.seekToNextBatch(); err != nil {
   302  		t.Fatal(err)
   303  	}
   304  	_, pos, err := buf.CurCmd()
   305  	if err != nil {
   306  		t.Fatal(err)
   307  	}
   308  	if pos != CmdPos(3) {
   309  		t.Fatalf("expected pos to be %d, got: %d", 3, pos)
   310  	}
   311  
   312  	// Go to 3rd batch.
   313  	if err := buf.seekToNextBatch(); err != nil {
   314  		t.Fatal(err)
   315  	}
   316  	_, pos, err = buf.CurCmd()
   317  	if err != nil {
   318  		t.Fatal(err)
   319  	}
   320  	if pos != CmdPos(7) {
   321  		t.Fatalf("expected pos to be %d, got: %d", 7, pos)
   322  	}
   323  
   324  	// Async start a 4th batch; that will unblock the seek below.
   325  	go func() {
   326  		mustPush(ctx, t, buf, Sync{})
   327  		_ = buf.Push(ctx, ExecStmt{Statement: s1})
   328  	}()
   329  
   330  	// Go to 4th batch.
   331  	if err := buf.seekToNextBatch(); err != nil {
   332  		t.Fatal(err)
   333  	}
   334  	_, pos, err = buf.CurCmd()
   335  	if err != nil {
   336  		t.Fatal(err)
   337  	}
   338  	if pos != CmdPos(9) {
   339  		t.Fatalf("expected pos to be %d, got: %d", 9, pos)
   340  	}
   341  }