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 }