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

     1  // Copyright 2019 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  	"strings"
    17  	"testing"
    18  
    19  	"github.com/cockroachdb/cockroach/pkg/base"
    20  	"github.com/cockroachdb/cockroach/pkg/kv/kvserver"
    21  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    22  	"github.com/cockroachdb/cockroach/pkg/server"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/tests"
    24  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    25  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    26  	"github.com/cockroachdb/cockroach/pkg/util/hlc"
    27  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    28  )
    29  
    30  func TestUnsplitAt(t *testing.T) {
    31  	defer leaktest.AfterTest(t)()
    32  
    33  	params, _ := tests.CreateTestServerParams()
    34  	// TODO(jeffreyxiao): Disable the merge queue due to a race condition. The
    35  	// merge queue might issue an AdminMerge and before the actual merge happens,
    36  	// the LHS of the merge is manually split and is later merged even though a
    37  	// sticky bit has been set on the new RHS. This race condition happens
    38  	// because there is two independent fetches of the RHS during a merge
    39  	// operation (one in the merge queue and another in the actual merge). The
    40  	// merge queue should pass the expected descriptor of the RHS into the
    41  	// AdminMerge request.
    42  	params.Knobs = base.TestingKnobs{
    43  		Store: &kvserver.StoreTestingKnobs{
    44  			DisableMergeQueue: true,
    45  		},
    46  	}
    47  	s, db, _ := serverutils.StartServer(t, params)
    48  	defer s.Stopper().Stop(context.Background())
    49  
    50  	r := sqlutils.MakeSQLRunner(db)
    51  
    52  	r.Exec(t, "CREATE DATABASE d")
    53  	r.Exec(t, `CREATE TABLE d.t (
    54  		i INT,
    55  		s STRING,
    56  		PRIMARY KEY (i, s),
    57  		INDEX s_idx (s)
    58  	)`)
    59  	r.Exec(t, `CREATE TABLE d.i (k INT PRIMARY KEY)`)
    60  	r.Exec(t, `CREATE TABLE i (k INT PRIMARY KEY)`)
    61  
    62  	tests := []struct {
    63  		splitStmt   string
    64  		unsplitStmt string
    65  		// Number of unsplits expected.
    66  		count int
    67  		error string
    68  		args  []interface{}
    69  	}{
    70  		{
    71  			splitStmt:   "ALTER TABLE d.t SPLIT AT VALUES (2, 'b')",
    72  			unsplitStmt: "ALTER TABLE d.t UNSPLIT AT VALUES (2, 'b')",
    73  			count:       1,
    74  		},
    75  		{
    76  			splitStmt:   "ALTER TABLE d.t SPLIT AT VALUES (3, 'c'), (4, 'd')",
    77  			unsplitStmt: "ALTER TABLE d.t UNSPLIT AT VALUES (3, 'c'), (4, 'd')",
    78  			count:       2,
    79  		},
    80  		{
    81  			splitStmt:   "ALTER TABLE d.t SPLIT AT VALUES (5, 'd')",
    82  			unsplitStmt: "ALTER TABLE d.t UNSPLIT AT SELECT 5, 'd'",
    83  			count:       1,
    84  		},
    85  		{
    86  			splitStmt:   "ALTER TABLE d.t SPLIT AT VALUES (6, 'e'), (7, 'f')",
    87  			unsplitStmt: "ALTER TABLE d.t UNSPLIT AT SELECT * FROM (VALUES (6, 'e'), (7, 'f')) AS a",
    88  			count:       2,
    89  		},
    90  		{
    91  			splitStmt:   "ALTER TABLE d.t SPLIT AT VALUES (10)",
    92  			unsplitStmt: "ALTER TABLE d.t UNSPLIT AT VALUES (10)",
    93  			count:       1,
    94  		},
    95  		{
    96  			splitStmt:   "ALTER TABLE d.i SPLIT AT VALUES (1)",
    97  			unsplitStmt: "ALTER TABLE d.i UNSPLIT AT VALUES ((SELECT 1))",
    98  			count:       1,
    99  		},
   100  		{
   101  			splitStmt:   "ALTER TABLE d.i SPLIT AT VALUES (8)",
   102  			unsplitStmt: "ALTER TABLE d.i UNSPLIT AT VALUES ($1)",
   103  			args:        []interface{}{8},
   104  			count:       1,
   105  		},
   106  		{
   107  			splitStmt:   "ALTER INDEX d.t@s_idx SPLIT AT VALUES ('f')",
   108  			unsplitStmt: "ALTER INDEX d.t@s_idx UNSPLIT AT VALUES ('f')",
   109  			count:       1,
   110  		},
   111  		{
   112  			splitStmt:   "ALTER TABLE d.t SPLIT AT VALUES (8, 'g'), (9, 'h'), (10, 'i')",
   113  			unsplitStmt: "ALTER TABLE d.t UNSPLIT ALL",
   114  			count:       3,
   115  		},
   116  		{
   117  			splitStmt:   "ALTER INDEX d.t@s_idx SPLIT AT VALUES ('g'), ('h'), ('i')",
   118  			unsplitStmt: "ALTER INDEX d.t@s_idx UNSPLIT ALL",
   119  			count:       3,
   120  		},
   121  		{
   122  			splitStmt:   "ALTER TABLE d.i SPLIT AT VALUES (10), (11), (12)",
   123  			unsplitStmt: "ALTER TABLE d.i UNSPLIT ALL",
   124  			count:       3,
   125  		},
   126  		{
   127  			splitStmt:   "ALTER TABLE i SPLIT AT VALUES (10), (11), (12)",
   128  			unsplitStmt: "ALTER TABLE i UNSPLIT ALL",
   129  			count:       3,
   130  		},
   131  		{
   132  			unsplitStmt: "ALTER TABLE d.t UNSPLIT AT VALUES (1, 'non-existent')",
   133  			error:       "could not UNSPLIT AT (1, 'non-existent')",
   134  		},
   135  		{
   136  			unsplitStmt: "ALTER TABLE d.t UNSPLIT AT VALUES ('c', 3)",
   137  			error:       "could not parse \"c\" as type int",
   138  		},
   139  		{
   140  			unsplitStmt: "ALTER TABLE d.t UNSPLIT AT VALUES (i, s)",
   141  			error:       `column "i" does not exist`,
   142  		},
   143  		{
   144  			unsplitStmt: "ALTER INDEX d.t@not_present UNSPLIT AT VALUES ('g')",
   145  			error:       `index "not_present" does not exist`,
   146  		},
   147  		{
   148  			unsplitStmt: "ALTER TABLE d.i UNSPLIT AT VALUES (avg(1::float))",
   149  			error:       "aggregate functions are not allowed in VALUES",
   150  		},
   151  		{
   152  			unsplitStmt: "ALTER TABLE d.i UNSPLIT AT VALUES ($1)",
   153  			error:       "no value provided for placeholder: $1",
   154  		},
   155  		{
   156  			unsplitStmt: "ALTER TABLE d.i UNSPLIT AT VALUES ($1)",
   157  			args:        []interface{}{"blah"},
   158  			error:       "error in argument for $1: strconv.ParseInt",
   159  		},
   160  		{
   161  			unsplitStmt: "ALTER TABLE d.i UNSPLIT AT VALUES ($1::string)",
   162  			args:        []interface{}{"1"},
   163  			error:       "UNSPLIT AT data column 1 (k) must be of type int, not type string",
   164  		},
   165  	}
   166  
   167  	for _, tt := range tests {
   168  		var key roachpb.Key
   169  		var pretty string
   170  		var expirationTimestamp gosql.NullString
   171  
   172  		if tt.splitStmt != "" {
   173  			rows, err := db.Query(tt.splitStmt)
   174  			if err != nil {
   175  				t.Fatalf("%s: unexpected error setting up test: %s", tt.splitStmt, err)
   176  			}
   177  			for rows.Next() {
   178  				if err := rows.Scan(&key, &pretty, &expirationTimestamp); err != nil {
   179  					t.Fatalf("%s: unexpected error setting up test: %s", tt.splitStmt, err)
   180  				}
   181  			}
   182  			if err := rows.Err(); err != nil {
   183  				t.Fatalf("%s: unexpected error setting up test: %s", tt.splitStmt, err)
   184  			}
   185  		}
   186  
   187  		rows, err := db.Query(tt.unsplitStmt, tt.args...)
   188  		if err != nil && tt.error == "" {
   189  			t.Fatalf("%s: unexpected error: %s", tt.unsplitStmt, err)
   190  		} else if tt.error != "" && err == nil {
   191  			t.Fatalf("%s: expected error: %s", tt.unsplitStmt, tt.error)
   192  		} else if err != nil && tt.error != "" {
   193  			if !strings.Contains(err.Error(), tt.error) {
   194  				t.Fatalf("%s: unexpected error: %s", tt.unsplitStmt, err)
   195  			}
   196  		} else {
   197  			actualCount := 0
   198  			for rows.Next() {
   199  				actualCount++
   200  				err := rows.Scan(&key, &pretty)
   201  				if err != nil {
   202  					t.Fatalf("%s: unexpected error: %s", tt.unsplitStmt, err)
   203  				}
   204  				// Successful unsplit, verify it happened.
   205  				rng, err := s.(*server.TestServer).LookupRange(key)
   206  				if err != nil {
   207  					t.Fatal(err)
   208  				}
   209  				if (rng.GetStickyBit() != hlc.Timestamp{}) {
   210  					t.Fatalf("%s: expected range sticky bit to be hlc.MinTimestamp, got %s", tt.unsplitStmt, rng.GetStickyBit())
   211  				}
   212  			}
   213  			if err := rows.Err(); err != nil {
   214  				t.Fatalf("%s: unexpected error: %s", tt.unsplitStmt, err)
   215  			}
   216  
   217  			if tt.count != actualCount {
   218  				t.Fatalf("%s: expected %d unsplits, got %d", tt.unsplitStmt, tt.count, actualCount)
   219  			}
   220  		}
   221  	}
   222  }