github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ccl/partitionccl/zone_test.go (about)

     1  // Copyright 2017 The Cockroach Authors.
     2  //
     3  // Licensed as a CockroachDB Enterprise file under the Cockroach Community
     4  // License (the "License"); you may not use this file except in compliance with
     5  // the License. You may obtain a copy of the License at
     6  //
     7  //     https://github.com/cockroachdb/cockroach/blob/master/licenses/CCL.txt
     8  
     9  package partitionccl
    10  
    11  import (
    12  	"context"
    13  	"fmt"
    14  	"strings"
    15  	"testing"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/base"
    18  	"github.com/cockroachdb/cockroach/pkg/config/zonepb"
    19  	"github.com/cockroachdb/cockroach/pkg/keys"
    20  	"github.com/cockroachdb/cockroach/pkg/server"
    21  	"github.com/cockroachdb/cockroach/pkg/settings/cluster"
    22  	"github.com/cockroachdb/cockroach/pkg/sql"
    23  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    24  	"github.com/cockroachdb/cockroach/pkg/testutils"
    25  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    26  	"github.com/cockroachdb/cockroach/pkg/testutils/sqlutils"
    27  	"github.com/cockroachdb/cockroach/pkg/util/encoding"
    28  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    29  	"github.com/cockroachdb/cockroach/pkg/util/randutil"
    30  	"github.com/cockroachdb/cockroach/pkg/util/uuid"
    31  )
    32  
    33  func TestValidIndexPartitionSetShowZones(t *testing.T) {
    34  	defer leaktest.AfterTest(t)()
    35  
    36  	s, db, _ := serverutils.StartServer(t, base.TestServerArgs{})
    37  	defer s.Stopper().Stop(context.Background())
    38  
    39  	sqlDB := sqlutils.MakeSQLRunner(db)
    40  	sqlDB.Exec(t, `
    41  		CREATE DATABASE d;
    42  		USE d;
    43  		CREATE TABLE t (c STRING PRIMARY KEY) PARTITION BY LIST (c) (
    44  			PARTITION p0 VALUES IN ('a'),
    45  			PARTITION p1 VALUES IN (DEFAULT)
    46  		)`)
    47  
    48  	yamlDefault := fmt.Sprintf("gc: {ttlseconds: %d}", s.(*server.TestServer).Cfg.DefaultZoneConfig.GC.TTLSeconds)
    49  	yamlOverride := "gc: {ttlseconds: 42}"
    50  	zoneOverride := s.(*server.TestServer).Cfg.DefaultZoneConfig
    51  	zoneOverride.GC = &zonepb.GCPolicy{TTLSeconds: 42}
    52  	partialZoneOverride := *zonepb.NewZoneConfig()
    53  	partialZoneOverride.GC = &zonepb.GCPolicy{TTLSeconds: 42}
    54  
    55  	dbID := sqlutils.QueryDatabaseID(t, db, "d")
    56  	tableID := sqlutils.QueryTableID(t, db, "d", "public", "t")
    57  
    58  	defaultRow := sqlutils.ZoneRow{
    59  		ID:     keys.RootNamespaceID,
    60  		Config: s.(*server.TestServer).Cfg.DefaultZoneConfig,
    61  	}
    62  	defaultOverrideRow := sqlutils.ZoneRow{
    63  		ID:     keys.RootNamespaceID,
    64  		Config: zoneOverride,
    65  	}
    66  	dbRow := sqlutils.ZoneRow{
    67  		ID:     dbID,
    68  		Config: zoneOverride,
    69  	}
    70  	tableRow := sqlutils.ZoneRow{
    71  		ID:     tableID,
    72  		Config: zoneOverride,
    73  	}
    74  	primaryRow := sqlutils.ZoneRow{
    75  		ID:     tableID,
    76  		Config: zoneOverride,
    77  	}
    78  	p0Row := sqlutils.ZoneRow{
    79  		ID:     tableID,
    80  		Config: zoneOverride,
    81  	}
    82  	p1Row := sqlutils.ZoneRow{
    83  		ID:     tableID,
    84  		Config: zoneOverride,
    85  	}
    86  
    87  	// Partially filled config rows
    88  	partialDbRow := sqlutils.ZoneRow{
    89  		ID:     dbID,
    90  		Config: partialZoneOverride,
    91  	}
    92  	partialTableRow := sqlutils.ZoneRow{
    93  		ID:     tableID,
    94  		Config: partialZoneOverride,
    95  	}
    96  	partialPrimaryRow := sqlutils.ZoneRow{
    97  		ID:     tableID,
    98  		Config: partialZoneOverride,
    99  	}
   100  	partialP0Row := sqlutils.ZoneRow{
   101  		ID:     tableID,
   102  		Config: partialZoneOverride,
   103  	}
   104  	partialP1Row := sqlutils.ZoneRow{
   105  		ID:     tableID,
   106  		Config: partialZoneOverride,
   107  	}
   108  
   109  	// Remove stock zone configs installed at cluster bootstrap. Otherwise this
   110  	// test breaks whenever these stock zone configs are adjusted.
   111  	sqlutils.RemoveAllZoneConfigs(t, sqlDB)
   112  
   113  	// Ensure the default is reported for all zones at first.
   114  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow)
   115  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "RANGE default", defaultRow)
   116  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", defaultRow)
   117  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", defaultRow)
   118  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", defaultRow)
   119  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", defaultRow)
   120  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", defaultRow)
   121  
   122  	// Ensure a database zone config applies to that database, its tables, and its
   123  	// tables' indices and partitions.
   124  	sqlutils.SetZoneConfig(t, sqlDB, "DATABASE d", yamlOverride)
   125  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialDbRow)
   126  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow)
   127  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", dbRow)
   128  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", dbRow)
   129  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", dbRow)
   130  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", dbRow)
   131  
   132  	// Ensure a table zone config applies to that table and its indices and
   133  	// partitions, but no other zones.
   134  	sqlutils.SetZoneConfig(t, sqlDB, "TABLE d.t", yamlOverride)
   135  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialDbRow, partialTableRow)
   136  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow)
   137  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow)
   138  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", tableRow)
   139  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", tableRow)
   140  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", tableRow)
   141  
   142  	// Ensure an index zone config applies to that index and its partitions, but
   143  	// no other zones.
   144  	sqlutils.SetZoneConfig(t, sqlDB, "INDEX d.t@primary", yamlOverride)
   145  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialDbRow, partialTableRow, partialPrimaryRow)
   146  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow)
   147  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow)
   148  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow)
   149  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", primaryRow)
   150  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow)
   151  
   152  	// Ensure a partition zone config applies to that partition, but no other
   153  	// zones.
   154  	sqlutils.SetZoneConfig(t, sqlDB, "PARTITION p0 OF TABLE d.t", yamlOverride)
   155  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialDbRow, partialTableRow, partialPrimaryRow, partialP0Row)
   156  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow)
   157  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow)
   158  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow)
   159  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row)
   160  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow)
   161  
   162  	// Ensure updating the default zone propagates to zones without an override,
   163  	// but not to those with overrides.
   164  	sqlutils.SetZoneConfig(t, sqlDB, "RANGE default", yamlOverride)
   165  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow, partialDbRow, partialTableRow, partialPrimaryRow, partialP0Row)
   166  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", dbRow)
   167  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow)
   168  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow)
   169  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row)
   170  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow)
   171  
   172  	// Ensure deleting a database zone leaves child overrides in place.
   173  	sqlutils.DeleteZoneConfig(t, sqlDB, "DATABASE d")
   174  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow, partialTableRow, partialPrimaryRow, partialP0Row)
   175  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", defaultOverrideRow)
   176  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", tableRow)
   177  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow)
   178  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row)
   179  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow)
   180  
   181  	// Ensure deleting a table zone leaves child overrides in place.
   182  	sqlutils.DeleteZoneConfig(t, sqlDB, "TABLE d.t")
   183  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow, partialPrimaryRow, partialP0Row)
   184  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", defaultOverrideRow)
   185  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", primaryRow)
   186  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row)
   187  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", primaryRow)
   188  
   189  	// Ensure deleting an index zone leaves child overrides in place.
   190  	sqlutils.DeleteZoneConfig(t, sqlDB, "INDEX d.t@primary")
   191  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow, partialP0Row)
   192  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", defaultOverrideRow)
   193  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row)
   194  
   195  	// Ensure deleting a partition zone works.
   196  	sqlutils.DeleteZoneConfig(t, sqlDB, "PARTITION p0 OF TABLE d.t")
   197  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultOverrideRow)
   198  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", defaultOverrideRow)
   199  
   200  	// Ensure deleting non-overridden zones is not an error.
   201  	sqlutils.DeleteZoneConfig(t, sqlDB, "DATABASE d")
   202  	sqlutils.DeleteZoneConfig(t, sqlDB, "TABLE d.t")
   203  	sqlutils.DeleteZoneConfig(t, sqlDB, "PARTITION p1 OF TABLE d.t")
   204  
   205  	// Ensure updating the default zone config applies to zones that have had
   206  	// overrides added and removed.
   207  	sqlutils.SetZoneConfig(t, sqlDB, "RANGE default", yamlDefault)
   208  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow)
   209  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "RANGE default", defaultRow)
   210  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "DATABASE d", defaultRow)
   211  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", defaultRow)
   212  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "INDEX d.t@primary", defaultRow)
   213  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", defaultRow)
   214  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", defaultRow)
   215  
   216  	// Ensure subzones can be created even when no table zone exists.
   217  	sqlutils.SetZoneConfig(t, sqlDB, "PARTITION p0 OF TABLE d.t", yamlOverride)
   218  	sqlutils.SetZoneConfig(t, sqlDB, "PARTITION p1 OF TABLE d.t", yamlOverride)
   219  	sqlutils.VerifyAllZoneConfigs(t, sqlDB, defaultRow, partialP0Row, partialP1Row)
   220  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "TABLE d.t", defaultRow)
   221  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE d.t", p0Row)
   222  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p1 OF TABLE d.t", p1Row)
   223  
   224  	// Ensure the shorthand index syntax works.
   225  	sqlutils.SetZoneConfig(t, sqlDB, `INDEX "primary"`, yamlOverride)
   226  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, `INDEX "primary"`, primaryRow)
   227  
   228  	// Ensure the session database is respected.
   229  	sqlutils.SetZoneConfig(t, sqlDB, "PARTITION p0 OF TABLE t", yamlOverride)
   230  	sqlutils.VerifyZoneConfigForTarget(t, sqlDB, "PARTITION p0 OF TABLE t", p0Row)
   231  }
   232  
   233  func TestInvalidIndexPartitionSetShowZones(t *testing.T) {
   234  	defer leaktest.AfterTest(t)()
   235  
   236  	s, db, _ := serverutils.StartServer(t, base.TestServerArgs{})
   237  	defer s.Stopper().Stop(context.Background())
   238  
   239  	for i, tc := range []struct {
   240  		query string
   241  		err   string
   242  	}{
   243  		{
   244  			"ALTER INDEX foo CONFIGURE ZONE USING DEFAULT",
   245  			`index "foo" does not exist`,
   246  		},
   247  		{
   248  			"SHOW ZONE CONFIGURATION FOR INDEX foo",
   249  			`index "foo" does not exist`,
   250  		},
   251  		{
   252  			"USE system; ALTER INDEX foo CONFIGURE ZONE USING DEFAULT",
   253  			`index "foo" does not exist`,
   254  		},
   255  		{
   256  			"USE system; SHOW ZONE CONFIGURATION FOR INDEX foo",
   257  			`index "foo" does not exist`,
   258  		},
   259  		{
   260  			"ALTER PARTITION p0 OF TABLE system.jobs CONFIGURE ZONE = 'foo'",
   261  			`partition "p0" does not exist`,
   262  		},
   263  		{
   264  			"SHOW ZONE CONFIGURATION FOR PARTITION p0 OF TABLE system.jobs",
   265  			`partition "p0" does not exist`,
   266  		},
   267  	} {
   268  		if _, err := db.Exec(tc.query); !testutils.IsError(err, tc.err) {
   269  			t.Errorf("#%d: expected error matching %q, but got %v", i, tc.err, err)
   270  		}
   271  	}
   272  }
   273  
   274  func TestGenerateSubzoneSpans(t *testing.T) {
   275  	defer leaktest.AfterTest(t)()
   276  	rng, _ := randutil.NewPseudoRand()
   277  
   278  	partitioningTests := allPartitioningTests(rng)
   279  	for _, test := range partitioningTests {
   280  		if test.generatedSpans == nil {
   281  			// The randomized partition tests don't have generatedSpans, and
   282  			// wouldn't be very interesting to test.
   283  			continue
   284  		}
   285  		t.Run(test.name, func(t *testing.T) {
   286  			if err := test.parse(); err != nil {
   287  				t.Fatalf("%+v", err)
   288  			}
   289  			clusterID := uuid.MakeV4()
   290  			hasNewSubzones := false
   291  			spans, err := sql.GenerateSubzoneSpans(
   292  				cluster.NoSettings, clusterID, keys.SystemSQLCodec, test.parsed.tableDesc, test.parsed.subzones, hasNewSubzones)
   293  			if err != nil {
   294  				t.Fatalf("generating subzone spans: %+v", err)
   295  			}
   296  
   297  			var actual []string
   298  			for _, span := range spans {
   299  				subzone := test.parsed.subzones[span.SubzoneIndex]
   300  				idxDesc, err := test.parsed.tableDesc.FindIndexByID(sqlbase.IndexID(subzone.IndexID))
   301  				if err != nil {
   302  					t.Fatalf("could not find index with ID %d: %+v", subzone.IndexID, err)
   303  				}
   304  
   305  				directions := []encoding.Direction{encoding.Ascending /* index ID */}
   306  				for _, cd := range idxDesc.ColumnDirections {
   307  					ed, err := cd.ToEncodingDirection()
   308  					if err != nil {
   309  						t.Fatal(err)
   310  					}
   311  					directions = append(directions, ed)
   312  				}
   313  
   314  				var subzoneShort string
   315  				if len(subzone.PartitionName) > 0 {
   316  					subzoneShort = "." + subzone.PartitionName
   317  				} else {
   318  					subzoneShort = "@" + idxDesc.Name
   319  				}
   320  
   321  				// Verify that we're always doing the space savings when we can.
   322  				if span.Key.PrefixEnd().Equal(span.EndKey) {
   323  					t.Errorf("endKey should be omitted when equal to key.PrefixEnd [%s, %s)",
   324  						encoding.PrettyPrintValue(directions, span.Key, "/"),
   325  						encoding.PrettyPrintValue(directions, span.EndKey, "/"))
   326  				}
   327  				if len(span.EndKey) == 0 {
   328  					span.EndKey = span.Key.PrefixEnd()
   329  				}
   330  
   331  				// TODO(dan): Check that spans are sorted.
   332  
   333  				actual = append(actual, fmt.Sprintf("%s %s-%s", subzoneShort,
   334  					encoding.PrettyPrintValue(directions, span.Key, "/"),
   335  					encoding.PrettyPrintValue(directions, span.EndKey, "/")))
   336  			}
   337  
   338  			if len(actual) != len(test.generatedSpans) {
   339  				t.Fatalf("got \n    %v\n expected \n    %v", actual, test.generatedSpans)
   340  			}
   341  			for i := range actual {
   342  				if expected := strings.TrimSpace(test.generatedSpans[i]); actual[i] != expected {
   343  					t.Errorf("%d: got [%s] expected [%s]", i, actual[i], expected)
   344  				}
   345  			}
   346  		})
   347  	}
   348  }