github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/conn_executor_test.go (about)

     1  // Copyright 2016 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_test
    12  
    13  import (
    14  	"context"
    15  	gosql "database/sql"
    16  	"database/sql/driver"
    17  	"fmt"
    18  	"net/url"
    19  	"regexp"
    20  	"strings"
    21  	"sync/atomic"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/cockroachdb/cockroach/pkg/base"
    26  	"github.com/cockroachdb/cockroach/pkg/keys"
    27  	"github.com/cockroachdb/cockroach/pkg/kv"
    28  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver"
    29  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver/kvserverbase"
    30  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    31  	"github.com/cockroachdb/cockroach/pkg/security"
    32  	"github.com/cockroachdb/cockroach/pkg/sql"
    33  	"github.com/cockroachdb/cockroach/pkg/sql/parser"
    34  	"github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode"
    35  	"github.com/cockroachdb/cockroach/pkg/sql/row"
    36  	"github.com/cockroachdb/cockroach/pkg/sql/rowexec"
    37  	"github.com/cockroachdb/cockroach/pkg/sql/tests"
    38  	"github.com/cockroachdb/cockroach/pkg/testutils"
    39  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    40  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    41  	"github.com/cockroachdb/cockroach/pkg/util/ctxgroup"
    42  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    43  	"github.com/cockroachdb/cockroach/pkg/util/timeutil"
    44  	"github.com/cockroachdb/errors"
    45  	"github.com/jackc/pgx"
    46  	"github.com/lib/pq"
    47  	"github.com/pmezard/go-difflib/difflib"
    48  	"github.com/stretchr/testify/require"
    49  )
    50  
    51  func TestAnonymizeStatementsForReporting(t *testing.T) {
    52  	defer leaktest.AfterTest(t)()
    53  
    54  	const stmt1s = `
    55  INSERT INTO sensitive(super, sensible) VALUES('that', 'nobody', 'must', 'see')
    56  `
    57  	stmt1, err := parser.ParseOne(stmt1s)
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  
    62  	rUnsafe := errors.New("panic: i'm not safe")
    63  	safeErr := sql.WithAnonymizedStatement(rUnsafe, stmt1.AST)
    64  
    65  	const expMessage = "panic: i'm not safe"
    66  	actMessage := safeErr.Error()
    67  	if actMessage != expMessage {
    68  		t.Errorf("wanted: %s\ngot: %s", expMessage, actMessage)
    69  	}
    70  
    71  	const expSafeRedactedMessage = `...conn_executor_test.go:NN: <*errors.errorString>
    72  wrapper: <*withstack.withStack>
    73  (more details:)
    74  github.com/cockroachdb/cockroach/pkg/sql_test.TestAnonymizeStatementsForReporting
    75  	...conn_executor_test.go:NN
    76  testing.tRunner
    77  	...testing.go:NN
    78  runtime.goexit
    79  	...asm_amd64.s:NN
    80  wrapper: <*safedetails.withSafeDetails>
    81  (more details:)
    82  while executing: %s
    83  -- arg 1: INSERT INTO _(_, _) VALUES (_, _, __more2__)`
    84  
    85  	// Edit non-determinstic stack trace filenames from the message.
    86  	actSafeRedactedMessage := fileref.ReplaceAllString(
    87  		errors.Redact(safeErr), "...$2:NN")
    88  
    89  	if actSafeRedactedMessage != expSafeRedactedMessage {
    90  		diff, _ := difflib.GetUnifiedDiffString(difflib.UnifiedDiff{
    91  			A:        difflib.SplitLines(expSafeRedactedMessage),
    92  			B:        difflib.SplitLines(actSafeRedactedMessage),
    93  			FromFile: "Expected",
    94  			FromDate: "",
    95  			ToFile:   "Actual",
    96  			ToDate:   "",
    97  			Context:  1,
    98  		})
    99  		t.Errorf("Diff:\n%s", diff)
   100  	}
   101  }
   102  
   103  var fileref = regexp.MustCompile(`((?:[a-zA-Z0-9\._@-]*/)*)([a-zA-Z0-9._@-]*\.(?:go|s)):\d+`)
   104  
   105  // Test that a connection closed abruptly while a SQL txn is in progress results
   106  // in that txn being rolled back.
   107  //
   108  // TODO(andrei): This test terminates a client connection by calling Close() on
   109  // a driver.Conn(), which sends a MsgTerminate. We should also have a test that
   110  // closes the connection more abruptly than that.
   111  func TestSessionFinishRollsBackTxn(t *testing.T) {
   112  	defer leaktest.AfterTest(t)()
   113  	aborter := NewTxnAborter()
   114  	defer aborter.Close(t)
   115  	params, _ := tests.CreateTestServerParams()
   116  	params.Knobs.SQLExecutor = aborter.executorKnobs()
   117  	s, mainDB, _ := serverutils.StartServer(t, params)
   118  	defer s.Stopper().Stop(context.Background())
   119  	{
   120  		pgURL, cleanup := sqlutils.PGUrl(
   121  			t, s.ServingSQLAddr(), "TestSessionFinishRollsBackTxn", url.User(security.RootUser))
   122  		defer cleanup()
   123  		if err := aborter.Init(pgURL); err != nil {
   124  			t.Fatal(err)
   125  		}
   126  	}
   127  
   128  	if _, err := mainDB.Exec(`
   129  CREATE DATABASE t;
   130  CREATE TABLE t.test (k INT PRIMARY KEY, v TEXT);
   131  `); err != nil {
   132  		t.Fatal(err)
   133  	}
   134  
   135  	// We're going to test the rollback of transactions left in various states
   136  	// when the connection closes abruptly.
   137  	// For the state CommitWait, there's no actual rollback we can test for (since
   138  	// the kv-level transaction has already been committed). But we still
   139  	// exercise this state to check that the server doesn't crash (which used to
   140  	// happen - #9879).
   141  	tests := []string{"Open", "Aborted", "CommitWait"}
   142  	for _, state := range tests {
   143  		t.Run(state, func(t *testing.T) {
   144  			// Create a low-level lib/pq connection so we can close it at will.
   145  			pgURL, cleanupDB := sqlutils.PGUrl(
   146  				t, s.ServingSQLAddr(), state, url.User(security.RootUser))
   147  			defer cleanupDB()
   148  			c, err := pq.Open(pgURL.String())
   149  			if err != nil {
   150  				t.Fatal(err)
   151  			}
   152  			connClosed := false
   153  			defer func() {
   154  				if connClosed {
   155  					return
   156  				}
   157  				if err := c.Close(); err != nil {
   158  					t.Fatal(err)
   159  				}
   160  			}()
   161  
   162  			ctx := context.Background()
   163  			conn := c.(driver.ConnBeginTx)
   164  			txn, err := conn.BeginTx(ctx, driver.TxOptions{})
   165  			if err != nil {
   166  				t.Fatal(err)
   167  			}
   168  			tx := txn.(driver.ExecerContext)
   169  			if _, err := tx.ExecContext(ctx, "SET TRANSACTION PRIORITY NORMAL", nil); err != nil {
   170  				t.Fatal(err)
   171  			}
   172  
   173  			if state == "CommitWait" {
   174  				if _, err := tx.ExecContext(ctx, "SAVEPOINT cockroach_restart", nil); err != nil {
   175  					t.Fatal(err)
   176  				}
   177  			}
   178  
   179  			insertStmt := "INSERT INTO t.public.test(k, v) VALUES (1, 'a')"
   180  			if state == "RestartWait" {
   181  				// To get a txn in RestartWait, we'll use an aborter.
   182  				if err := aborter.QueueStmtForAbortion(
   183  					insertStmt, 1 /* restartCount */, false /* willBeRetriedIbid */); err != nil {
   184  					t.Fatal(err)
   185  				}
   186  			}
   187  			if _, err := tx.ExecContext(ctx, insertStmt, nil); err != nil {
   188  				t.Fatal(err)
   189  			}
   190  
   191  			if err := aborter.VerifyAndClear(); err != nil {
   192  				t.Fatal(err)
   193  			}
   194  
   195  			if state == "CommitWait" {
   196  				_, err := tx.ExecContext(ctx, "RELEASE SAVEPOINT cockroach_restart", nil)
   197  				if state == "CommitWait" {
   198  					if err != nil {
   199  						t.Fatal(err)
   200  					}
   201  				} else if !testutils.IsError(err, "pq: restart transaction:.*") {
   202  					t.Fatal(err)
   203  				}
   204  			}
   205  
   206  			// Abruptly close the connection.
   207  			connClosed = true
   208  			if err := c.Close(); err != nil {
   209  				t.Fatal(err)
   210  			}
   211  
   212  			// Check that the txn we had above was rolled back. We do this by reading
   213  			// after the preceding txn and checking that we don't get an error and
   214  			// that we haven't been blocked by intents (we can't exactly test that we
   215  			// haven't been blocked but we assert that the query didn't take too
   216  			// long).
   217  			// We do the read in an explicit txn so that automatic retries don't hide
   218  			// any errors.
   219  			// TODO(andrei): Figure out a better way to test for non-blocking.
   220  			// Use a trace when the client-side tracing story gets good enough.
   221  			// There's a bit of difficulty because the cleanup is async.
   222  			txCheck, err := mainDB.Begin()
   223  			if err != nil {
   224  				t.Fatal(err)
   225  			}
   226  			// Run check at low priority so we don't push the previous transaction and
   227  			// fool ourselves into thinking it had been rolled back.
   228  			if _, err := txCheck.Exec("SET TRANSACTION PRIORITY LOW"); err != nil {
   229  				t.Fatal(err)
   230  			}
   231  			ts := timeutil.Now()
   232  			var count int
   233  			if err := txCheck.QueryRow("SELECT count(1) FROM t.test").Scan(&count); err != nil {
   234  				t.Fatal(err)
   235  			}
   236  			// CommitWait actually committed, so we'll need to clean up.
   237  			if state != "CommitWait" {
   238  				if count != 0 {
   239  					t.Fatalf("expected no rows, got: %d", count)
   240  				}
   241  			} else {
   242  				if _, err := txCheck.Exec("DELETE FROM t.test"); err != nil {
   243  					t.Fatal(err)
   244  				}
   245  			}
   246  			if err := txCheck.Commit(); err != nil {
   247  				t.Fatal(err)
   248  			}
   249  			if d := timeutil.Since(ts); d > time.Second {
   250  				t.Fatalf("Looks like the checking tx was unexpectedly blocked. "+
   251  					"It took %s to commit.", d)
   252  			}
   253  
   254  		})
   255  	}
   256  }
   257  
   258  // Test two things about non-retriable errors happening when the Executor does
   259  // an "autoCommit" (i.e. commits the KV txn after running an implicit
   260  // transaction):
   261  // 1) The error is reported to the client.
   262  // 2) The error doesn't leave the session in the Aborted state. After running
   263  // implicit transactions, the state should always be NoTxn, regardless of any
   264  // errors.
   265  func TestNonRetriableErrorOnAutoCommit(t *testing.T) {
   266  	defer leaktest.AfterTest(t)()
   267  
   268  	query := "SELECT 42"
   269  
   270  	params := base.TestServerArgs{
   271  		Knobs: base.TestingKnobs{
   272  			SQLExecutor: &sql.ExecutorTestingKnobs{
   273  				BeforeAutoCommit: func(ctx context.Context, stmt string) error {
   274  					if strings.Contains(stmt, query) {
   275  						return fmt.Errorf("injected autocommit error")
   276  					}
   277  					return nil
   278  				},
   279  			},
   280  		},
   281  	}
   282  	s, sqlDB, _ := serverutils.StartServer(t, params)
   283  	defer s.Stopper().Stop(context.Background())
   284  
   285  	sqlDB.SetMaxOpenConns(1)
   286  
   287  	if _, err := sqlDB.Exec(query); !testutils.IsError(err, "injected") {
   288  		t.Fatalf("expected injected error, got: %v", err)
   289  	}
   290  
   291  	var state string
   292  	if err := sqlDB.QueryRow("SHOW TRANSACTION STATUS").Scan(&state); err != nil {
   293  		t.Fatal(err)
   294  	}
   295  	if state != "NoTxn" {
   296  		t.Fatalf("expected state %s, got: %s", "NoTxn", state)
   297  	}
   298  }
   299  
   300  // Test that, if a ROLLBACK statement encounters an error, the error is not
   301  // returned to the client and the session state is transitioned to NoTxn.
   302  func TestErrorOnRollback(t *testing.T) {
   303  	defer leaktest.AfterTest(t)()
   304  
   305  	const targetKeyString string = "/Table/53/1/1/0"
   306  	var injectedErr int64
   307  
   308  	// We're going to inject an error into our EndTxn.
   309  	params := base.TestServerArgs{
   310  		Knobs: base.TestingKnobs{
   311  			Store: &kvserver.StoreTestingKnobs{
   312  				TestingProposalFilter: func(fArgs kvserverbase.ProposalFilterArgs) *roachpb.Error {
   313  					if !fArgs.Req.IsSingleRequest() {
   314  						return nil
   315  					}
   316  					req := fArgs.Req.Requests[0]
   317  					etReq, ok := req.GetInner().(*roachpb.EndTxnRequest)
   318  					// We only inject the error once. Turns out that during the
   319  					// life of the test there's two EndTxns being sent - one is
   320  					// the direct result of the test's call to tx.Rollback(),
   321  					// the second is sent by the TxnCoordSender - indirectly
   322  					// triggered by the fact that, on the server side, the
   323  					// transaction's context gets canceled at the SQL layer.
   324  					if ok &&
   325  						etReq.Header().Key.String() == targetKeyString &&
   326  						atomic.LoadInt64(&injectedErr) == 0 {
   327  
   328  						atomic.StoreInt64(&injectedErr, 1)
   329  						return roachpb.NewErrorf("test injected error")
   330  					}
   331  					return nil
   332  				},
   333  			},
   334  		},
   335  	}
   336  	s, sqlDB, _ := serverutils.StartServer(t, params)
   337  	ctx := context.Background()
   338  	defer s.Stopper().Stop(ctx)
   339  
   340  	if _, err := sqlDB.Exec(`
   341  CREATE DATABASE t;
   342  CREATE TABLE t.test (k INT PRIMARY KEY, v TEXT);
   343  `); err != nil {
   344  		t.Fatal(err)
   345  	}
   346  
   347  	tx, err := sqlDB.Begin()
   348  	if err != nil {
   349  		t.Fatal(err)
   350  	}
   351  
   352  	// Perform a write so that the EndTxn we're going to send doesn't get elided.
   353  	if _, err := tx.ExecContext(ctx, "INSERT INTO t.test(k, v) VALUES (1, 'abc')"); err != nil {
   354  		t.Fatal(err)
   355  	}
   356  
   357  	if err := tx.Rollback(); err != nil {
   358  		t.Fatal(err)
   359  	}
   360  
   361  	var state string
   362  	if err := sqlDB.QueryRow("SHOW TRANSACTION STATUS").Scan(&state); err != nil {
   363  		t.Fatal(err)
   364  	}
   365  	if state != "NoTxn" {
   366  		t.Fatalf("expected state %s, got: %s", "NoTxn", state)
   367  	}
   368  
   369  	if atomic.LoadInt64(&injectedErr) == 0 {
   370  		t.Fatal("test didn't inject the error; it must have failed to find " +
   371  			"the EndTxn with the expected key")
   372  	}
   373  }
   374  
   375  func TestHalloweenProblemAvoidance(t *testing.T) {
   376  	defer leaktest.AfterTest(t)()
   377  
   378  	// Populate a sufficiently large number of rows. We want at least as
   379  	// many rows as an insert can batch in its output buffer (to force a
   380  	// buffer flush), plus as many rows as a fetcher can fetch at once
   381  	// (to force a read buffer update), plus some more.
   382  	//
   383  	// Instead of customizing the working set size of the test up to the
   384  	// default settings for the SQL package, we scale down the config
   385  	// of the SQL package to the test. The reason for this is that
   386  	// race-enable builds are very slow and the default batch sizes
   387  	// would cause the test duration to exceed the timeout.
   388  	//
   389  	// We are also careful to override these defaults before starting
   390  	// the server, so as to not risk updating them concurrently with
   391  	// some background SQL activity.
   392  	const smallerKvBatchSize = 10
   393  	defer row.TestingSetKVBatchSize(smallerKvBatchSize)()
   394  	const smallerInsertBatchSize = 5
   395  	defer sql.TestingSetInsertBatchSize(smallerInsertBatchSize)()
   396  	numRows := smallerKvBatchSize + smallerInsertBatchSize + 10
   397  
   398  	params, _ := tests.CreateTestServerParams()
   399  	params.Insecure = true
   400  	s, db, _ := serverutils.StartServer(t, params)
   401  	defer s.Stopper().Stop(context.Background())
   402  
   403  	if _, err := db.Exec(`
   404  CREATE DATABASE t;
   405  CREATE TABLE t.test (x FLOAT);
   406  `); err != nil {
   407  		t.Fatal(err)
   408  	}
   409  
   410  	if _, err := db.Exec(
   411  		`INSERT INTO t.test(x) SELECT generate_series(1, $1)::FLOAT`,
   412  		numRows); err != nil {
   413  		t.Fatal(err)
   414  	}
   415  
   416  	// Now slightly modify the values in duplicate rows.
   417  	// We choose a float +0.1 to ensure that none of the derived
   418  	// values become duplicate of already-present values.
   419  	if _, err := db.Exec(`
   420  INSERT INTO t.test(x)
   421      -- the if ensures that no row is processed two times.
   422  SELECT IF(x::INT::FLOAT = x,
   423            x,
   424            crdb_internal.force_error(
   425               'NOOPE', 'insert saw its own writes: ' || x::STRING || ' (it is halloween today)')::FLOAT)
   426         + 0.1
   427    FROM t.test
   428  `); err != nil {
   429  		t.Fatal(err)
   430  	}
   431  
   432  	// Finally verify that no rows has been operated on more than once.
   433  	row := db.QueryRow(`SELECT count(DISTINCT x) FROM t.test`)
   434  	var cnt int
   435  	if err := row.Scan(&cnt); err != nil {
   436  		t.Fatal(err)
   437  	}
   438  
   439  	if cnt != 2*numRows {
   440  		t.Fatalf("expected %d rows in final table, got %d", 2*numRows, cnt)
   441  	}
   442  }
   443  
   444  func TestAppNameStatisticsInitialization(t *testing.T) {
   445  	defer leaktest.AfterTest(t)()
   446  
   447  	params, _ := tests.CreateTestServerParams()
   448  	params.Insecure = true
   449  	s, _, _ := serverutils.StartServer(t, params)
   450  	defer s.Stopper().Stop(context.Background())
   451  
   452  	// Prepare a session with a custom application name.
   453  	pgURL := url.URL{
   454  		Scheme:   "postgres",
   455  		User:     url.User(security.RootUser),
   456  		Host:     s.ServingSQLAddr(),
   457  		RawQuery: "sslmode=disable&application_name=mytest",
   458  	}
   459  	rawSQL, err := gosql.Open("postgres", pgURL.String())
   460  	if err != nil {
   461  		t.Fatal(err)
   462  	}
   463  	defer rawSQL.Close()
   464  	sqlDB := sqlutils.MakeSQLRunner(rawSQL)
   465  
   466  	// Issue a query to be registered in stats.
   467  	sqlDB.Exec(t, "SELECT version()")
   468  
   469  	// Verify the query shows up in stats.
   470  	rows := sqlDB.Query(t, "SELECT application_name, key FROM crdb_internal.node_statement_statistics")
   471  	defer rows.Close()
   472  
   473  	counts := map[string]int{}
   474  	for rows.Next() {
   475  		var appName, key string
   476  		if err := rows.Scan(&appName, &key); err != nil {
   477  			t.Fatal(err)
   478  		}
   479  		counts[appName+":"+key]++
   480  	}
   481  	if counts["mytest:SELECT version()"] == 0 {
   482  		t.Fatalf("query was not counted properly: %+v", counts)
   483  	}
   484  }
   485  
   486  func TestQueryProgress(t *testing.T) {
   487  	defer leaktest.AfterTest(t)()
   488  
   489  	const rows, kvBatchSize = 1000, 50
   490  
   491  	defer rowexec.TestingSetScannedRowProgressFrequency(rows / 60)()
   492  	defer row.TestingSetKVBatchSize(kvBatchSize)()
   493  
   494  	const expectedScans = (rows / 2) /* WHERE restricts scan to 1/2 */ / kvBatchSize
   495  	const stallAfterScans = expectedScans/2 + 1
   496  
   497  	var queryRunningAtomic, scannedBatchesAtomic int64
   498  	stalled, unblock := make(chan struct{}), make(chan struct{})
   499  
   500  	tableKey := keys.SystemSQLCodec.TablePrefix(keys.MinNonPredefinedUserDescID + 1)
   501  	tableSpan := roachpb.Span{Key: tableKey, EndKey: tableKey.PrefixEnd()}
   502  
   503  	// Install a store filter which, if queryRunningAtomic is 1, will count scan
   504  	// requests issued to the test table and then, on the `stallAfterScans` one,
   505  	// will stall the scan and in turn the query, so the test has a chance to
   506  	// inspect the query progress. The filter signals the test that it has reached
   507  	// the stall-point by closing the `stalled` ch and then waits for the test to
   508  	// run its check(s) by receiving on the `unblock` channel (which the test can
   509  	// then close once it has checked the progress).
   510  	params := base.TestServerArgs{
   511  		Knobs: base.TestingKnobs{
   512  			Store: &kvserver.StoreTestingKnobs{
   513  				TestingRequestFilter: func(_ context.Context, req roachpb.BatchRequest) *roachpb.Error {
   514  					if req.IsSingleRequest() {
   515  						scan, ok := req.Requests[0].GetInner().(*roachpb.ScanRequest)
   516  						if ok && tableSpan.ContainsKey(scan.Key) && atomic.LoadInt64(&queryRunningAtomic) == 1 {
   517  							i := atomic.AddInt64(&scannedBatchesAtomic, 1)
   518  							if i == stallAfterScans {
   519  								close(stalled)
   520  								t.Logf("stalling on scan %d at %s and waiting for test to unblock...", i, scan.Key)
   521  								<-unblock
   522  							}
   523  						}
   524  					}
   525  					return nil
   526  				},
   527  			},
   528  		},
   529  	}
   530  	s, rawDB, _ := serverutils.StartServer(t, params)
   531  	defer s.Stopper().Stop(context.Background())
   532  
   533  	db := sqlutils.MakeSQLRunner(rawDB)
   534  
   535  	db.Exec(t, `SET CLUSTER SETTING sql.stats.automatic_collection.enabled = false`)
   536  	db.Exec(t, `CREATE DATABASE t; CREATE TABLE t.test (x INT PRIMARY KEY);`)
   537  	db.Exec(t, `INSERT INTO t.test SELECT generate_series(1, $1)::INT`, rows)
   538  	db.Exec(t, `CREATE STATISTICS __auto__ FROM t.test`)
   539  	const query = `SELECT count(*) FROM t.test WHERE x > $1 and x % 2 = 0`
   540  
   541  	ctx, cancel := context.WithCancel(context.Background())
   542  	defer cancel()
   543  
   544  	g := ctxgroup.WithContext(ctx)
   545  	g.GoCtx(func(ctx context.Context) error {
   546  		// Ensure that after query execution, we've actually hit and closed the
   547  		// stalled ch as expected.
   548  		defer func() {
   549  			select {
   550  			case <-stalled: //stalled was closed as expected.
   551  			default:
   552  				panic("expected stalled to have been closed during execution")
   553  			}
   554  		}()
   555  		atomic.StoreInt64(&queryRunningAtomic, 1)
   556  		_, err := rawDB.ExecContext(ctx, query, rows/2)
   557  		return err
   558  	})
   559  
   560  	t.Log("waiting for query to make progress...")
   561  	<-stalled
   562  	t.Log("query is now stalled. checking progress...")
   563  
   564  	var progress string
   565  	err := rawDB.QueryRow(`SELECT phase FROM [SHOW QUERIES] WHERE query LIKE 'SELECT count(*) FROM t.test%'`).Scan(&progress)
   566  
   567  	// Unblock the KV requests first, regardless of what we found in the progress.
   568  	close(unblock)
   569  	require.NoError(t, g.Wait())
   570  
   571  	if err != nil {
   572  		t.Fatal(err)
   573  	}
   574  	// Although we know we've scanned ~50% of what we'll scan, exactly when the
   575  	// meta makes its way back to the receiver vs when the progress is checked is
   576  	// non-deterministic so we could see 47% done or 53% done, etc. To avoid being
   577  	// flaky, we just make sure we see one of 4x% or 5x%
   578  	require.Regexp(t, `executing \([45]\d\.`, progress)
   579  }
   580  
   581  // This test ensures that when in an explicit transaction, statement preparation
   582  // uses the user's transaction and thus properly interacts with deadlock
   583  // detection.
   584  func TestPrepareInExplicitTransactionDoesNotDeadlock(t *testing.T) {
   585  	defer leaktest.AfterTest(t)()
   586  
   587  	s, sqlDB, _ := serverutils.StartServer(t, base.TestServerArgs{})
   588  	defer s.Stopper().Stop(context.Background())
   589  
   590  	testDB := sqlutils.MakeSQLRunner(sqlDB)
   591  	testDB.Exec(t, "CREATE TABLE foo (i INT PRIMARY KEY)")
   592  	testDB.Exec(t, "CREATE TABLE bar (i INT PRIMARY KEY)")
   593  
   594  	tx1, err := sqlDB.Begin()
   595  	require.NoError(t, err)
   596  
   597  	tx2, err := sqlDB.Begin()
   598  	require.NoError(t, err)
   599  
   600  	// So now I really want to try to have a deadlock.
   601  
   602  	_, err = tx1.Exec("ALTER TABLE foo ADD COLUMN j INT NOT NULL")
   603  	require.NoError(t, err)
   604  
   605  	_, err = tx2.Exec("ALTER TABLE bar ADD COLUMN j INT NOT NULL")
   606  	require.NoError(t, err)
   607  
   608  	// Now we want tx2 to get blocked on tx1 and stay blocked, then we want to
   609  	// push tx1 above tx2 and have it get blocked in planning.
   610  	errCh := make(chan error)
   611  	go func() {
   612  		_, err := tx2.Exec("ALTER TABLE foo ADD COLUMN k INT NOT NULL")
   613  		errCh <- err
   614  	}()
   615  	select {
   616  	case <-time.After(time.Millisecond):
   617  	case err := <-errCh:
   618  		t.Fatalf("expected the transaction to block, got %v", err)
   619  	default:
   620  	}
   621  
   622  	// Read from foo so that we can push tx1 above tx2.
   623  	testDB.Exec(t, "SELECT count(*) FROM foo")
   624  
   625  	// Write into foo to push tx1
   626  	_, err = tx1.Exec("INSERT INTO foo VALUES (1)")
   627  	require.NoError(t, err)
   628  
   629  	// Plan a query which will resolve bar during planning time, this would block
   630  	// and deadlock if it were run on a new transaction.
   631  	_, err = tx1.Prepare("SELECT NULL FROM [SHOW COLUMNS FROM bar] LIMIT 1")
   632  	require.NoError(t, err)
   633  
   634  	// Try to commit tx1. Either it should get a RETRY_SERIALIZABLE error or
   635  	// tx2 should. Ensure that either one or both of them does.
   636  	if tx1Err := tx1.Commit(); tx1Err == nil {
   637  		// tx1 committed successfully, ensure tx2 failed.
   638  		tx2ExecErr := <-errCh
   639  		require.Regexp(t, "RETRY_SERIALIZABLE", tx2ExecErr)
   640  		_ = tx2.Rollback()
   641  	} else {
   642  		require.Regexp(t, "RETRY_SERIALIZABLE", tx1Err)
   643  		tx2ExecErr := <-errCh
   644  		require.NoError(t, tx2ExecErr)
   645  		if tx2CommitErr := tx2.Commit(); tx2CommitErr != nil {
   646  			require.Regexp(t, "RETRY_SERIALIZABLE", tx2CommitErr)
   647  		}
   648  	}
   649  }
   650  
   651  // TestRetriableErrorDuringPrepare ensures that when preparing and using a new
   652  // transaction, retriable errors are handled properly and do not propagate to
   653  // the user's transaction.
   654  func TestRetriableErrorDuringPrepare(t *testing.T) {
   655  	defer leaktest.AfterTest(t)()
   656  	const uniqueString = "'a very unique string'"
   657  	var failed int64
   658  	const numToFail = 2 // only fail on the first two attempts
   659  	s, sqlDB, _ := serverutils.StartServer(t, base.TestServerArgs{
   660  		Knobs: base.TestingKnobs{
   661  			SQLExecutor: &sql.ExecutorTestingKnobs{
   662  				BeforePrepare: func(ctx context.Context, stmt string, txn *kv.Txn) error {
   663  					if strings.Contains(stmt, uniqueString) && atomic.AddInt64(&failed, 1) <= numToFail {
   664  						return roachpb.NewTransactionRetryWithProtoRefreshError("boom",
   665  							txn.ID(), *txn.TestingCloneTxn())
   666  					}
   667  					return nil
   668  				},
   669  			},
   670  		},
   671  	})
   672  	defer s.Stopper().Stop(context.Background())
   673  
   674  	testDB := sqlutils.MakeSQLRunner(sqlDB)
   675  	testDB.Exec(t, "CREATE TABLE foo (i INT PRIMARY KEY)")
   676  
   677  	stmt, err := sqlDB.Prepare("SELECT " + uniqueString)
   678  	require.NoError(t, err)
   679  	defer func() { _ = stmt.Close() }()
   680  }
   681  
   682  // This test ensures that when in an explicit transaction and statement
   683  // preparation uses the user's transaction, errors during those planning queries
   684  // are handled correctly.
   685  func TestErrorDuringPrepareInExplicitTransactionPropagates(t *testing.T) {
   686  	defer leaktest.AfterTest(t)()
   687  
   688  	filter := newDynamicRequestFilter()
   689  	s, sqlDB, _ := serverutils.StartServer(t, base.TestServerArgs{
   690  		Knobs: base.TestingKnobs{
   691  			Store: &kvserver.StoreTestingKnobs{
   692  				TestingRequestFilter: filter.filter,
   693  			},
   694  		},
   695  	})
   696  	defer s.Stopper().Stop(context.Background())
   697  
   698  	testDB := sqlutils.MakeSQLRunner(sqlDB)
   699  	testDB.Exec(t, "CREATE TABLE foo (i INT PRIMARY KEY)")
   700  	testDB.Exec(t, "CREATE TABLE bar (i INT PRIMARY KEY)")
   701  
   702  	// This test will create an explicit transaction that encounters an error on
   703  	// a latter statement during planning of SHOW COLUMNS. The planning for this
   704  	// SHOW COLUMNS will be run in the user's transaction. The test will inject
   705  	// errors into the execution of that planning query and ensure that the user's
   706  	// transaction state evolves appropriately.
   707  
   708  	// Use pgx so that we can introspect error codes returned from cockroach.
   709  	pgURL, cleanup := sqlutils.PGUrl(t, s.ServingSQLAddr(), "", url.User("root"))
   710  	defer cleanup()
   711  	conf, err := pgx.ParseConnectionString(pgURL.String())
   712  	require.NoError(t, err)
   713  	conn, err := pgx.Connect(conf)
   714  	require.NoError(t, err)
   715  
   716  	tx, err := conn.Begin()
   717  	require.NoError(t, err)
   718  
   719  	_, err = tx.Exec("SAVEPOINT cockroach_restart")
   720  	require.NoError(t, err)
   721  
   722  	// Do something with the user's transaction so that we'll use the user
   723  	// transaction in the planning of the below `SHOW COLUMNS`.
   724  	_, err = tx.Exec("INSERT INTO foo VALUES (1)")
   725  	require.NoError(t, err)
   726  
   727  	// Inject an error that will happen during planning.
   728  	filter.setFilter(func(ctx context.Context, ba roachpb.BatchRequest) *roachpb.Error {
   729  		if ba.Txn == nil {
   730  			return nil
   731  		}
   732  		if req, ok := ba.GetArg(roachpb.Get); ok {
   733  			get := req.(*roachpb.GetRequest)
   734  			_, tableID, err := keys.SystemSQLCodec.DecodeTablePrefix(get.Key)
   735  			if err != nil || tableID != keys.NamespaceTableID {
   736  				err = nil
   737  				return nil
   738  			}
   739  			return roachpb.NewErrorWithTxn(
   740  				roachpb.NewTransactionRetryError(roachpb.RETRY_REASON_UNKNOWN, "boom"), ba.Txn)
   741  		}
   742  		return nil
   743  	})
   744  
   745  	// Plan a query will get a restart error during planning.
   746  	_, err = tx.Prepare("show_columns", "SELECT NULL FROM [SHOW COLUMNS FROM bar] LIMIT 1")
   747  	require.Regexp(t,
   748  		`restart transaction: TransactionRetryWithProtoRefreshError: TransactionRetryError: retry txn \(RETRY_REASON_UNKNOWN - boom\)`,
   749  		err)
   750  	var pgErr pgx.PgError
   751  	require.True(t, errors.As(err, &pgErr))
   752  	require.Equal(t, pgcode.SerializationFailure, pgErr.Code)
   753  
   754  	// Clear the error producing filter, restart the transaction, and run it to
   755  	// completion.
   756  	filter.setFilter(nil)
   757  
   758  	_, err = tx.Exec("ROLLBACK TO SAVEPOINT cockroach_restart")
   759  	require.NoError(t, err)
   760  
   761  	_, err = tx.Exec("INSERT INTO foo VALUES (1)")
   762  	require.NoError(t, err)
   763  	_, err = tx.Prepare("show_columns", "SELECT NULL FROM [SHOW COLUMNS FROM bar] LIMIT 1")
   764  	require.NoError(t, err)
   765  	require.NoError(t, tx.Commit())
   766  }
   767  
   768  // TestTrimFlushedStatements verifies that the conn executor trims the
   769  // statements buffer once the corresponding results are returned to the user.
   770  func TestTrimFlushedStatements(t *testing.T) {
   771  	defer leaktest.AfterTest(t)()
   772  
   773  	const (
   774  		countStmt = "SELECT count(*) FROM test"
   775  		// stmtBufMaxLen is the maximum length the statement buffer should be during
   776  		// execution of COUNT(*). This includes a SELECT COUNT(*) command as well
   777  		// as a Sync command.
   778  		stmtBufMaxLen = 2
   779  	)
   780  	// stmtBufLen is set to the length of the statement buffer after each SELECT
   781  	// COUNT(*) execution.
   782  	stmtBufLen := 0
   783  	ctx := context.Background()
   784  	s, sqlDB, _ := serverutils.StartServer(t, base.TestServerArgs{
   785  		Knobs: base.TestingKnobs{
   786  			SQLExecutor: &sql.ExecutorTestingKnobs{
   787  				AfterExecCmd: func(_ context.Context, cmd sql.Command, buf *sql.StmtBuf) {
   788  					if strings.Contains(cmd.String(), countStmt) {
   789  						// Only compare statement buffer length on SELECT COUNT(*) queries.
   790  						stmtBufLen = buf.Len()
   791  					}
   792  				},
   793  			},
   794  		},
   795  	})
   796  	defer s.Stopper().Stop(ctx)
   797  
   798  	_, err := sqlDB.Exec("CREATE TABLE test (i int)")
   799  	require.NoError(t, err)
   800  
   801  	tx, err := sqlDB.Begin()
   802  	require.NoError(t, err)
   803  
   804  	for i := 0; i < 10; i++ {
   805  		_, err := tx.Exec(countStmt)
   806  		require.NoError(t, err)
   807  		if stmtBufLen > stmtBufMaxLen {
   808  			t.Fatalf("statement buffer grew to %d (> %d) after %dth execution", stmtBufLen, stmtBufMaxLen, i)
   809  		}
   810  	}
   811  	require.NoError(t, tx.Commit())
   812  }
   813  
   814  // dynamicRequestFilter exposes a filter method which is a
   815  // kvserverbase.ReplicaRequestFilter but can be set dynamically.
   816  type dynamicRequestFilter struct {
   817  	v atomic.Value
   818  }
   819  
   820  func newDynamicRequestFilter() *dynamicRequestFilter {
   821  	f := &dynamicRequestFilter{}
   822  	f.v.Store(kvserverbase.ReplicaRequestFilter(noopRequestFilter))
   823  	return f
   824  }
   825  
   826  func (f *dynamicRequestFilter) setFilter(filter kvserverbase.ReplicaRequestFilter) {
   827  	if filter == nil {
   828  		f.v.Store(kvserverbase.ReplicaRequestFilter(noopRequestFilter))
   829  	} else {
   830  		f.v.Store(filter)
   831  	}
   832  }
   833  
   834  // noopRequestFilter is a kvserverbase.ReplicaRequestFilter.
   835  func (f *dynamicRequestFilter) filter(
   836  	ctx context.Context, request roachpb.BatchRequest,
   837  ) *roachpb.Error {
   838  	return f.v.Load().(kvserverbase.ReplicaRequestFilter)(ctx, request)
   839  }
   840  
   841  // noopRequestFilter is a kvserverbase.ReplicaRequestFilter that does nothing.
   842  func noopRequestFilter(ctx context.Context, request roachpb.BatchRequest) *roachpb.Error {
   843  	return nil
   844  }