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  }