Browse Source

Fix bug fetching out unset timestamp values.

If your row exists but has an empty timestamp column, your time.Time
bind variable was being initialized to epoch time 0. Now it returns
early and does not modify the bind variable. I considered having it
instead set the bind variable to the go zero time.Time value, but
since that is techincally a legitimate time value as well it still
doesn't solve the semipredicate problem.

I tweaked the timestamp marshal code to do "val.UnixNano() / 1000000"
instead of "val.UnixNano() / time.Millisecond" because it doesn't make
sense to do operations directly between integers and time.Duration values.
The latter only works because the base unit for time.Duration happens to
be nanoseconds.
Muir Manders 11 years ago
parent
commit
803daed9cc
2 changed files with 29 additions and 1 deletions
  1. 25 0
      cassandra_test.go
  2. 4 1
      marshal.go

+ 25 - 0
cassandra_test.go

@@ -19,6 +19,7 @@ import (
 	"testing"
 	"testing"
 	"time"
 	"time"
 	"unicode"
 	"unicode"
+
 	"speter.net/go/exp/math/dec/inf"
 	"speter.net/go/exp/math/dec/inf"
 )
 )
 
 
@@ -1442,3 +1443,27 @@ func TestNilInQuery(t *testing.T) {
 		t.Fatalf("expected id to be 1, got %v", id)
 		t.Fatalf("expected id to be 1, got %v", id)
 	}
 	}
 }
 }
+
+// Don't initialize time.Time bind variable if cassandra timestamp column is empty
+func TestEmptyTimestamp(t *testing.T) {
+	session := createSession(t)
+	defer session.Close()
+
+	if err := createTable(session, "CREATE TABLE test_empty_timestamp (id int, time timestamp, num int, PRIMARY KEY (id))"); err != nil {
+		t.Fatalf("failed to create table with error '%v'", err)
+	}
+
+	if err := session.Query("INSERT INTO test_empty_timestamp (id, num) VALUES (?,?)", 1, 561).Exec(); err != nil {
+		t.Fatalf("failed to insert with err: %v", err)
+	}
+
+	var timeVal time.Time
+
+	if err := session.Query("SELECT time FROM test_empty_timestamp where id = ?", 1).Scan(&timeVal); err != nil {
+		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)
+	}
+}

+ 4 - 1
marshal.go

@@ -752,7 +752,7 @@ func marshalTimestamp(info *TypeInfo, value interface{}) ([]byte, error) {
 	case int64:
 	case int64:
 		return encBigInt(v), nil
 		return encBigInt(v), nil
 	case time.Time:
 	case time.Time:
-		x := v.In(time.UTC).UnixNano() / int64(time.Millisecond)
+		x := v.UnixNano() / int64(1000000)
 		return encBigInt(x), nil
 		return encBigInt(x), nil
 	}
 	}
 	rv := reflect.ValueOf(value)
 	rv := reflect.ValueOf(value)
@@ -773,6 +773,9 @@ func unmarshalTimestamp(info *TypeInfo, data []byte, value interface{}) error {
 		*v = decBigInt(data)
 		*v = decBigInt(data)
 		return nil
 		return nil
 	case *time.Time:
 	case *time.Time:
+		if len(data) == 0 {
+			return nil
+		}
 		x := decBigInt(data)
 		x := decBigInt(data)
 		sec := x / 1000
 		sec := x / 1000
 		nsec := (x - sec*1000) * 1000000
 		nsec := (x - sec*1000) * 1000000