...
 
Commits (4)
  • Nathan VanBenschoten's avatar
    sql: Remove cluster version input to GetInitialValues · c2dabe03
    Nathan VanBenschoten authored
    Addresses a TODO and helps clear the way for #47904.
    c2dabe03
  • Nathan VanBenschoten's avatar
    sql: properly handle NULL hashedPassword column in system.users · 7901304f
    Nathan VanBenschoten authored
    Fixes #48769.
    
    Before this change, attempts to log in as a user with a NULL value
    in their "hashedPassword" column in the system.users table would
    cause the server to crash. This was because `retrieveUserAndPassword`
    was not properly handling NULL values.
    
    This change fixes this.
    
    Release note (bug fix): Manually writing a NULL value into the
    system.users table for the "hashedPassword" column will no longer
    cause a server crash during user authentication.
    7901304f
  • Nathan VanBenschoten's avatar
    sql: properly handle nil byte slices in golangFillQueryArguments · 9d64636c
    Nathan VanBenschoten authored
    Before this, nil byte slices were being treated as empty byte slices,
    which resulted in confusing behavior where a nil byte slice passed to an
    InternalExecutor would not be NULL.
    
    Also, fix TestGolangQueryArgs, which was completely broken and asserting
    that `reflect.Type(*types.T) == reflect.Type(*types.T)`.
    
    This change is what caught the bug fixed by the previous change.
    9d64636c
  • craig[bot]'s avatar
    Merge #48504 #48773 · ee733b32
    craig[bot] authored
    48504: sql: Remove cluster version input to GetInitialValues r=nvanbenschoten a=nvanbenschoten
    
    Addresses a TODO and helps clear the way for #47904.
    
    This does not remove the rest of the references to `VersionNamespaceTableWithSchemas`.
    
    48773: sql: properly handle NULL hashedPassword column in system.users r=nvanbenschoten a=nvanbenschoten
    
    Fixes #48769.
    
    Before this change, attempts to log in as a user with a NULL value in their "hashedPassword" column in the `system.users` table would cause the server to crash. This was because `retrieveUserAndPassword` was not properly handling NULL values.
    
    This change fixes this. It then fixes the bug that led me to the first one - we were not properly handling nil byte slices in `golangFillQueryArguments`. Nil byte slices were being treated as empty byte slices, which resulted in confusing behavior where a nil byte slice passed to an InternalExecutor would not be NULL. I'm considered backporting this fix, but I don't think we should. I fear that doing so will have unintended consequences by tickling other bugs like what is fixed in the first commit.
    
    Finally, this fixes `TestGolangQueryArgs`, which was completely broken and asserting that `reflect.Type(*types.T) == reflect.Type(*types.T)`.
    
    Release note (bug fix): Manually writing a NULL value into the system.users table for the "hashedPassword" column will no longer cause a server crash during user authentication.
    Co-authored-by: default avatarNathan VanBenschoten <[email protected]>
    ee733b32
......@@ -14,7 +14,6 @@ import (
"sort"
"testing"
"github.com/cockroachdb/cockroach/pkg/clusterversion"
"github.com/cockroachdb/cockroach/pkg/config"
"github.com/cockroachdb/cockroach/pkg/config/zonepb"
"github.com/cockroachdb/cockroach/pkg/keys"
......@@ -165,7 +164,7 @@ func TestGetLargestID(t *testing.T) {
ms := sqlbase.MakeMetadataSchema(keys.SystemSQLCodec, zonepb.DefaultZoneConfigRef(), zonepb.DefaultSystemZoneConfigRef())
descIDs := ms.DescriptorIDs()
maxDescID := descIDs[len(descIDs)-1]
kvs, _ /* splits */ := ms.GetInitialValues(clusterversion.TestingClusterVersion)
kvs, _ /* splits */ := ms.GetInitialValues()
return testCase{kvs, uint32(maxDescID), 0, ""}
}(),
......@@ -260,7 +259,7 @@ func TestComputeSplitKeySystemRanges(t *testing.T) {
cfg := config.NewSystemConfig(zonepb.DefaultZoneConfigRef())
kvs, _ /* splits */ := sqlbase.MakeMetadataSchema(
keys.SystemSQLCodec, cfg.DefaultZoneConfig, zonepb.DefaultSystemZoneConfigRef(),
).GetInitialValues(clusterversion.TestingClusterVersion)
).GetInitialValues()
cfg.SystemConfigEntries = config.SystemConfigEntries{
Values: kvs,
}
......@@ -294,9 +293,9 @@ func TestComputeSplitKeyTableIDs(t *testing.T) {
keys.SystemSQLCodec, zonepb.DefaultZoneConfigRef(), zonepb.DefaultSystemZoneConfigRef(),
)
// Real system tables only.
baseSql, _ /* splits */ := schema.GetInitialValues(clusterversion.TestingClusterVersion)
baseSql, _ /* splits */ := schema.GetInitialValues()
// Real system tables plus some user stuff.
kvs, _ /* splits */ := schema.GetInitialValues(clusterversion.TestingClusterVersion)
kvs, _ /* splits */ := schema.GetInitialValues()
userSQL := append(kvs, descriptor(start), descriptor(start+1), descriptor(start+5))
// Real system tables and partitioned user tables.
var subzoneSQL = make([]roachpb.KeyValue, len(userSQL))
......@@ -440,7 +439,7 @@ func TestGetZoneConfigForKey(t *testing.T) {
kvs, _ /* splits */ := sqlbase.MakeMetadataSchema(
keys.SystemSQLCodec, cfg.DefaultZoneConfig, zonepb.DefaultSystemZoneConfigRef(),
).GetInitialValues(clusterversion.TestingClusterVersion)
).GetInitialValues()
cfg.SystemConfigEntries = config.SystemConfigEntries{
Values: kvs,
}
......
......@@ -24,7 +24,6 @@ import (
"time"
"github.com/cockroachdb/cockroach/pkg/base"
"github.com/cockroachdb/cockroach/pkg/clusterversion"
"github.com/cockroachdb/cockroach/pkg/config"
"github.com/cockroachdb/cockroach/pkg/config/zonepb"
"github.com/cockroachdb/cockroach/pkg/gossip"
......@@ -1292,7 +1291,7 @@ func TestStoreRangeSystemSplits(t *testing.T) {
return err
}
descTablePrefix := keys.SystemSQLCodec.TablePrefix(keys.DescriptorTableID)
kvs, _ /* splits */ := schema.GetInitialValues(clusterversion.TestingClusterVersion)
kvs, _ /* splits */ := schema.GetInitialValues()
for _, kv := range kvs {
if !bytes.HasPrefix(kv.Key, descTablePrefix) {
continue
......
......@@ -186,10 +186,9 @@ func createTestStoreWithOpts(
if !opts.dontBootstrap {
var kvs []roachpb.KeyValue
var splits []roachpb.RKey
bootstrapVersion := clusterversion.TestingClusterVersion
kvs, tableSplits := sqlbase.MakeMetadataSchema(
keys.SystemSQLCodec, storeCfg.DefaultZoneConfig, storeCfg.DefaultSystemZoneConfig,
).GetInitialValues(bootstrapVersion)
).GetInitialValues()
if !opts.dontCreateSystemRanges {
splits = config.StaticSplits()
splits = append(splits, tableSplits...)
......@@ -892,10 +891,9 @@ func (m *multiTestContext) addStore(idx int) {
if needBootstrap && idx == 0 {
// Bootstrap the initial range on the first engine.
var splits []roachpb.RKey
bootstrapVersion := clusterversion.TestingClusterVersion
kvs, tableSplits := sqlbase.MakeMetadataSchema(
keys.SystemSQLCodec, cfg.DefaultZoneConfig, cfg.DefaultSystemZoneConfig,
).GetInitialValues(bootstrapVersion)
).GetInitialValues()
if !m.startWithSingleRange {
splits = config.StaticSplits()
splits = append(splits, tableSplits...)
......
......@@ -59,7 +59,7 @@ FROM (
version + 1 AS new_version,
num_records + 1 AS new_num_records,
num_spans + $3 AS new_num_spans,
total_bytes + length($9) + length($6) + length($7) AS new_total_bytes
total_bytes + length($9) + length($6) + coalesce(length($7:::BYTES),0) AS new_total_bytes
FROM
current_meta
)
......@@ -135,7 +135,7 @@ RETURNING
SELECT
id,
num_spans AS record_spans,
length(spans) + length(meta_type) + length(meta) AS record_bytes
length(spans) + length(meta_type) + coalesce(length(meta),0) AS record_bytes
FROM
system.protected_ts_records
WHERE
......
......@@ -67,13 +67,22 @@ func (p *storage) Protect(ctx context.Context, txn *kv.Txn, r *ptpb.Record) erro
if err != nil { // how can this possibly fail?
return errors.Wrap(err, "failed to marshal spans")
}
meta := r.Meta
if meta == nil {
// v20.1 crashes in rowToRecord and storage.Release if it finds a NULL
// value in system.protected_ts_records.meta. v20.2 and above handle
// this correctly, but we need to maintain mixed version compatibility
// for at least one release.
// TODO(nvanbenschoten): remove this for v21.1.
meta = []byte{}
}
s := makeSettings(p.settings)
rows, err := p.ex.QueryEx(ctx, "protectedts-protect", txn,
sqlbase.InternalExecutorSessionDataOverride{User: security.NodeUser},
protectQuery,
s.maxSpans, s.maxBytes, len(r.Spans),
r.ID.GetBytesMut(), r.Timestamp.AsOfSystemTime(),
r.MetaType, r.Meta,
r.MetaType, meta,
len(r.Spans), encodedSpans)
if err != nil {
return errors.Wrapf(err, "failed to write record %v", r.ID)
......@@ -218,8 +227,10 @@ func rowToRecord(ctx context.Context, row tree.Datums, r *ptpb.Record) error {
r.Timestamp = ts
r.MetaType = string(*row[2].(*tree.DString))
if meta := row[3].(*tree.DBytes); meta != nil && len(*meta) > 0 {
r.Meta = []byte(*meta)
if row[3] != tree.DNull {
if meta := row[3].(*tree.DBytes); len(*meta) > 0 {
r.Meta = []byte(*meta)
}
}
var spans Spans
if err := protoutil.Unmarshal([]byte(*row[4].(*tree.DBytes)), &spans); err != nil {
......
......@@ -239,10 +239,9 @@ func createTestStoreWithoutStart(
t.Fatal(err)
}
var splits []roachpb.RKey
bootstrapVersion := clusterversion.TestingClusterVersion
kvs, tableSplits := sqlbase.MakeMetadataSchema(
keys.SystemSQLCodec, cfg.DefaultZoneConfig, cfg.DefaultSystemZoneConfig,
).GetInitialValues(bootstrapVersion)
).GetInitialValues()
if opts.createSystemRanges {
splits = config.StaticSplits()
splits = append(splits, tableSplits...)
......@@ -456,10 +455,9 @@ func TestStoreInitAndBootstrap(t *testing.T) {
// Bootstrap the system ranges.
var splits []roachpb.RKey
bootstrapVersion := clusterversion.TestingClusterVersion
kvs, tableSplits := sqlbase.MakeMetadataSchema(
keys.SystemSQLCodec, cfg.DefaultZoneConfig, cfg.DefaultSystemZoneConfig,
).GetInitialValues(bootstrapVersion)
).GetInitialValues()
splits = config.StaticSplits()
splits = append(splits, tableSplits...)
sort.Slice(splits, func(i, j int) bool {
......
......@@ -217,18 +217,14 @@ func bootstrapCluster(
cv, err := kvserver.ReadClusterVersion(ctx, eng)
if err != nil {
return nil, errors.Wrapf(err, "reading cluster version of %s", eng)
}
// bootstrapCluster requires matching cluster versions on all engines.
if cv.Major == 0 {
} else if cv.Major == 0 {
return nil, errors.Errorf("missing bootstrap version")
}
// bootstrapCluster requires matching cluster versions on all engines.
if i == 0 {
bootstrapVersion = cv
}
if bootstrapVersion != cv {
} else if bootstrapVersion != cv {
return nil, errors.Wrapf(err, "found cluster versions %s and %s", bootstrapVersion, cv)
}
......@@ -249,7 +245,7 @@ func bootstrapCluster(
// first store.
if i == 0 {
schema := GetBootstrapSchema(keys.SystemSQLCodec, defaultZoneConfig, defaultSystemZoneConfig)
initialValues, tableSplits := schema.GetInitialValues(bootstrapVersion)
initialValues, tableSplits := schema.GetInitialValues()
splits := append(config.StaticSplits(), tableSplits...)
sort.Slice(splits, func(i, j int) bool {
return splits[i].Less(splits[j])
......
......@@ -91,7 +91,7 @@ func TestBootstrapCluster(t *testing.T) {
// Add the initial keys for sql.
kvs, tableSplits := GetBootstrapSchema(
keys.SystemSQLCodec, zonepb.DefaultZoneConfigRef(), zonepb.DefaultSystemZoneConfigRef(),
).GetInitialValues(clusterversion.TestingClusterVersion)
).GetInitialValues()
for _, kv := range kvs {
expectedKeys = append(expectedKeys, kv.Key)
}
......
......@@ -146,6 +146,15 @@ func (n *alterRoleNode) startExec(params runParams) error {
"setting or updating a password is not supported in insecure mode")
}
if hashedPassword == nil {
// v20.1 and below crash during authentication if they find a NULL value
// in system.users.hashedPassword. v20.2 and above handle this correctly,
// but we need to maintain mixed version compatibility for at least one
// release.
// TODO(nvanbenschoten): remove this for v21.1.
hashedPassword = []byte{}
}
// Updating PASSWORD is a special case since PASSWORD lives in system.users
// while the rest of the role options lives in system.role_options.
_, err = params.extendedEvalCtx.ExecCfg.InternalExecutor.Exec(
......
......@@ -125,6 +125,13 @@ func (n *CreateRoleNode) startExec(params runParams) error {
return pgerror.New(pgcode.InvalidPassword,
"setting or updating a password is not supported in insecure mode")
}
} else {
// v20.1 and below crash during authentication if they find a NULL value
// in system.users.hashedPassword. v20.2 and above handle this correctly,
// but we need to maintain mixed version compatibility for at least one
// release.
// TODO(nvanbenschoten): remove this for v21.1.
hashedPassword = []byte{}
}
// Reject the "public" role. It does not have an entry in the users table but is reserved.
......
......@@ -905,8 +905,10 @@ func golangFillQueryArguments(args ...interface{}) (tree.Datums, error) {
case reflect.String:
d = tree.NewDString(val.String())
case reflect.Slice:
// Handle byte slices.
if val.Type().Elem().Kind() == reflect.Uint8 {
switch {
case val.IsNil():
d = tree.DNull
case val.Type().Elem().Kind() == reflect.Uint8:
d = tree.NewDBytes(tree.DBytes(val.Bytes()))
}
}
......
# LogicTest: local-mixed-19.2-20.1
# This should test the local-mixed-19.2-20.1 configuration because system.namespace
# changed in 20.1.
query ITI rowsort
SELECT * FROM system.namespace
----
0 defaultdb 50
0 postgres 51
0 system 1
0 test 52
1 comments 24
1 descriptor 3
1 eventlog 12
1 jobs 15
1 lease 11
1 locations 21
1 namespace 2
1 namespace2 30
1 protected_ts_meta 31
1 protected_ts_records 32
1 rangelog 13
1 replication_constraint_stats 25
1 replication_critical_localities 26
1 replication_stats 27
1 reports_meta 28
1 role_members 23
1 role_options 33
1 settings 6
1 statement_bundle_chunks 34
1 statement_diagnostics 36
1 statement_diagnostics_requests 35
1 table_statistics 20
1 ui 14
1 users 4
1 web_sessions 19
1 zones 5
# Verify format of system namespace.
query TTBTTTB
SHOW COLUMNS FROM system.namespace
----
parentID INT8 false NULL · {primary} false
name STRING false NULL · {primary} false
id INT8 true NULL · {} false
......@@ -267,4 +267,3 @@ I: [n1,client=XXX,local] 81 disconnected; duration: XXX
subtest end
subtest end
......@@ -93,3 +93,34 @@ DROP USER testuser; CREATE USER testuser
ok
subtest end user_has_both_cert_and_passwd
subtest user_has_null_hashed_password_column
# This test manually adds a user to the system.users table with a NULL (not
# empty) hashedPassword and attempts to log in as that user. This used to crash
# the server (and this test) because the authentication routine only properly
# handled empty hashedPassword values. See #48769.
sql
INSERT INTO system.users (username, "hashedPassword") VALUES ('nopassword', NULL)
----
ok
set_hba
host all nopassword 0.0.0.0/0 password
----
# Active authentication configuration on this node:
# Original configuration:
# host all root all cert-password # CockroachDB mandatory rule
# host all nopassword 0.0.0.0/0 password
#
# Interpreted configuration:
# TYPE DATABASE USER ADDRESS METHOD OPTIONS
host all root all cert-password
host all nopassword 0.0.0.0/0 password
connect user=nopassword
----
ERROR: password authentication failed for user nopassword
subtest end user_has_null_hashed_password_column
......@@ -131,9 +131,7 @@ func (ms MetadataSchema) SystemDescriptorCount() int {
// a bootstrapping cluster in order to create the tables contained
// in the schema. Also returns a list of split points (a split for each SQL
// table descriptor part of the initial values). Both returned sets are sorted.
func (ms MetadataSchema) GetInitialValues(
bootstrapVersion clusterversion.ClusterVersion,
) ([]roachpb.KeyValue, []roachpb.RKey) {
func (ms MetadataSchema) GetInitialValues() ([]roachpb.KeyValue, []roachpb.RKey) {
var ret []roachpb.KeyValue
var splits []roachpb.RKey
......@@ -152,36 +150,26 @@ func (ms MetadataSchema) GetInitialValues(
// Create name metadata key.
value := roachpb.Value{}
value.SetInt(int64(desc.GetID()))
// TODO(solon): This if/else can be removed in 20.2, as there will be no
// need to support the deprecated namespace table.
if bootstrapVersion.IsActive(clusterversion.VersionNamespaceTableWithSchemas) {
if parentID != keys.RootNamespaceID {
ret = append(ret, roachpb.KeyValue{
Key: NewPublicTableKey(parentID, desc.GetName()).Key(ms.codec),
Value: value,
})
} else {
// Initializing a database. Databases must be initialized with
// the public schema, as all tables are scoped under the public schema.
publicSchemaValue := roachpb.Value{}
publicSchemaValue.SetInt(int64(keys.PublicSchemaID))
ret = append(
ret,
roachpb.KeyValue{
Key: NewDatabaseKey(desc.GetName()).Key(ms.codec),
Value: value,
},
roachpb.KeyValue{
Key: NewPublicSchemaKey(desc.GetID()).Key(ms.codec),
Value: publicSchemaValue,
})
}
} else {
if parentID != keys.RootNamespaceID {
ret = append(ret, roachpb.KeyValue{
Key: NewDeprecatedTableKey(parentID, desc.GetName()).Key(ms.codec),
Key: NewPublicTableKey(parentID, desc.GetName()).Key(ms.codec),
Value: value,
})
} else {
// Initializing a database. Databases must be initialized with
// the public schema, as all tables are scoped under the public schema.
publicSchemaValue := roachpb.Value{}
publicSchemaValue.SetInt(int64(keys.PublicSchemaID))
ret = append(
ret,
roachpb.KeyValue{
Key: NewDatabaseKey(desc.GetName()).Key(ms.codec),
Value: value,
},
roachpb.KeyValue{
Key: NewPublicSchemaKey(desc.GetID()).Key(ms.codec),
Value: publicSchemaValue,
})
}
// Create descriptor metadata key.
......
......@@ -15,7 +15,6 @@ import (
"strings"
"testing"
"github.com/cockroachdb/cockroach/pkg/clusterversion"
"github.com/cockroachdb/cockroach/pkg/config/zonepb"
"github.com/cockroachdb/cockroach/pkg/keys"
"github.com/cockroachdb/cockroach/pkg/roachpb"
......@@ -34,7 +33,7 @@ func TestInitialKeys(t *testing.T) {
const nonDescKeys = 9
ms := sqlbase.MakeMetadataSchema(keys.SystemSQLCodec, zonepb.DefaultZoneConfigRef(), zonepb.DefaultSystemZoneConfigRef())
kv, _ /* splits */ := ms.GetInitialValues(clusterversion.TestingClusterVersion)
kv, _ /* splits */ := ms.GetInitialValues()
expected := nonDescKeys + keysPerDesc*ms.SystemDescriptorCount()
if actual := len(kv); actual != expected {
t.Fatalf("Wrong number of initial sql kv pairs: %d, wanted %d", actual, expected)
......@@ -53,7 +52,7 @@ func TestInitialKeys(t *testing.T) {
t.Fatal(err)
}
ms.AddDescriptor(keys.SystemDatabaseID, &desc)
kv, _ /* splits */ = ms.GetInitialValues(clusterversion.TestingClusterVersion)
kv, _ /* splits */ = ms.GetInitialValues()
expected = nonDescKeys + keysPerDesc*ms.SystemDescriptorCount()
if actual := len(kv); actual != expected {
t.Fatalf("Wrong number of initial sql kv pairs: %d, wanted %d", actual, expected)
......
......@@ -119,7 +119,9 @@ func retrieveUserAndPassword(
}
if values != nil {
exists = true
hashedPassword = []byte(*(values[0].(*tree.DBytes)))
if v := values[0]; v != tree.DNull {
hashedPassword = []byte(*(v.(*tree.DBytes)))
}
}
if !exists {
......
......@@ -182,56 +182,57 @@ func TestGolangQueryArgs(t *testing.T) {
// type
testCases := []struct {
value interface{}
expectedType reflect.Type
expectedType *types.T
}{
// Null type.
{nil, reflect.TypeOf(types.Unknown)},
{nil, types.Unknown},
{[]byte(nil), types.Unknown},
// Bool type.
{true, reflect.TypeOf(types.Bool)},
{true, types.Bool},
// Primitive Integer types.
{int(1), reflect.TypeOf(types.Int)},
{int8(1), reflect.TypeOf(types.Int)},
{int16(1), reflect.TypeOf(types.Int)},
{int32(1), reflect.TypeOf(types.Int)},
{int64(1), reflect.TypeOf(types.Int)},
{uint(1), reflect.TypeOf(types.Int)},
{uint8(1), reflect.TypeOf(types.Int)},
{uint16(1), reflect.TypeOf(types.Int)},
{uint32(1), reflect.TypeOf(types.Int)},
{uint64(1), reflect.TypeOf(types.Int)},
{int(1), types.Int},
{int8(1), types.Int},
{int16(1), types.Int},
{int32(1), types.Int},
{int64(1), types.Int},
{uint(1), types.Int},
{uint8(1), types.Int},
{uint16(1), types.Int},
{uint32(1), types.Int},
{uint64(1), types.Int},
// Primitive Float types.
{float32(1.0), reflect.TypeOf(types.Float)},
{float64(1.0), reflect.TypeOf(types.Float)},
{float32(1.0), types.Float},
{float64(1.0), types.Float},
// Decimal type.
{apd.New(55, 1), reflect.TypeOf(types.Decimal)},
{apd.New(55, 1), types.Decimal},
// String type.
{"test", reflect.TypeOf(types.String)},
{"test", types.String},
// Bytes type.
{[]byte("abc"), reflect.TypeOf(types.Bytes)},
{[]byte("abc"), types.Bytes},
// Interval and timestamp.
{time.Duration(1), reflect.TypeOf(types.Interval)},
{timeutil.Now(), reflect.TypeOf(types.Timestamp)},
{time.Duration(1), types.Interval},
{timeutil.Now(), types.Timestamp},
// Primitive type aliases.
{roachpb.NodeID(1), reflect.TypeOf(types.Int)},
{sqlbase.ID(1), reflect.TypeOf(types.Int)},
{floatAlias(1), reflect.TypeOf(types.Float)},
{boolAlias(true), reflect.TypeOf(types.Bool)},
{stringAlias("string"), reflect.TypeOf(types.String)},
{roachpb.NodeID(1), types.Int},
{sqlbase.ID(1), types.Int},
{floatAlias(1), types.Float},
{boolAlias(true), types.Bool},
{stringAlias("string"), types.String},
// Byte slice aliases.
{roachpb.Key("key"), reflect.TypeOf(types.Bytes)},
{roachpb.RKey("key"), reflect.TypeOf(types.Bytes)},
{roachpb.Key("key"), types.Bytes},
{roachpb.RKey("key"), types.Bytes},
// Bit array.
{bitarray.MakeBitArrayFromInt64(8, 58, 7), reflect.TypeOf(types.VarBit)},
{bitarray.MakeBitArrayFromInt64(8, 58, 7), types.VarBit},
}
for i, tcase := range testCases {
......@@ -241,7 +242,7 @@ func TestGolangQueryArgs(t *testing.T) {
t.Fatalf("expected 1 datum, got: %d", len(datums))
}
d := datums[0]
if a, e := reflect.TypeOf(d.ResolvedType()), tcase.expectedType; a != e {
if a, e := d.ResolvedType(), tcase.expectedType; !a.Equal(e) {
t.Errorf("case %d failed: expected type %s, got %s", i, e.String(), a.String())
}
}
......
......@@ -192,8 +192,7 @@ func (ltc *LocalTestCluster) Start(t testing.TB, baseCtx *base.Config, initFacto
keys.SystemSQLCodec, cfg.DefaultZoneConfig, cfg.DefaultSystemZoneConfig,
)
var tableSplits []roachpb.RKey
bootstrapVersion := clusterversion.TestingClusterVersion
initialValues, tableSplits = schema.GetInitialValues(bootstrapVersion)
initialValues, tableSplits = schema.GetInitialValues()
splits = append(config.StaticSplits(), tableSplits...)
sort.Slice(splits, func(i, j int) bool {
return splits[i].Less(splits[j])
......