Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix timestamp serialization into time.Time, makes zero data <-> zeroTimestamp #375

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions cassandra_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2075,7 +2075,9 @@ func TestNilInQuery(t *testing.T) {

// Don't initialize time.Time bind variable if cassandra timestamp column is empty
func TestEmptyTimestamp(t *testing.T) {
zeroTimestamp := time.UnixMilli(0).UTC()
session := createSession(t)

defer session.Close()

if err := createTable(session, "CREATE TABLE gocql_test.test_empty_timestamp (id int, time timestamp, num int, PRIMARY KEY (id))"); err != nil {
Expand All @@ -2092,8 +2094,8 @@ func TestEmptyTimestamp(t *testing.T) {
t.Fatalf("failed to select with err: %v", err)
}

if !timeVal.IsZero() {
t.Errorf("time.Time bind variable should still be empty (was %s)", timeVal)
if !timeVal.Equal(zeroTimestamp) {
t.Errorf("time.Time bind variable should be zero (was %s)", timeVal)
}
}

Expand Down
13 changes: 6 additions & 7 deletions serialization/timestamp/marshal_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import (
"time"
)

const (
maxValInt64 int64 = 86399999999999
minValInt64 int64 = 0
maxValDur time.Duration = 86399999999999
minValDur time.Duration = 0
var (
maxTimestamp = time.Date(292278994, 8, 17, 7, 12, 55, 807*1000000, time.UTC)
zeroTimestamp = time.Date(1970, 1, 1, 0, 0, 0, 0, time.UTC)
minTimestamp = time.Date(-292275055, 5, 16, 16, 47, 4, 192*1000000, time.UTC)
)

func EncInt64(v int64) ([]byte, error) {
Expand All @@ -25,8 +24,8 @@ func EncInt64R(v *int64) ([]byte, error) {
}

func EncTime(v time.Time) ([]byte, error) {
if v.IsZero() {
return make([]byte, 0), nil
if v.After(maxTimestamp) || v.Before(minTimestamp) {
return nil, fmt.Errorf("failed to marshal timestamp: the (%T)(%s) value should be in the range from -292275055-05-16T16:47:04.192Z to 292278994-08-17T07:12:55.807", v, v.Format(time.RFC3339Nano))
}
ms := v.Unix()*1e3 + int64(v.Nanosecond())/1e6
return []byte{byte(ms >> 56), byte(ms >> 48), byte(ms >> 40), byte(ms >> 32), byte(ms >> 24), byte(ms >> 16), byte(ms >> 8), byte(ms)}, nil
Expand Down
5 changes: 3 additions & 2 deletions serialization/timestamp/unmarshal_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func DecTime(p []byte, v *time.Time) error {
}
switch len(p) {
case 0:
*v = time.Time{}
*v = zeroTimestamp
case 8:
*v = decTime(p)
default:
Expand All @@ -73,7 +73,8 @@ func DecTimeR(p []byte, v **time.Time) error {
if p == nil {
*v = nil
} else {
*v = new(time.Time)
val := zeroTimestamp
*v = &val
}
case 8:
val := decTime(p)
Expand Down
24 changes: 24 additions & 0 deletions tests/serialization/marshal_16_timestamp_corrupt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,33 @@ func TestMarshalTimestampCorrupt(t *testing.T) {
}

for _, tSuite := range testSuites {
marshal := tSuite.marshal
unmarshal := tSuite.unmarshal

t.Run(tSuite.name, func(t *testing.T) {
serialization.NegativeMarshalSet{
Values: mod.Values{
time.Date(292278994, 8, 17, 7, 12, 55, 808*1000000, time.UTC),
time.Date(292278994, 8, 17, 7, 12, 56, 807*1000000, time.UTC),
time.Date(292278994, 8, 17, 7, 13, 55, 807*1000000, time.UTC),
time.Date(292278994, 8, 17, 8, 12, 55, 807*1000000, time.UTC),
time.Date(292278994, 8, 18, 7, 12, 55, 807*1000000, time.UTC),
time.Date(292278994, 9, 17, 7, 12, 55, 807*1000000, time.UTC),
time.Date(292278995, 8, 17, 7, 12, 55, 807*1000000, time.UTC),
}.AddVariants(mod.All...),
}.Run("big_vals", t, marshal)

serialization.NegativeMarshalSet{
Values: mod.Values{
time.Date(-292275055, 5, 16, 16, 47, 4, 191*1000000, time.UTC),
time.Date(-292275055, 5, 16, 16, 47, 3, 192*1000000, time.UTC),
time.Date(-292275055, 5, 16, 16, 46, 4, 192*1000000, time.UTC),
time.Date(-292275055, 5, 16, 15, 47, 4, 192*1000000, time.UTC),
time.Date(-292275055, 5, 15, 16, 47, 4, 192*1000000, time.UTC),
time.Date(-292275055, 4, 16, 16, 47, 4, 192*1000000, time.UTC),
time.Date(-292275056, 5, 16, 16, 47, 4, 192*1000000, time.UTC),
}.AddVariants(mod.All...),
}.Run("small_vals", t, marshal)

serialization.NegativeUnmarshalSet{
Data: []byte("\x7f\xff\xff\xff\xff\xff\xff\xff\xff"),
Expand Down
15 changes: 4 additions & 11 deletions tests/serialization/marshal_16_timestamp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,7 @@ func TestMarshalsTimestamp(t *testing.T) {
},
}

zeroTime := time.Unix(0, 0).UTC()

// The `time` package have a speciality - values `time.Time{}` and `time.Unix(0,0).UTC()` are different
// The old unmarshal function unmarshalls `nil` and `zero` data into `time.Time{}`, but data with zeros into `time.Unix(0,0).UTC()`
brokenTime := serialization.GetTypes(time.Time{}, &time.Time{})
_ = brokenTime
zeroTimestamp := time.Unix(0, 0).UTC()

for _, tSuite := range testSuites {
marshal := tSuite.marshal
Expand All @@ -62,23 +57,21 @@ func TestMarshalsTimestamp(t *testing.T) {
serialization.PositiveSet{
Data: nil,
Values: mod.Values{
int64(0), zeroTime,
int64(0), zeroTimestamp,
}.AddVariants(mod.CustomType),
BrokenUnmarshalTypes: brokenTime,
}.Run("[nil]unmarshal", t, nil, unmarshal)

serialization.PositiveSet{
Data: make([]byte, 0),
Values: mod.Values{
int64(0), zeroTime,
int64(0), zeroTimestamp,
}.AddVariants(mod.All...),
BrokenUnmarshalTypes: brokenTime,
}.Run("[]unmarshal", t, nil, unmarshal)

serialization.PositiveSet{
Data: []byte("\x00\x00\x00\x00\x00\x00\x00\x00"),
Values: mod.Values{
int64(0), zeroTime,
int64(0), zeroTimestamp,
}.AddVariants(mod.All...),
}.Run("zeros", t, marshal, unmarshal)

Expand Down
Loading