From 2e7cabcaa96000c60cae51f32297f67888d741aa Mon Sep 17 00:00:00 2001 From: "mykyta.oleksiienko" Date: Thu, 19 Sep 2024 15:14:34 +0300 Subject: [PATCH] CASSGO-2 Marshal big int returns variable length slice. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The marshalBigInt return 8 bytes slice in all cases except for big.Int, which returns a variable length slice, but should be 8 bytes slice as well. patch by Mykyta Oleksiienko; reviewed by João Reis for CASSGO-2 --- CHANGELOG.md | 2 ++ marshal.go | 9 +++++++-- marshal_test.go | 30 +++++++++++++++++++++++++++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 67c88a141..12211342d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Retry policy now takes into account query idempotency (CASSGO-27) - Don't return error to caller with RetryType Ignore (CASSGO-28) +- The marshalBigInt return 8 bytes slice in all cases except for big.Int, + which returns a variable length slice, but should be 8 bytes slice as well (CASSGO-2) ## [1.7.0] - 2024-09-23 diff --git a/marshal.go b/marshal.go index 4d0adb923..2708c54ea 100644 --- a/marshal.go +++ b/marshal.go @@ -77,7 +77,7 @@ type Unmarshaler interface { // tinyint, smallint, int | integer types | // tinyint, smallint, int | string | formatted as base 10 number // bigint, counter | integer types | -// bigint, counter | big.Int | +// bigint, counter | big.Int | according to cassandra bigint specification the big.Int value limited to int64 size(an eight-byte two's complement integer.) // bigint, counter | string | formatted as base 10 number // float | float32 | // double | float64 | @@ -671,7 +671,10 @@ func marshalBigInt(info TypeInfo, value interface{}) ([]byte, error) { case uint8: return encBigInt(int64(v)), nil case big.Int: - return encBigInt2C(&v), nil + if !v.IsInt64() { + return nil, marshalErrorf("marshal bigint: value %v out of range", &v) + } + return encBigInt(v.Int64()), nil case string: i, err := strconv.ParseInt(value.(string), 10, 64) if err != nil { @@ -773,6 +776,8 @@ func marshalVarint(info TypeInfo, value interface{}) ([]byte, error) { retBytes = make([]byte, 8) binary.BigEndian.PutUint64(retBytes, v) } + case big.Int: + retBytes = encBigInt2C(&v) default: retBytes, err = marshalBigInt(info, value) } diff --git a/marshal_test.go b/marshal_test.go index 6c139e6bc..d11015500 100644 --- a/marshal_test.go +++ b/marshal_test.go @@ -39,6 +39,8 @@ import ( "time" "gopkg.in/inf.v0" + + "github.com/stretchr/testify/require" ) type AliasInt int @@ -1349,7 +1351,7 @@ func TestMarshal_Encode(t *testing.T) { } } else { if _, err := Marshal(test.Info, test.Value); err != test.MarshalError { - t.Errorf("unmarshalTest[%d] (%v=>%t): %#v returned error %#v, want %#v.", i, test.Info, test.Value, test.Value, err, test.MarshalError) + t.Errorf("marshalTest[%d] (%v=>%t): %#v returned error %#v, want %#v.", i, test.Info, test.Value, test.Value, err, test.MarshalError) } } } @@ -1535,6 +1537,32 @@ func TestMarshalVarint(t *testing.T) { } } +func TestMarshalBigInt(t *testing.T) { + var testStruct = []struct { + Info TypeInfo + Value interface{} + MarshalError error + }{ + { + NativeType{proto: 2, typ: TypeBigInt}, + "-78635384813432117863538481343211", + MarshalError("can not marshal string to bigint: strconv.ParseInt: parsing \"-78635384813432117863538481343211\": value out of range"), + }, + { + NativeType{proto: 2, typ: TypeBigInt}, + "922337203685477692259749625974294", + MarshalError("can not marshal string to bigint: strconv.ParseInt: parsing \"922337203685477692259749625974294\": value out of range"), + }, + } + + t.Run("testMarshalBigInt", func(t *testing.T) { + for _, tc := range testStruct { + _, err := Marshal(tc.Info, tc.Value) + require.Equal(t, tc.MarshalError, err) + } + }) +} + func equalStringPointerSlice(leftList, rightList []*string) bool { if len(leftList) != len(rightList) { return false