Skip to content

Commit

Permalink
sqlbase: add interesting datums for all scalar types
Browse files Browse the repository at this point in the history
This PR extends randInterestingDatums to include at least
one interesting datum for all scalar types to ensure that
edge cases don't break things. Additionally, this PR adds
a panic to randInterestingDatums if an interesting datum
for a type could not be found, so that we continue to have
coverage for all of our types.

Part of work for cockroachdb#44322.

Release note: None
  • Loading branch information
rohany committed Jan 28, 2020
1 parent 20908ab commit 2d36a35
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 23 deletions.
38 changes: 19 additions & 19 deletions pkg/sql/sem/tree/datum.go
Original file line number Diff line number Diff line change
Expand Up @@ -1474,26 +1474,26 @@ func (d *DUuid) Next(_ *EvalContext) (Datum, bool) {

// IsMax implements the Datum interface.
func (d *DUuid) IsMax(_ *EvalContext) bool {
return d.equal(dMaxUUID)
return d.equal(DMaxUUID)
}

// IsMin implements the Datum interface.
func (d *DUuid) IsMin(_ *EvalContext) bool {
return d.equal(dMinUUID)
return d.equal(DMinUUID)
}

var dMinUUID = NewDUuid(DUuid{uuid.UUID{}})
var dMaxUUID = NewDUuid(DUuid{uuid.UUID{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
var DMinUUID = NewDUuid(DUuid{uuid.UUID{}})
var DMaxUUID = NewDUuid(DUuid{uuid.UUID{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}})

// Min implements the Datum interface.
func (*DUuid) Min(_ *EvalContext) (Datum, bool) {
return dMinUUID, true
return DMinUUID, true
}

// Max implements the Datum interface.
func (*DUuid) Max(_ *EvalContext) (Datum, bool) {
return dMaxUUID, true
return DMaxUUID, true
}

// AmbiguousFormat implements the Datum interface.
Expand Down Expand Up @@ -1619,12 +1619,12 @@ func (d *DIPAddr) Next(_ *EvalContext) (Datum, bool) {

// IsMax implements the Datum interface.
func (d *DIPAddr) IsMax(_ *EvalContext) bool {
return d.equal(dMaxIPAddr)
return d.equal(DMaxIPAddr)
}

// IsMin implements the Datum interface.
func (d *DIPAddr) IsMin(_ *EvalContext) bool {
return d.equal(dMinIPAddr)
return d.equal(DMinIPAddr)
}

// dIPv4 and dIPv6 min and maxes use ParseIP because the actual byte constant is
Expand All @@ -1640,18 +1640,18 @@ var dIPv6max = ipaddr.Addr(uint128.FromBytes([]byte(net.ParseIP("ffff:ffff:ffff:
var dMaxIPv4Addr = NewDIPAddr(DIPAddr{ipaddr.IPAddr{Family: ipaddr.IPv4family, Addr: dIPv4max, Mask: 32}})
var dMinIPv6Addr = NewDIPAddr(DIPAddr{ipaddr.IPAddr{Family: ipaddr.IPv6family, Addr: dIPv6min, Mask: 0}})

// dMinIPAddr and dMaxIPAddr are used as the DIPAddr global min and max.
var dMinIPAddr = NewDIPAddr(DIPAddr{ipaddr.IPAddr{Family: ipaddr.IPv4family, Addr: dIPv4min, Mask: 0}})
var dMaxIPAddr = NewDIPAddr(DIPAddr{ipaddr.IPAddr{Family: ipaddr.IPv6family, Addr: dIPv6max, Mask: 128}})
// DMinIPAddr and DMaxIPAddr are used as the DIPAddr global min and max.
var DMinIPAddr = NewDIPAddr(DIPAddr{ipaddr.IPAddr{Family: ipaddr.IPv4family, Addr: dIPv4min, Mask: 0}})
var DMaxIPAddr = NewDIPAddr(DIPAddr{ipaddr.IPAddr{Family: ipaddr.IPv6family, Addr: dIPv6max, Mask: 128}})

// Min implements the Datum interface.
func (*DIPAddr) Min(_ *EvalContext) (Datum, bool) {
return dMinIPAddr, true
return DMinIPAddr, true
}

// Max implements the Datum interface.
func (*DIPAddr) Max(_ *EvalContext) (Datum, bool) {
return dMaxIPAddr, true
return DMaxIPAddr, true
}

// AmbiguousFormat implements the Datum interface.
Expand Down Expand Up @@ -1973,8 +1973,8 @@ type DTimeTZ struct {
}

var (
dMinTimeTZ = NewDTimeTZFromOffset(timeofday.Min, timetz.MinTimeTZOffsetSecs)
dMaxTimeTZ = NewDTimeTZFromOffset(timeofday.Time2400, timetz.MaxTimeTZOffsetSecs)
DMinTimeTZ = NewDTimeTZFromOffset(timeofday.Min, timetz.MinTimeTZOffsetSecs)
DMaxTimeTZ = NewDTimeTZFromOffset(timeofday.Time2400, timetz.MaxTimeTZOffsetSecs)
)

// NewDTimeTZ creates a DTimeTZ from a timetz.TimeTZ.
Expand Down Expand Up @@ -2040,17 +2040,17 @@ func (d *DTimeTZ) Next(ctx *EvalContext) (Datum, bool) {

// IsMax implements the Datum interface.
func (d *DTimeTZ) IsMax(_ *EvalContext) bool {
return d.TimeOfDay == dMaxTimeTZ.TimeOfDay && d.OffsetSecs == timetz.MaxTimeTZOffsetSecs
return d.TimeOfDay == DMaxTimeTZ.TimeOfDay && d.OffsetSecs == timetz.MaxTimeTZOffsetSecs
}

// IsMin implements the Datum interface.
func (d *DTimeTZ) IsMin(_ *EvalContext) bool {
return d.TimeOfDay == dMinTimeTZ.TimeOfDay && d.OffsetSecs == timetz.MinTimeTZOffsetSecs
return d.TimeOfDay == DMinTimeTZ.TimeOfDay && d.OffsetSecs == timetz.MinTimeTZOffsetSecs
}

// Max implements the Datum interface.
func (d *DTimeTZ) Max(_ *EvalContext) (Datum, bool) {
return dMaxTimeTZ, true
return DMaxTimeTZ, true
}

// Round returns a new DTimeTZ to the specified precision.
Expand All @@ -2060,7 +2060,7 @@ func (d *DTimeTZ) Round(precision time.Duration) *DTimeTZ {

// Min implements the Datum interface.
func (d *DTimeTZ) Min(_ *EvalContext) (Datum, bool) {
return dMinTimeTZ, true
return DMinTimeTZ, true
}

// AmbiguousFormat implements the Datum interface.
Expand Down
57 changes: 53 additions & 4 deletions pkg/sql/sqlbase/testutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,10 @@ var (
// randInterestingDatums is a collection of interesting datums that can be
// used for random testing.
randInterestingDatums = map[types.Family][]tree.Datum{
types.BoolFamily: {
tree.DBoolTrue,
tree.DBoolFalse,
},
types.IntFamily: {
tree.NewDInt(tree.DInt(0)),
tree.NewDInt(tree.DInt(-1)),
Expand Down Expand Up @@ -419,6 +423,10 @@ var (
tree.MakeDTime(timeofday.Min),
tree.MakeDTime(timeofday.Max),
},
types.TimeTZFamily: {
tree.DMinTimeTZ,
tree.DMaxTimeTZ,
},
types.TimestampFamily: func() []tree.Datum {
res := make([]tree.Datum, len(randTimestampSpecials))
for i, t := range randTimestampSpecials {
Expand Down Expand Up @@ -458,6 +466,46 @@ var (
tree.NewDBytes("\u2603"), // unicode snowman
tree.NewDBytes("\xFF"), // invalid utf-8 sequence, but a valid bytes
},
types.OidFamily: {
tree.NewDOid(0),
},
types.UuidFamily: {
tree.DMinUUID,
tree.DMaxUUID,
},
types.INetFamily: {
tree.DMinIPAddr,
tree.DMaxIPAddr,
},
types.JsonFamily: func() []tree.Datum {
var res []tree.Datum
for _, s := range []string{
`{}`,
`1`,
`{"test": "json"}`,
} {
d, err := tree.ParseDJSON(s)
if err != nil {
panic(err)
}
res = append(res, d)
}
return res
}(),
types.BitFamily: func() []tree.Datum {
var res []tree.Datum
for _, i := range []int64{
0,
1<<63 - 1,
} {
d, err := tree.NewDBitArrayFromInt(i, 64)
if err != nil {
panic(err)
}
res = append(res, d)
}
return res
}(),
}
randTimestampSpecials = []time.Time{
{},
Expand Down Expand Up @@ -523,13 +571,14 @@ func init() {
}

// randInterestingDatum returns an interesting Datum of type typ. If there are
// no such Datums, it returns nil. Note that it pays attention to the width of
// no such Datums, it panics. Note that it pays attention to the width of
// the requested type for Int and Float type families.
func randInterestingDatum(rng *rand.Rand, typ *types.T) tree.Datum {
specials := randInterestingDatums[typ.Family()]
if len(specials) == 0 {
return nil
specials, ok := randInterestingDatums[typ.Family()]
if !ok || len(specials) == 0 {
panic(fmt.Sprintf("no interesting datum for type %s found", typ.String()))
}

special := specials[rng.Intn(len(specials))]
switch typ.Family() {
case types.IntFamily:
Expand Down

0 comments on commit 2d36a35

Please sign in to comment.