github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/show_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 "fmt" 17 "math" 18 "net/url" 19 "strings" 20 "testing" 21 "unicode/utf8" 22 23 "github.com/cockroachdb/cockroach/pkg/base" 24 "github.com/cockroachdb/cockroach/pkg/security" 25 "github.com/cockroachdb/cockroach/pkg/sql" 26 "github.com/cockroachdb/cockroach/pkg/sql/lex" 27 "github.com/cockroachdb/cockroach/pkg/sql/parser" 28 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 29 "github.com/cockroachdb/cockroach/pkg/sql/tests" 30 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 31 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 32 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 33 "github.com/cockroachdb/errors" 34 ) 35 36 func TestShowCreateTable(t *testing.T) { 37 defer leaktest.AfterTest(t)() 38 39 params, _ := tests.CreateTestServerParams() 40 s, sqlDB, _ := serverutils.StartServer(t, params) 41 defer s.Stopper().Stop(context.Background()) 42 43 if _, err := sqlDB.Exec(` 44 CREATE DATABASE d; 45 SET DATABASE = d; 46 CREATE TABLE items ( 47 a int8, 48 b int8, 49 c int8 unique, 50 primary key (a, b) 51 ); 52 CREATE DATABASE o; 53 CREATE TABLE o.foo(x int primary key); 54 `); err != nil { 55 t.Fatal(err) 56 } 57 58 tests := []struct { 59 stmt string 60 expect string // empty means identical to stmt 61 }{ 62 { 63 stmt: `CREATE TABLE %s ( 64 i INT8, 65 s STRING NULL, 66 v FLOAT NOT NULL, 67 t TIMESTAMP DEFAULT now():::TIMESTAMP, 68 CHECK (i > 0), 69 FAMILY "primary" (i, v, t, rowid), 70 FAMILY fam_1_s (s) 71 )`, 72 expect: `CREATE TABLE %s ( 73 i INT8 NULL, 74 s STRING NULL, 75 v FLOAT8 NOT NULL, 76 t TIMESTAMP NULL DEFAULT now():::TIMESTAMP, 77 FAMILY "primary" (i, v, t, rowid), 78 FAMILY fam_1_s (s), 79 CONSTRAINT check_i CHECK (i > 0:::INT8) 80 )`, 81 }, 82 { 83 stmt: `CREATE TABLE %s ( 84 i INT8 CHECK (i > 0), 85 s STRING NULL, 86 v FLOAT NOT NULL, 87 t TIMESTAMP DEFAULT now():::TIMESTAMP, 88 FAMILY "primary" (i, v, t, rowid), 89 FAMILY fam_1_s (s) 90 )`, 91 expect: `CREATE TABLE %s ( 92 i INT8 NULL, 93 s STRING NULL, 94 v FLOAT8 NOT NULL, 95 t TIMESTAMP NULL DEFAULT now():::TIMESTAMP, 96 FAMILY "primary" (i, v, t, rowid), 97 FAMILY fam_1_s (s), 98 CONSTRAINT check_i CHECK (i > 0:::INT8) 99 )`, 100 }, 101 { 102 stmt: `CREATE TABLE %s ( 103 i INT8 NULL, 104 s STRING NULL, 105 CONSTRAINT ck CHECK (i > 0), 106 FAMILY "primary" (i, rowid), 107 FAMILY fam_1_s (s) 108 )`, 109 expect: `CREATE TABLE %s ( 110 i INT8 NULL, 111 s STRING NULL, 112 FAMILY "primary" (i, rowid), 113 FAMILY fam_1_s (s), 114 CONSTRAINT ck CHECK (i > 0:::INT8) 115 )`, 116 }, 117 { 118 stmt: `CREATE TABLE %s ( 119 i INT8 PRIMARY KEY 120 )`, 121 expect: `CREATE TABLE %s ( 122 i INT8 NOT NULL, 123 CONSTRAINT "primary" PRIMARY KEY (i ASC), 124 FAMILY "primary" (i) 125 )`, 126 }, 127 { 128 stmt: ` 129 CREATE TABLE %s (i INT8, f FLOAT, s STRING, d DATE, 130 FAMILY "primary" (i, f, d, rowid), 131 FAMILY fam_1_s (s)); 132 CREATE INDEX idx_if on %[1]s (f, i) STORING (s, d); 133 CREATE UNIQUE INDEX on %[1]s (d); 134 `, 135 expect: `CREATE TABLE %s ( 136 i INT8 NULL, 137 f FLOAT8 NULL, 138 s STRING NULL, 139 d DATE NULL, 140 INDEX idx_if (f ASC, i ASC) STORING (s, d), 141 UNIQUE INDEX %[1]s_d_key (d ASC), 142 FAMILY "primary" (i, f, d, rowid), 143 FAMILY fam_1_s (s) 144 )`, 145 }, 146 { 147 stmt: `CREATE TABLE %s ( 148 "te""st" INT8 NOT NULL, 149 CONSTRAINT "pri""mary" PRIMARY KEY ("te""st" ASC), 150 FAMILY "primary" ("te""st") 151 )`, 152 }, 153 { 154 stmt: `CREATE TABLE %s ( 155 a int8, 156 b int8, 157 index c(a asc, b desc) 158 )`, 159 expect: `CREATE TABLE %s ( 160 a INT8 NULL, 161 b INT8 NULL, 162 INDEX c (a ASC, b DESC), 163 FAMILY "primary" (a, b, rowid) 164 )`, 165 }, 166 // Check that FK dependencies inside the current database 167 // have their db name omitted. 168 { 169 stmt: `CREATE TABLE %s ( 170 i int8, 171 j int8, 172 FOREIGN KEY (i, j) REFERENCES items (a, b), 173 k int REFERENCES items (c) 174 )`, 175 expect: `CREATE TABLE %s ( 176 i INT8 NULL, 177 j INT8 NULL, 178 k INT8 NULL, 179 CONSTRAINT fk_i_ref_items FOREIGN KEY (i, j) REFERENCES items(a, b), 180 CONSTRAINT fk_k_ref_items FOREIGN KEY (k) REFERENCES items(c), 181 INDEX %[1]s_auto_index_fk_i_ref_items (i ASC, j ASC), 182 INDEX %[1]s_auto_index_fk_k_ref_items (k ASC), 183 FAMILY "primary" (i, j, k, rowid) 184 )`, 185 }, 186 // Check that FK dependencies using MATCH FULL on a non-composite key still 187 // show 188 { 189 stmt: `CREATE TABLE %s ( 190 i int8, 191 j int8, 192 k int REFERENCES items (c) MATCH FULL, 193 FOREIGN KEY (i, j) REFERENCES items (a, b) MATCH FULL 194 )`, 195 expect: `CREATE TABLE %s ( 196 i INT8 NULL, 197 j INT8 NULL, 198 k INT8 NULL, 199 CONSTRAINT fk_i_ref_items FOREIGN KEY (i, j) REFERENCES items(a, b) MATCH FULL, 200 CONSTRAINT fk_k_ref_items FOREIGN KEY (k) REFERENCES items(c) MATCH FULL, 201 INDEX %[1]s_auto_index_fk_i_ref_items (i ASC, j ASC), 202 INDEX %[1]s_auto_index_fk_k_ref_items (k ASC), 203 FAMILY "primary" (i, j, k, rowid) 204 )`, 205 }, 206 // Check that FK dependencies outside of the current database 207 // have their db name prefixed. 208 { 209 stmt: `CREATE TABLE %s ( 210 x INT8, 211 CONSTRAINT fk_ref FOREIGN KEY (x) REFERENCES o.foo (x) 212 )`, 213 expect: `CREATE TABLE %s ( 214 x INT8 NULL, 215 CONSTRAINT fk_ref FOREIGN KEY (x) REFERENCES o.public.foo(x), 216 INDEX %[1]s_auto_index_fk_ref (x ASC), 217 FAMILY "primary" (x, rowid) 218 )`, 219 }, 220 // Check that FK dependencies using SET NULL or SET DEFAULT 221 // are pretty-printed properly. Regression test for #32529. 222 { 223 stmt: `CREATE TABLE %s ( 224 i int8 DEFAULT 123, 225 j int8 DEFAULT 123, 226 FOREIGN KEY (i, j) REFERENCES items (a, b) ON DELETE SET DEFAULT, 227 k int8 REFERENCES items (c) ON DELETE SET NULL 228 )`, 229 expect: `CREATE TABLE %s ( 230 i INT8 NULL DEFAULT 123:::INT8, 231 j INT8 NULL DEFAULT 123:::INT8, 232 k INT8 NULL, 233 CONSTRAINT fk_i_ref_items FOREIGN KEY (i, j) REFERENCES items(a, b) ON DELETE SET DEFAULT, 234 CONSTRAINT fk_k_ref_items FOREIGN KEY (k) REFERENCES items(c) ON DELETE SET NULL, 235 INDEX %[1]s_auto_index_fk_i_ref_items (i ASC, j ASC), 236 INDEX %[1]s_auto_index_fk_k_ref_items (k ASC), 237 FAMILY "primary" (i, j, k, rowid) 238 )`, 239 }, 240 // Check that INTERLEAVE dependencies inside the current database 241 // have their db name omitted. 242 { 243 stmt: `CREATE TABLE %s ( 244 a INT8, 245 b INT8, 246 PRIMARY KEY (a, b) 247 ) INTERLEAVE IN PARENT items (a, b)`, 248 expect: `CREATE TABLE %s ( 249 a INT8 NOT NULL, 250 b INT8 NOT NULL, 251 CONSTRAINT "primary" PRIMARY KEY (a ASC, b ASC), 252 FAMILY "primary" (a, b) 253 ) INTERLEAVE IN PARENT items (a, b)`, 254 }, 255 // Check that INTERLEAVE dependencies outside of the current 256 // database are prefixed by their db name. 257 { 258 stmt: `CREATE TABLE %s ( 259 x INT8 PRIMARY KEY 260 ) INTERLEAVE IN PARENT o.foo (x)`, 261 expect: `CREATE TABLE %s ( 262 x INT8 NOT NULL, 263 CONSTRAINT "primary" PRIMARY KEY (x ASC), 264 FAMILY "primary" (x) 265 ) INTERLEAVE IN PARENT o.public.foo (x)`, 266 }, 267 // Check that FK dependencies using MATCH FULL and MATCH SIMPLE are both 268 // pretty-printed properly. 269 { 270 stmt: `CREATE TABLE %s ( 271 i int DEFAULT 1, 272 j int DEFAULT 2, 273 k int DEFAULT 3, 274 l int DEFAULT 4, 275 FOREIGN KEY (i, j) REFERENCES items (a, b) MATCH SIMPLE ON DELETE SET DEFAULT, 276 FOREIGN KEY (k, l) REFERENCES items (a, b) MATCH FULL ON UPDATE CASCADE 277 )`, 278 expect: `CREATE TABLE %s ( 279 i INT8 NULL DEFAULT 1:::INT8, 280 j INT8 NULL DEFAULT 2:::INT8, 281 k INT8 NULL DEFAULT 3:::INT8, 282 l INT8 NULL DEFAULT 4:::INT8, 283 CONSTRAINT fk_i_ref_items FOREIGN KEY (i, j) REFERENCES items(a, b) ON DELETE SET DEFAULT, 284 CONSTRAINT fk_k_ref_items FOREIGN KEY (k, l) REFERENCES items(a, b) MATCH FULL ON UPDATE CASCADE, 285 INDEX %[1]s_auto_index_fk_i_ref_items (i ASC, j ASC), 286 INDEX %[1]s_auto_index_fk_k_ref_items (k ASC, l ASC), 287 FAMILY "primary" (i, j, k, l, rowid) 288 )`, 289 }, 290 } 291 for i, test := range tests { 292 name := fmt.Sprintf("t%d", i) 293 t.Run(name, func(t *testing.T) { 294 if test.expect == "" { 295 test.expect = test.stmt 296 } 297 stmt := fmt.Sprintf(test.stmt, name) 298 expect := fmt.Sprintf(test.expect, name) 299 if _, err := sqlDB.Exec(stmt); err != nil { 300 t.Fatal(err) 301 } 302 row := sqlDB.QueryRow(fmt.Sprintf("SHOW CREATE TABLE %s", name)) 303 var scanName, create string 304 if err := row.Scan(&scanName, &create); err != nil { 305 t.Fatal(err) 306 } 307 if scanName != name { 308 t.Fatalf("expected table name %s, got %s", name, scanName) 309 } 310 if create != expect { 311 t.Fatalf("statement: %s\ngot: %s\nexpected: %s", stmt, create, expect) 312 } 313 if _, err := sqlDB.Exec(fmt.Sprintf("DROP TABLE %s", name)); err != nil { 314 t.Fatal(err) 315 } 316 // Re-insert to make sure it's round-trippable. 317 name += "_2" 318 expect = fmt.Sprintf(test.expect, name) 319 if _, err := sqlDB.Exec(expect); err != nil { 320 t.Fatalf("reinsert failure: %s: %s", expect, err) 321 } 322 row = sqlDB.QueryRow(fmt.Sprintf("SHOW CREATE TABLE %s", name)) 323 if err := row.Scan(&scanName, &create); err != nil { 324 t.Fatal(err) 325 } 326 if create != expect { 327 t.Fatalf("round trip statement: %s\ngot: %s", expect, create) 328 } 329 if _, err := sqlDB.Exec(fmt.Sprintf("DROP TABLE %s", name)); err != nil { 330 t.Fatal(err) 331 } 332 }) 333 } 334 } 335 336 func TestShowCreateView(t *testing.T) { 337 defer leaktest.AfterTest(t)() 338 339 params, _ := tests.CreateTestServerParams() 340 s, sqlDB, _ := serverutils.StartServer(t, params) 341 defer s.Stopper().Stop(context.Background()) 342 343 if _, err := sqlDB.Exec(` 344 CREATE DATABASE d; 345 SET DATABASE = d; 346 CREATE TABLE t (i INT, s STRING NULL, v FLOAT NOT NULL, t TIMESTAMP DEFAULT now()); 347 `); err != nil { 348 t.Fatal(err) 349 } 350 351 tests := []struct { 352 create string 353 expected string 354 }{ 355 { 356 `CREATE VIEW %s AS SELECT i, s, v, t FROM t`, 357 `CREATE VIEW %s (i, s, v, t) AS SELECT i, s, v, t FROM d.public.t`, 358 }, 359 { 360 `CREATE VIEW %s AS SELECT i, s, t FROM t`, 361 `CREATE VIEW %s (i, s, t) AS SELECT i, s, t FROM d.public.t`, 362 }, 363 { 364 `CREATE VIEW %s AS SELECT t.i, t.s, t.t FROM t`, 365 `CREATE VIEW %s (i, s, t) AS SELECT t.i, t.s, t.t FROM d.public.t`, 366 }, 367 { 368 `CREATE VIEW %s AS SELECT foo.i, foo.s, foo.t FROM t AS foo WHERE foo.i > 3`, 369 `CREATE VIEW %s (i, s, t) AS SELECT foo.i, foo.s, foo.t FROM d.public.t AS foo WHERE foo.i > 3`, 370 }, 371 { 372 `CREATE VIEW %s AS SELECT count(*) FROM t`, 373 `CREATE VIEW %s (count) AS SELECT count(*) FROM d.public.t`, 374 }, 375 { 376 `CREATE VIEW %s AS SELECT s, count(*) FROM t GROUP BY s HAVING count(*) > 3:::INT8`, 377 `CREATE VIEW %s (s, count) AS SELECT s, count(*) FROM d.public.t GROUP BY s HAVING count(*) > 3:::INT8`, 378 }, 379 { 380 `CREATE VIEW %s (a, b, c, d) AS SELECT i, s, v, t FROM t`, 381 `CREATE VIEW %s (a, b, c, d) AS SELECT i, s, v, t FROM d.public.t`, 382 }, 383 { 384 `CREATE VIEW %s (a, b) AS SELECT i, v FROM t`, 385 `CREATE VIEW %s (a, b) AS SELECT i, v FROM d.public.t`, 386 }, 387 } 388 for i, test := range tests { 389 t.Run(fmt.Sprint(i), func(t *testing.T) { 390 name := fmt.Sprintf("t%d", i) 391 stmt := fmt.Sprintf(test.create, name) 392 expect := fmt.Sprintf(test.expected, name) 393 if _, err := sqlDB.Exec(stmt); err != nil { 394 t.Fatal(err) 395 } 396 row := sqlDB.QueryRow(fmt.Sprintf("SHOW CREATE VIEW %s", name)) 397 var scanName, create string 398 if err := row.Scan(&scanName, &create); err != nil { 399 t.Fatal(err) 400 } 401 if scanName != name { 402 t.Fatalf("expected view name %s, got %s", name, scanName) 403 } 404 if create != expect { 405 t.Fatalf("statement: %s\ngot: %s\nexpected: %s", stmt, create, expect) 406 } 407 if _, err := sqlDB.Exec(fmt.Sprintf("DROP VIEW %s", name)); err != nil { 408 t.Fatal(err) 409 } 410 // Re-insert to make sure it's round-trippable. 411 name += "_2" 412 expect = fmt.Sprintf(test.expected, name) 413 if _, err := sqlDB.Exec(expect); err != nil { 414 t.Fatalf("reinsert failure: %s: %s", expect, err) 415 } 416 row = sqlDB.QueryRow(fmt.Sprintf("SHOW CREATE VIEW %s", name)) 417 if err := row.Scan(&scanName, &create); err != nil { 418 t.Fatal(err) 419 } 420 if create != expect { 421 t.Fatalf("round trip statement: %s\ngot: %s", expect, create) 422 } 423 if _, err := sqlDB.Exec(fmt.Sprintf("DROP VIEW %s", name)); err != nil { 424 t.Fatal(err) 425 } 426 }) 427 } 428 } 429 430 func TestShowCreateSequence(t *testing.T) { 431 defer leaktest.AfterTest(t)() 432 433 params, _ := tests.CreateTestServerParams() 434 s, sqlDB, _ := serverutils.StartServer(t, params) 435 defer s.Stopper().Stop(context.Background()) 436 437 if _, err := sqlDB.Exec(` 438 CREATE DATABASE d; 439 SET DATABASE = d; 440 `); err != nil { 441 t.Fatal(err) 442 } 443 444 tests := []struct { 445 create string 446 expected string 447 }{ 448 { 449 `CREATE SEQUENCE %s`, 450 `CREATE SEQUENCE %s MINVALUE 1 MAXVALUE 9223372036854775807 INCREMENT 1 START 1`, 451 }, 452 { 453 `CREATE SEQUENCE %s INCREMENT BY 5`, 454 `CREATE SEQUENCE %s MINVALUE 1 MAXVALUE 9223372036854775807 INCREMENT 5 START 1`, 455 }, 456 { 457 `CREATE SEQUENCE %s START WITH 5`, 458 `CREATE SEQUENCE %s MINVALUE 1 MAXVALUE 9223372036854775807 INCREMENT 1 START 5`, 459 }, 460 { 461 `CREATE SEQUENCE %s INCREMENT 5 MAXVALUE 10000 START 10 MINVALUE 0`, 462 `CREATE SEQUENCE %s MINVALUE 0 MAXVALUE 10000 INCREMENT 5 START 10`, 463 }, 464 } 465 for i, test := range tests { 466 t.Run(fmt.Sprint(i), func(t *testing.T) { 467 name := fmt.Sprintf("t%d", i) 468 stmt := fmt.Sprintf(test.create, name) 469 expect := fmt.Sprintf(test.expected, name) 470 if _, err := sqlDB.Exec(stmt); err != nil { 471 t.Fatal(err) 472 } 473 row := sqlDB.QueryRow(fmt.Sprintf("SHOW CREATE SEQUENCE %s", name)) 474 var scanName, create string 475 if err := row.Scan(&scanName, &create); err != nil { 476 t.Fatal(err) 477 } 478 if scanName != name { 479 t.Fatalf("expected view name %s, got %s", name, scanName) 480 } 481 if create != expect { 482 t.Fatalf("statement: %s\ngot: %s\nexpected: %s", stmt, create, expect) 483 } 484 if _, err := sqlDB.Exec(fmt.Sprintf("DROP SEQUENCE %s", name)); err != nil { 485 t.Fatal(err) 486 } 487 // Re-insert to make sure it's round-trippable. 488 name += "_2" 489 expect = fmt.Sprintf(test.expected, name) 490 if _, err := sqlDB.Exec(expect); err != nil { 491 t.Fatalf("reinsert failure: %s: %s", expect, err) 492 } 493 row = sqlDB.QueryRow(fmt.Sprintf("SHOW CREATE SEQUENCE %s", name)) 494 if err := row.Scan(&scanName, &create); err != nil { 495 t.Fatal(err) 496 } 497 if create != expect { 498 t.Fatalf("round trip statement: %s\ngot: %s", expect, create) 499 } 500 if _, err := sqlDB.Exec(fmt.Sprintf("DROP SEQUENCE %s", name)); err != nil { 501 t.Fatal(err) 502 } 503 }) 504 } 505 } 506 507 func TestShowQueries(t *testing.T) { 508 defer leaktest.AfterTest(t)() 509 510 const multiByte = "💩" 511 const selectBase = "SELECT * FROM " 512 513 maxLen := sql.MaxSQLBytes - utf8.RuneLen('…') 514 515 // Craft a statement that would naively be truncated mid-rune. 516 tableName := strings.Repeat("a", maxLen-len(selectBase)-(len(multiByte)-1)) + multiByte 517 // Push the total length over the truncation threshold. 518 tableName += strings.Repeat("a", sql.MaxSQLBytes-len(tableName)+1) 519 selectStmt := selectBase + tableName 520 521 if r, _ := utf8.DecodeLastRuneInString(selectStmt[:maxLen]); r != utf8.RuneError { 522 t.Fatalf("expected naive truncation to produce invalid utf8, got %c", r) 523 } 524 expectedSelectStmt := selectStmt 525 for i := range expectedSelectStmt { 526 if i > maxLen { 527 _, prevLen := utf8.DecodeLastRuneInString(expectedSelectStmt[:i]) 528 expectedSelectStmt = expectedSelectStmt[:i-prevLen] 529 break 530 } 531 } 532 expectedSelectStmt = expectedSelectStmt + "…" 533 534 var conn1 *gosql.DB 535 var conn2 *gosql.DB 536 537 execKnobs := &sql.ExecutorTestingKnobs{} 538 539 found := false 540 var failure error 541 542 execKnobs.StatementFilter = func(ctx context.Context, stmt string, err error) { 543 if stmt == selectStmt { 544 found = true 545 const showQuery = "SELECT node_id, (now() - start)::FLOAT8, query FROM [SHOW CLUSTER QUERIES]" 546 547 rows, err := conn1.Query(showQuery) 548 if err != nil { 549 t.Fatal(err) 550 } 551 defer rows.Close() 552 553 var stmts []string 554 for rows.Next() { 555 var nodeID int 556 var stmt string 557 var delta float64 558 if err := rows.Scan(&nodeID, &delta, &stmt); err != nil { 559 failure = err 560 return 561 } 562 stmts = append(stmts, stmt) 563 if nodeID < 1 || nodeID > 2 { 564 failure = fmt.Errorf("invalid node ID: %d", nodeID) 565 return 566 } 567 568 // The delta measures how long ago or in the future (in 569 // seconds) the start time is. It must be 570 // "close to now", otherwise we have a problem with the time 571 // accounting. 572 if math.Abs(delta) > 10 { 573 failure = fmt.Errorf("start time too far in the past or the future: expected <10s, got %.3fs", delta) 574 return 575 } 576 } 577 if err := rows.Err(); err != nil { 578 failure = err 579 return 580 } 581 582 foundSelect := false 583 for _, stmt := range stmts { 584 if stmt == expectedSelectStmt { 585 foundSelect = true 586 } 587 } 588 if !foundSelect { 589 failure = fmt.Errorf("original query not found in SHOW QUERIES. expected: %s\nactual: %v", selectStmt, stmts) 590 } 591 } 592 } 593 594 tc := serverutils.StartTestCluster(t, 2, /* numNodes */ 595 base.TestClusterArgs{ 596 ReplicationMode: base.ReplicationManual, 597 ServerArgs: base.TestServerArgs{ 598 UseDatabase: "test", 599 Knobs: base.TestingKnobs{ 600 SQLExecutor: execKnobs, 601 }, 602 }, 603 }) 604 defer tc.Stopper().Stop(context.Background()) 605 606 conn1 = tc.ServerConn(0) 607 conn2 = tc.ServerConn(1) 608 sqlutils.CreateTable(t, conn1, tableName, "num INT", 0, nil) 609 610 if _, err := conn2.Exec(selectStmt); err != nil { 611 t.Fatal(err) 612 } 613 614 if failure != nil { 615 t.Fatal(failure) 616 } 617 618 if !found { 619 t.Fatalf("knob did not activate in test") 620 } 621 622 // Now check the behavior on error. 623 tc.StopServer(1) 624 625 rows, err := conn1.Query(`SELECT node_id, query FROM [SHOW ALL CLUSTER QUERIES]`) 626 if err != nil { 627 t.Fatal(err) 628 } 629 defer rows.Close() 630 631 count := 0 632 errcount := 0 633 for rows.Next() { 634 count++ 635 636 var nodeID int 637 var sql string 638 if err := rows.Scan(&nodeID, &sql); err != nil { 639 t.Fatal(err) 640 } 641 t.Log(sql) 642 if strings.HasPrefix(sql, "-- failed") || strings.HasPrefix(sql, "-- error") { 643 errcount++ 644 } 645 } 646 if err := rows.Err(); err != nil { 647 t.Fatal(err) 648 } 649 650 if errcount != 1 { 651 t.Fatalf("expected 1 error row, got %d", errcount) 652 } 653 } 654 655 func TestShowSessions(t *testing.T) { 656 defer leaktest.AfterTest(t)() 657 658 var conn *gosql.DB 659 660 tc := serverutils.StartTestCluster(t, 2 /* numNodes */, base.TestClusterArgs{}) 661 defer tc.Stopper().Stop(context.Background()) 662 663 conn = tc.ServerConn(0) 664 sqlutils.CreateTable(t, conn, "t", "num INT", 0, nil) 665 666 // We'll skip "internal" sessions, as those are unpredictable. 667 var showSessions = fmt.Sprintf(` 668 select node_id, (now() - session_start)::float from 669 [show cluster sessions] where application_name not like '%s%%' 670 `, sqlbase.InternalAppNamePrefix) 671 672 rows, err := conn.Query(showSessions) 673 if err != nil { 674 t.Fatal(err) 675 } 676 defer rows.Close() 677 678 count := 0 679 for rows.Next() { 680 count++ 681 682 var nodeID int 683 var delta float64 684 if err := rows.Scan(&nodeID, &delta); err != nil { 685 t.Fatal(err) 686 } 687 if nodeID < 1 || nodeID > 2 { 688 t.Fatalf("invalid node ID: %d", nodeID) 689 } 690 691 // The delta measures how long ago or in the future (in seconds) the start 692 // time is. It must be "close to now", otherwise we have a problem with the 693 // time accounting. 694 if math.Abs(delta) > 10 { 695 t.Fatalf("start time too far in the past or the future: expected <10s, got %.3fs", delta) 696 } 697 } 698 if err := rows.Err(); err != nil { 699 t.Fatal(err) 700 } 701 702 if expectedCount := 1; count != expectedCount { 703 // Print the sessions to aid debugging. 704 report, err := func() (string, error) { 705 result := "Active sessions (results might have changed since the test checked):\n" 706 rows, err = conn.Query(` 707 select active_queries, last_active_query, application_name 708 from [show cluster sessions]`) 709 if err != nil { 710 return "", err 711 } 712 var q, lq, name string 713 for rows.Next() { 714 if err := rows.Scan(&q, &lq, &name); err != nil { 715 return "", err 716 } 717 result += fmt.Sprintf("app: %q, query: %q, last query: %s", 718 name, q, lq) 719 } 720 if err := rows.Close(); err != nil { 721 return "", err 722 } 723 return result, nil 724 }() 725 if err != nil { 726 report = fmt.Sprintf("failed to generate report: %s", err) 727 } 728 729 t.Fatalf("unexpected number of running sessions: %d, expected %d.\n%s", 730 count, expectedCount, report) 731 } 732 733 // Now check the behavior on error. 734 tc.StopServer(1) 735 736 rows, err = conn.Query(`SELECT node_id, active_queries FROM [SHOW ALL CLUSTER SESSIONS]`) 737 if err != nil { 738 t.Fatal(err) 739 } 740 defer rows.Close() 741 742 count = 0 743 errcount := 0 744 for rows.Next() { 745 count++ 746 747 var nodeID int 748 var sql string 749 if err := rows.Scan(&nodeID, &sql); err != nil { 750 t.Fatal(err) 751 } 752 t.Log(sql) 753 if strings.HasPrefix(sql, "-- failed") || strings.HasPrefix(sql, "-- error") { 754 errcount++ 755 } 756 } 757 if err := rows.Err(); err != nil { 758 t.Fatal(err) 759 } 760 761 if errcount != 1 { 762 t.Fatalf("expected 1 error row, got %d", errcount) 763 } 764 } 765 766 func TestShowSessionPrivileges(t *testing.T) { 767 defer leaktest.AfterTest(t)() 768 769 params, _ := tests.CreateTestServerParams() 770 params.Insecure = true 771 s, rawSQLDBroot, _ := serverutils.StartServer(t, params) 772 sqlDBroot := sqlutils.MakeSQLRunner(rawSQLDBroot) 773 defer s.Stopper().Stop(context.Background()) 774 775 // Prepare a non-root session. 776 _ = sqlDBroot.Exec(t, `CREATE USER nonroot`) 777 pgURL := url.URL{ 778 Scheme: "postgres", 779 User: url.User("nonroot"), 780 Host: s.ServingSQLAddr(), 781 RawQuery: "sslmode=disable", 782 } 783 rawSQLDBnonroot, err := gosql.Open("postgres", pgURL.String()) 784 if err != nil { 785 t.Fatal(err) 786 } 787 defer rawSQLDBnonroot.Close() 788 sqlDBnonroot := sqlutils.MakeSQLRunner(rawSQLDBnonroot) 789 790 // Ensure the non-root session is open. 791 sqlDBnonroot.Exec(t, `SELECT version()`) 792 793 t.Run("root", func(t *testing.T) { 794 // Verify that the root session can use SHOW SESSIONS properly and 795 // can observe other sessions than its own. 796 rows := sqlDBroot.Query(t, `SELECT user_name FROM [SHOW CLUSTER SESSIONS]`) 797 defer rows.Close() 798 counts := map[string]int{} 799 for rows.Next() { 800 var userName string 801 if err := rows.Scan(&userName); err != nil { 802 t.Fatal(err) 803 } 804 counts[userName]++ 805 } 806 if err := rows.Err(); err != nil { 807 t.Fatal(err) 808 } 809 if counts[security.RootUser] == 0 { 810 t.Fatalf("root session is unable to see its own session: %+v", counts) 811 } 812 if counts["nonroot"] == 0 { 813 t.Fatal("root session is unable to see non-root session") 814 } 815 }) 816 817 t.Run("non-root", func(t *testing.T) { 818 // Verify that the non-root session can use SHOW SESSIONS properly 819 // and cannot observe other sessions than its own. 820 rows := sqlDBnonroot.Query(t, `SELECT user_name FROM [SHOW CLUSTER SESSIONS]`) 821 defer rows.Close() 822 counts := map[string]int{} 823 for rows.Next() { 824 var userName string 825 if err := rows.Scan(&userName); err != nil { 826 t.Fatal(err) 827 } 828 counts[userName]++ 829 } 830 if err := rows.Err(); err != nil { 831 t.Fatal(err) 832 } 833 if counts["nonroot"] == 0 { 834 t.Fatal("non-root session is unable to see its own session") 835 } 836 if len(counts) > 1 { 837 t.Fatalf("non-root session is able to see other sessions: %+v", counts) 838 } 839 }) 840 } 841 842 func TestLintClusterSettingNames(t *testing.T) { 843 defer leaktest.AfterTest(t)() 844 845 params, _ := tests.CreateTestServerParams() 846 s, sqlDB, _ := serverutils.StartServer(t, params) 847 defer s.Stopper().Stop(context.Background()) 848 849 rows, err := sqlDB.Query(`SELECT variable, setting_type, description FROM [SHOW ALL CLUSTER SETTINGS]`) 850 if err != nil { 851 t.Fatal(err) 852 } 853 defer rows.Close() 854 855 for rows.Next() { 856 var varName, sType, desc string 857 if err := rows.Scan(&varName, &sType, &desc); err != nil { 858 t.Fatal(err) 859 } 860 861 if strings.ToLower(varName) != varName { 862 t.Errorf("%s: variable name must be all lowercase", varName) 863 } 864 865 suffixSuggestions := map[string]string{ 866 "_ttl": ".ttl", 867 "_enabled": ".enabled", 868 "_timeout": ".timeout", 869 } 870 871 nameErr := func() error { 872 segments := strings.Split(varName, ".") 873 for _, segment := range segments { 874 if strings.TrimSpace(segment) != segment { 875 return errors.Errorf("%s: part %q has heading or trailing whitespace", varName, segment) 876 } 877 tokens, ok := parser.Tokens(segment) 878 if !ok { 879 return errors.Errorf("%s: part %q does not scan properly", varName, segment) 880 } 881 if len(tokens) == 0 || len(tokens) > 1 { 882 return errors.Errorf("%s: part %q has invalid structure", varName, segment) 883 } 884 if tokens[0].TokenID != parser.IDENT { 885 cat, ok := lex.KeywordsCategories[tokens[0].Str] 886 if !ok { 887 return errors.Errorf("%s: part %q has invalid structure", varName, segment) 888 } 889 if cat == "R" { 890 return errors.Errorf("%s: part %q is a reserved keyword", varName, segment) 891 } 892 } 893 } 894 895 for suffix, repl := range suffixSuggestions { 896 if strings.HasSuffix(varName, suffix) { 897 return errors.Errorf("%s: use %q instead of %q", varName, repl, suffix) 898 } 899 } 900 901 if sType == "b" && !strings.HasSuffix(varName, ".enabled") { 902 return errors.Errorf("%s: use .enabled for booleans", varName) 903 } 904 905 return nil 906 }() 907 if nameErr != nil { 908 var grandFathered = map[string]string{ 909 "server.declined_reservation_timeout": `server.declined_reservation_timeout: use ".timeout" instead of "_timeout"`, 910 "server.failed_reservation_timeout": `server.failed_reservation_timeout: use ".timeout" instead of "_timeout"`, 911 "server.web_session_timeout": `server.web_session_timeout: use ".timeout" instead of "_timeout"`, 912 "sql.distsql.flow_stream_timeout": `sql.distsql.flow_stream_timeout: use ".timeout" instead of "_timeout"`, 913 "debug.panic_on_failed_assertions": `debug.panic_on_failed_assertions: use .enabled for booleans`, 914 "diagnostics.reporting.send_crash_reports": `diagnostics.reporting.send_crash_reports: use .enabled for booleans`, 915 "kv.closed_timestamp.follower_reads_enabled": `kv.closed_timestamp.follower_reads_enabled: use ".enabled" instead of "_enabled"`, 916 "kv.raft_log.disable_synchronization_unsafe": `kv.raft_log.disable_synchronization_unsafe: use .enabled for booleans`, 917 "kv.range_merge.queue_enabled": `kv.range_merge.queue_enabled: use ".enabled" instead of "_enabled"`, 918 "kv.range_split.by_load_enabled": `kv.range_split.by_load_enabled: use ".enabled" instead of "_enabled"`, 919 "kv.transaction.parallel_commits_enabled": `kv.transaction.parallel_commits_enabled: use ".enabled" instead of "_enabled"`, 920 "kv.transaction.write_pipelining_enabled": `kv.transaction.write_pipelining_enabled: use ".enabled" instead of "_enabled"`, 921 "server.clock.forward_jump_check_enabled": `server.clock.forward_jump_check_enabled: use ".enabled" instead of "_enabled"`, 922 "sql.defaults.experimental_optimizer_mutations": `sql.defaults.experimental_optimizer_mutations: use .enabled for booleans`, 923 "sql.distsql.distribute_index_joins": `sql.distsql.distribute_index_joins: use .enabled for booleans`, 924 "sql.metrics.statement_details.dump_to_logs": `sql.metrics.statement_details.dump_to_logs: use .enabled for booleans`, 925 "sql.metrics.statement_details.sample_logical_plans": `sql.metrics.statement_details.sample_logical_plans: use .enabled for booleans`, 926 "sql.trace.log_statement_execute": `sql.trace.log_statement_execute: use .enabled for booleans`, 927 "trace.debug.enable": `trace.debug.enable: use .enabled for booleans`, 928 "cloudstorage.gs.default.key": `cloudstorage.gs.default.key: part "default" is a reserved keyword`, 929 // These two settings have been deprecated in favor of a new (better named) setting 930 // but the old name is still around to support migrations. 931 // TODO(knz): remove these cases when these settings are retired. 932 "timeseries.storage.10s_resolution_ttl": `timeseries.storage.10s_resolution_ttl: part "10s_resolution_ttl" has invalid structure`, 933 "timeseries.storage.30m_resolution_ttl": `timeseries.storage.30m_resolution_ttl: part "30m_resolution_ttl" has invalid structure`, 934 } 935 expectedErr, found := grandFathered[varName] 936 if !found || expectedErr != nameErr.Error() { 937 t.Error(nameErr) 938 } 939 } 940 941 if strings.TrimSpace(desc) != desc { 942 t.Errorf("%s: description %q has heading or trailing whitespace", varName, desc) 943 } 944 945 if len(desc) == 0 { 946 t.Errorf("%s: description is empty", varName) 947 } 948 949 if len(desc) > 0 { 950 if strings.ToLower(desc[0:1]) != desc[0:1] { 951 t.Errorf("%s: description %q must not start with capital", varName, desc) 952 } 953 if strings.Contains(desc, ". ") != (desc[len(desc)-1] == '.') { 954 t.Errorf("%s: description %q must end with period if and only if it contains a secondary sentence", varName, desc) 955 } 956 } 957 } 958 959 } 960 961 // TestCancelQueriesRace can be stressed to try and reproduce a race 962 // between SHOW QUERIES and currently executing statements. For 963 // more details, see #28033. 964 func TestCancelQueriesRace(t *testing.T) { 965 defer leaktest.AfterTest(t)() 966 ctx, cancel := context.WithCancel(context.Background()) 967 s, sqlDB, _ := serverutils.StartServer(t, base.TestServerArgs{}) 968 defer s.Stopper().Stop(context.Background()) 969 970 waiter := make(chan struct{}) 971 go func() { 972 _, _ = sqlDB.ExecContext(ctx, `SELECT pg_sleep(10)`) 973 close(waiter) 974 }() 975 _, _ = sqlDB.ExecContext(ctx, `CANCEL QUERIES ( 976 SELECT query_id FROM [SHOW QUERIES] WHERE query LIKE 'SELECT pg_sleep%' 977 )`) 978 _, _ = sqlDB.ExecContext(ctx, `CANCEL QUERIES ( 979 SELECT query_id FROM [SHOW QUERIES] WHERE query LIKE 'SELECT pg_sleep%' 980 )`) 981 982 cancel() 983 <-waiter 984 }