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

     1  // Copyright 2015 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
    12  
    13  import (
    14  	"context"
    15  	"reflect"
    16  	"testing"
    17  
    18  	"github.com/cockroachdb/cockroach/pkg/keys"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    21  	"github.com/cockroachdb/cockroach/pkg/sql/tests"
    22  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    23  	"github.com/cockroachdb/cockroach/pkg/testutils"
    24  	"github.com/cockroachdb/cockroach/pkg/testutils/serverutils"
    25  	"github.com/cockroachdb/cockroach/pkg/util/leaktest"
    26  	"github.com/cockroachdb/cockroach/pkg/util/protoutil"
    27  )
    28  
    29  func TestMakeTableDescColumns(t *testing.T) {
    30  	defer leaktest.AfterTest(t)()
    31  
    32  	testData := []struct {
    33  		sqlType  string
    34  		colType  *types.T
    35  		nullable bool
    36  	}{
    37  		{
    38  			"BIT",
    39  			types.MakeBit(1),
    40  			true,
    41  		},
    42  		{
    43  			"BIT(3)",
    44  			types.MakeBit(3),
    45  			true,
    46  		},
    47  		{
    48  			"VARBIT",
    49  			types.VarBit,
    50  			true,
    51  		},
    52  		{
    53  			"VARBIT(3)",
    54  			types.MakeVarBit(3),
    55  			true,
    56  		},
    57  		{
    58  			"BOOLEAN",
    59  			types.Bool,
    60  			true,
    61  		},
    62  		{
    63  			"INT",
    64  			types.Int,
    65  			true,
    66  		},
    67  		{
    68  			"INT2",
    69  			types.Int2,
    70  			true,
    71  		},
    72  		{
    73  			"INT4",
    74  			types.Int4,
    75  			true,
    76  		},
    77  		{
    78  			"INT8",
    79  			types.Int,
    80  			true,
    81  		},
    82  		{
    83  			"INT64",
    84  			types.Int,
    85  			true,
    86  		},
    87  		{
    88  			"BIGINT",
    89  			types.Int,
    90  			true,
    91  		},
    92  		{
    93  			"FLOAT(3)",
    94  			types.Float4,
    95  			true,
    96  		},
    97  		{
    98  			"DOUBLE PRECISION",
    99  			types.Float,
   100  			true,
   101  		},
   102  		{
   103  			"DECIMAL(6,5)",
   104  			types.MakeDecimal(6, 5),
   105  			true,
   106  		},
   107  		{
   108  			"DATE",
   109  			types.Date,
   110  			true,
   111  		},
   112  		{
   113  			"TIME",
   114  			types.Time,
   115  			true,
   116  		},
   117  		{
   118  			"TIMESTAMP",
   119  			types.Timestamp,
   120  			true,
   121  		},
   122  		{
   123  			"INTERVAL",
   124  			types.Interval,
   125  			true,
   126  		},
   127  		{
   128  			"CHAR",
   129  			types.MakeChar(1),
   130  			true,
   131  		},
   132  		{
   133  			"CHAR(3)",
   134  			types.MakeChar(3),
   135  			true,
   136  		},
   137  		{
   138  			"VARCHAR",
   139  			types.VarChar,
   140  			true,
   141  		},
   142  		{
   143  			"VARCHAR(3)",
   144  			types.MakeVarChar(3),
   145  			true,
   146  		},
   147  		{
   148  			"TEXT",
   149  			types.String,
   150  			true,
   151  		},
   152  		{
   153  			`"char"`,
   154  			types.MakeQChar(0),
   155  			true,
   156  		},
   157  		{
   158  			"BLOB",
   159  			types.Bytes,
   160  			true,
   161  		},
   162  		{
   163  			"INT NOT NULL",
   164  			types.Int,
   165  			false,
   166  		},
   167  		{
   168  			"INT NULL",
   169  			types.Int,
   170  			true,
   171  		},
   172  	}
   173  	for i, d := range testData {
   174  		s := "CREATE TABLE foo.test (a " + d.sqlType + " PRIMARY KEY, b " + d.sqlType + ")"
   175  		schema, err := CreateTestTableDescriptor(context.Background(), 1, 100, s, sqlbase.NewDefaultPrivilegeDescriptor())
   176  		if err != nil {
   177  			t.Fatalf("%d: %v", i, err)
   178  		}
   179  		if schema.Columns[0].Nullable {
   180  			t.Fatalf("%d: expected non-nullable primary key, but got %+v", i, schema.Columns[0].Nullable)
   181  		}
   182  		if !d.colType.Identical(schema.Columns[0].Type) {
   183  			t.Fatalf("%d: expected %+v, but got %+v", i, d.colType.DebugString(), schema.Columns[0].Type.DebugString())
   184  		}
   185  		if d.nullable != schema.Columns[1].Nullable {
   186  			t.Fatalf("%d: expected %+v, but got %+v", i, d.nullable, schema.Columns[1].Nullable)
   187  		}
   188  	}
   189  }
   190  
   191  func TestMakeTableDescIndexes(t *testing.T) {
   192  	defer leaktest.AfterTest(t)()
   193  
   194  	testData := []struct {
   195  		sql     string
   196  		primary sqlbase.IndexDescriptor
   197  		indexes []sqlbase.IndexDescriptor
   198  	}{
   199  		{
   200  			"a INT PRIMARY KEY",
   201  			sqlbase.IndexDescriptor{
   202  				Name:             sqlbase.PrimaryKeyIndexName,
   203  				ID:               1,
   204  				Unique:           true,
   205  				ColumnNames:      []string{"a"},
   206  				ColumnIDs:        []sqlbase.ColumnID{1},
   207  				ColumnDirections: []sqlbase.IndexDescriptor_Direction{sqlbase.IndexDescriptor_ASC},
   208  				Version:          sqlbase.SecondaryIndexFamilyFormatVersion,
   209  			},
   210  			[]sqlbase.IndexDescriptor{},
   211  		},
   212  		{
   213  			"a INT UNIQUE, b INT PRIMARY KEY",
   214  			sqlbase.IndexDescriptor{
   215  				Name:             "primary",
   216  				ID:               1,
   217  				Unique:           true,
   218  				ColumnNames:      []string{"b"},
   219  				ColumnIDs:        []sqlbase.ColumnID{2},
   220  				ColumnDirections: []sqlbase.IndexDescriptor_Direction{sqlbase.IndexDescriptor_ASC},
   221  				Version:          sqlbase.SecondaryIndexFamilyFormatVersion,
   222  			},
   223  			[]sqlbase.IndexDescriptor{
   224  				{
   225  					Name:             "test_a_key",
   226  					ID:               2,
   227  					Unique:           true,
   228  					ColumnNames:      []string{"a"},
   229  					ColumnIDs:        []sqlbase.ColumnID{1},
   230  					ExtraColumnIDs:   []sqlbase.ColumnID{2},
   231  					ColumnDirections: []sqlbase.IndexDescriptor_Direction{sqlbase.IndexDescriptor_ASC},
   232  					Version:          sqlbase.SecondaryIndexFamilyFormatVersion,
   233  				},
   234  			},
   235  		},
   236  		{
   237  			"a INT, b INT, CONSTRAINT c PRIMARY KEY (a, b)",
   238  			sqlbase.IndexDescriptor{
   239  				Name:             "c",
   240  				ID:               1,
   241  				Unique:           true,
   242  				ColumnNames:      []string{"a", "b"},
   243  				ColumnIDs:        []sqlbase.ColumnID{1, 2},
   244  				ColumnDirections: []sqlbase.IndexDescriptor_Direction{sqlbase.IndexDescriptor_ASC, sqlbase.IndexDescriptor_ASC},
   245  				Version:          sqlbase.SecondaryIndexFamilyFormatVersion,
   246  			},
   247  			[]sqlbase.IndexDescriptor{},
   248  		},
   249  		{
   250  			"a INT, b INT, CONSTRAINT c UNIQUE (b), PRIMARY KEY (a, b)",
   251  			sqlbase.IndexDescriptor{
   252  				Name:             "primary",
   253  				ID:               1,
   254  				Unique:           true,
   255  				ColumnNames:      []string{"a", "b"},
   256  				ColumnIDs:        []sqlbase.ColumnID{1, 2},
   257  				ColumnDirections: []sqlbase.IndexDescriptor_Direction{sqlbase.IndexDescriptor_ASC, sqlbase.IndexDescriptor_ASC},
   258  				Version:          sqlbase.SecondaryIndexFamilyFormatVersion,
   259  			},
   260  			[]sqlbase.IndexDescriptor{
   261  				{
   262  					Name:             "c",
   263  					ID:               2,
   264  					Unique:           true,
   265  					ColumnNames:      []string{"b"},
   266  					ColumnIDs:        []sqlbase.ColumnID{2},
   267  					ExtraColumnIDs:   []sqlbase.ColumnID{1},
   268  					ColumnDirections: []sqlbase.IndexDescriptor_Direction{sqlbase.IndexDescriptor_ASC},
   269  					Version:          sqlbase.SecondaryIndexFamilyFormatVersion,
   270  				},
   271  			},
   272  		},
   273  		{
   274  			"a INT, b INT, PRIMARY KEY (a, b)",
   275  			sqlbase.IndexDescriptor{
   276  				Name:             sqlbase.PrimaryKeyIndexName,
   277  				ID:               1,
   278  				Unique:           true,
   279  				ColumnNames:      []string{"a", "b"},
   280  				ColumnIDs:        []sqlbase.ColumnID{1, 2},
   281  				ColumnDirections: []sqlbase.IndexDescriptor_Direction{sqlbase.IndexDescriptor_ASC, sqlbase.IndexDescriptor_ASC},
   282  				Version:          sqlbase.SecondaryIndexFamilyFormatVersion,
   283  			},
   284  			[]sqlbase.IndexDescriptor{},
   285  		},
   286  	}
   287  	for i, d := range testData {
   288  		s := "CREATE TABLE foo.test (" + d.sql + ")"
   289  		schema, err := CreateTestTableDescriptor(context.Background(), 1, 100, s, sqlbase.NewDefaultPrivilegeDescriptor())
   290  		if err != nil {
   291  			t.Fatalf("%d (%s): %v", i, d.sql, err)
   292  		}
   293  		if !reflect.DeepEqual(d.primary, schema.PrimaryIndex) {
   294  			t.Fatalf("%d (%s): primary mismatch: expected %+v, but got %+v", i, d.sql, d.primary, schema.PrimaryIndex)
   295  		}
   296  		if !reflect.DeepEqual(d.indexes, append([]sqlbase.IndexDescriptor{}, schema.Indexes...)) {
   297  			t.Fatalf("%d (%s): index mismatch: expected %+v, but got %+v", i, d.sql, d.indexes, schema.Indexes)
   298  		}
   299  
   300  	}
   301  }
   302  
   303  func TestPrimaryKeyUnspecified(t *testing.T) {
   304  	defer leaktest.AfterTest(t)()
   305  	s := "CREATE TABLE foo.test (a INT, b INT, CONSTRAINT c UNIQUE (b))"
   306  	desc, err := CreateTestTableDescriptor(context.Background(), 1, 100, s, sqlbase.NewDefaultPrivilegeDescriptor())
   307  	if err != nil {
   308  		t.Fatal(err)
   309  	}
   310  	desc.PrimaryIndex = sqlbase.IndexDescriptor{}
   311  
   312  	err = desc.ValidateTable()
   313  	if !testutils.IsError(err, sqlbase.ErrMissingPrimaryKey.Error()) {
   314  		t.Fatalf("unexpected error: %v", err)
   315  	}
   316  }
   317  
   318  func TestCanCloneTableWithUDT(t *testing.T) {
   319  	defer leaktest.AfterTest(t)()
   320  
   321  	ctx := context.Background()
   322  	params, _ := tests.CreateTestServerParams()
   323  	s, sqlDB, kvDB := serverutils.StartServer(t, params)
   324  	defer s.Stopper().Stop(ctx)
   325  	if _, err := sqlDB.Exec(`
   326  SET experimental_enable_enums=true;
   327  CREATE DATABASE test;
   328  CREATE TYPE test.t AS ENUM ('hello');
   329  CREATE TABLE test.tt (x test.t);
   330  `); err != nil {
   331  		t.Fatal(err)
   332  	}
   333  	desc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "tt")
   334  	typLookup := func(id sqlbase.ID) (*tree.TypeName, *sqlbase.TypeDescriptor, error) {
   335  		typDesc, err := sqlbase.GetTypeDescFromID(ctx, kvDB, keys.SystemSQLCodec, id)
   336  		if err != nil {
   337  			return nil, nil, err
   338  		}
   339  		return &tree.TypeName{}, typDesc, nil
   340  	}
   341  	if err := sqlbase.HydrateTypesInTableDescriptor(desc, typLookup); err != nil {
   342  		t.Fatal(err)
   343  	}
   344  	// Ensure that we can clone this table.
   345  	_ = protoutil.Clone(desc).(*TableDescriptor)
   346  }
   347  
   348  // TestSerializedUDTsInTableDescriptor tests that expressions containing
   349  // explicit type references and members of user defined types are serialized
   350  // in a way that is stable across changes to the type itself. For example,
   351  // we want to ensure that enum members are serialized in a way that is stable
   352  // across renames to the member itself.
   353  func TestSerializedUDTsInTableDescriptor(t *testing.T) {
   354  	defer leaktest.AfterTest(t)()
   355  
   356  	ctx := context.Background()
   357  	getDefault := func(desc *TableDescriptor) string {
   358  		return *desc.Columns[0].DefaultExpr
   359  	}
   360  	getComputed := func(desc *TableDescriptor) string {
   361  		return *desc.Columns[0].ComputeExpr
   362  	}
   363  	getCheck := func(desc *TableDescriptor) string {
   364  		return desc.Checks[0].Expr
   365  	}
   366  	testdata := []struct {
   367  		colSQL       string
   368  		expectedExpr string
   369  		getExpr      func(desc *TableDescriptor) string
   370  	}{
   371  		// Test a simple UDT as the default value.
   372  		{
   373  			"x greeting DEFAULT ('hello')",
   374  			`b'\x80':::@53`,
   375  			getDefault,
   376  		},
   377  		{
   378  			"x greeting DEFAULT ('hello':::greeting)",
   379  			`b'\x80':::@53`,
   380  			getDefault,
   381  		},
   382  		// Test when a UDT is used in a default value, but isn't the
   383  		// final type of the column.
   384  		{
   385  			"x INT DEFAULT (CASE WHEN 'hello'::greeting = 'hello'::greeting THEN 0 ELSE 1 END)",
   386  			`CASE WHEN b'\x80':::@53::@53 = b'\x80':::@53::@53 THEN 0:::INT8 ELSE 1:::INT8 END`,
   387  			getDefault,
   388  		},
   389  		{
   390  			"x BOOL DEFAULT ('hello'::greeting IS OF (greeting, greeting))",
   391  			`b'\x80':::@53::@53 IS OF (@53, @53)`,
   392  			getDefault,
   393  		},
   394  		// Test check constraints.
   395  		{
   396  			"x greeting, CHECK (x = 'hello')",
   397  			`x = b'\x80':::@53`,
   398  			getCheck,
   399  		},
   400  		{
   401  			"x greeting, y STRING, CHECK (y::greeting = x)",
   402  			`y::@53 = x`,
   403  			getCheck,
   404  		},
   405  		// Test a computed column in the same cases as above.
   406  		{
   407  			"x greeting AS ('hello') STORED",
   408  			`b'\x80':::@53`,
   409  			getComputed,
   410  		},
   411  		{
   412  			"x INT AS (CASE WHEN 'hello'::greeting = 'hello'::greeting THEN 0 ELSE 1 END) STORED",
   413  			`CASE WHEN b'\x80':::@53::@53 = b'\x80':::@53::@53 THEN 0:::INT8 ELSE 1:::INT8 END`,
   414  			getComputed,
   415  		},
   416  	}
   417  
   418  	params, _ := tests.CreateTestServerParams()
   419  	s, sqlDB, kvDB := serverutils.StartServer(t, params)
   420  	defer s.Stopper().Stop(ctx)
   421  	if _, err := sqlDB.Exec(`
   422  	CREATE DATABASE test;
   423  	USE test;
   424  	SET experimental_enable_enums=true;
   425  	CREATE TYPE greeting AS ENUM ('hello');
   426  `); err != nil {
   427  		t.Fatal(err)
   428  	}
   429  	for _, tc := range testdata {
   430  		create := "CREATE TABLE t (" + tc.colSQL + ")"
   431  		if _, err := sqlDB.Exec(create); err != nil {
   432  			t.Fatal(err)
   433  		}
   434  		desc := sqlbase.GetTableDescriptor(kvDB, keys.SystemSQLCodec, "test", "t")
   435  		found := tc.getExpr(desc)
   436  		if tc.expectedExpr != found {
   437  			t.Errorf("for column %s, found %s, expected %s", tc.colSQL, found, tc.expectedExpr)
   438  		}
   439  		if _, err := sqlDB.Exec("DROP TABLE t"); err != nil {
   440  			t.Fatal(err)
   441  		}
   442  	}
   443  }