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

Marshal, unmarshal. Problems with zero and null data and values. #250

Open
illia-li opened this issue Aug 28, 2024 · 0 comments
Open

Marshal, unmarshal. Problems with zero and null data and values. #250

illia-li opened this issue Aug 28, 2024 · 0 comments
Assignees
Labels

Comments

@illia-li
Copy link

Explanation according to the cassandra protocol:
row is composed of value_1...value_n where n is columns_count.
value is a bytes representing the value.
bytes - a int n, followed by n bytes if n >= 0.
If n = 0, no byte should follow and the value represented is zero.
If n < 0, no byte should follow and the value represented is null.

Explanation of the current situation in gocql:
Marshalling: for almost all types:
The zero value is marshaled into a slice with a length equal to the length of the type filled with zeros.
example: zero values of TypeInt marshaled into []byte{0,0,0,0}.
The null values marshaled correctly, with some assumptions.
Unmarshalling: for almost all types, the zero and null data is unmarshaled into zero values.

Explanation of the current situation in cassanda:
The following behavioral features were found:

  1. On INSERT zero data into columns with types tinyint, smallint, date, time, duration - db returns error.
  2. On SELECT zero values from columns with types tinyint, smallint, date, time, duration - db returns data filled with zeros (with not zero len) .
  3. On SELECT zero values from columns with types list, set, map, ascii, blob, text, timeuuid, uuid, varchar- db returns null data (with len -1) .
    Types udt and tuple need to check.

Explanation of the current situation in scylla:
The following behavioral features were found:

  1. On INSERT zero data into columns with type duration - db returns error.
  2. On SELECT zero values from columns with type duration - db returns data filled with zeros (with not zero len) .
  3. On SELECT zero values from columns with types list, set, map, ascii, blob, text, timeuuid, uuid, varchar- db returns null data (with len -1) .
    Types udt and tuple need to check.

Test code for Marshal zero values:

func TestMarshalZeroValues(t *testing.T) {
	type tCase struct {
		Type  TypeInfo
		Value interface{}
	}

	tCases := []tCase{
		{Type: NativeType{proto: 2, typ: TypeBoolean}, Value: false},
		{Type: NativeType{proto: 2, typ: TypeTinyInt}, Value: int(0)},
		{Type: NativeType{proto: 2, typ: TypeSmallInt}, Value: int(0)},
		{Type: NativeType{proto: 2, typ: TypeInt}, Value: int(0)},
		{Type: NativeType{proto: 2, typ: TypeBigInt}, Value: int(0)},
		{Type: NativeType{proto: 2, typ: TypeVarint}, Value: int(0)},
		{Type: NativeType{proto: 2, typ: TypeFloat}, Value: float32(0)},
		{Type: NativeType{proto: 2, typ: TypeDouble}, Value: float64(0)},
		{Type: NativeType{proto: 2, typ: TypeDecimal}, Value: inf.Dec{}},
		{Type: NativeType{proto: 2, typ: TypeInet}, Value: make(net.IP, 0)},
		{Type: NativeType{proto: 2, typ: TypeUUID}, Value: UUID{}},
		{Type: NativeType{proto: 2, typ: TypeTimeUUID}, Value: UUID{}},
		{Type: NativeType{proto: 2, typ: TypeTime}, Value: int64(0)},
		{Type: NativeType{proto: 2, typ: TypeDate}, Value: int64(0)},
		{Type: NativeType{proto: 2, typ: TypeDuration}, Value: time.Duration(0)},
		{Type: NativeType{proto: 2, typ: TypeTimestamp}, Value: int64(0)},
		{Type: NativeType{proto: 2, typ: TypeText}, Value: ""},
		{Type: NativeType{proto: 2, typ: TypeAscii}, Value: ""},
		{Type: NativeType{proto: 2, typ: TypeBlob}, Value: ""},
		{Type: NativeType{proto: 2, typ: TypeVarchar}, Value: ""},

		{
			Type: CollectionType{
				NativeType: NativeType{proto: 2, typ: TypeList},
				Elem:       NativeType{proto: 2, typ: TypeSmallInt},
			},
			Value: make([]byte, 0)},
		{
			Type: CollectionType{
				NativeType: NativeType{proto: 2, typ: TypeSet},
				Elem:       NativeType{proto: 2, typ: TypeSmallInt},
			},
			Value: make([]byte, 0)},
		{
			Type: CollectionType{
				NativeType: NativeType{proto: 2, typ: TypeMap},
				Key:        NativeType{proto: 2, typ: TypeSmallInt},
				Elem:       NativeType{proto: 2, typ: TypeSmallInt},
			},
			Value: make(map[int]int)},
		{
			Type: UDTTypeInfo{
				NativeType: NativeType{proto: 3, typ: TypeUDT},
				KeySpace:   "",
				Name:       "test_udt",
				Elements: []UDTField{
					{Name: "1", Type: NativeType{proto: 2, typ: TypeSmallInt}},
				},
			},
			Value: map[string]interface{}{},
		},
		{
			Type: TupleTypeInfo{
				NativeType: NativeType{proto: 3, typ: TypeTuple},
				Elems: []TypeInfo{
					NativeType{proto: 2, typ: TypeSmallInt},
				},
			},
			Value: []interface{}{},
		},
	}

	errs := make([]string, 0)
	mData := make([]string, 0)
	for _, c := range tCases {
		data, err := Marshal(c.Type, c.Value)
		if err != nil {
			errs = append(errs, fmt.Sprintf("type:<%s>\t-\terror: %s", c.Type.Type(), err.Error()))
		} else if len(data) != 0 {
			mData = append(mData, fmt.Sprintf("type:<%s>\t-\tdata: <%#v>", c.Type.Type(), data))
		}
	}

	if len(errs) != 0 {
		t.Errorf("\nMarshaling of %d cases, have %d errors:\n%s", len(tCases), len(errs), strings.Join(errs, "\n"))
	}
	if len(mData) != 0 {
		t.Errorf("\nMarshaling of %d cases, have %d a non zero data:\n%s", len(tCases), len(mData), strings.Join(mData, "\n"))
	}
}

Output:

=== RUN   TestMarshalZeroValues
    marshal_0_all_test.go:226: 
        Marshaling of 25 cases, have 1 errors:
        type:<tuple>	-	error: cannont marshal tuple: wrong number of elements
    marshal_0_all_test.go:229: 
        Marshaling of 25 cases, have 19 a non zero data:
        type:<boolean>	-	data: <[]byte{0x0}>
        type:<tinyint>	-	data: <[]byte{0x0}>
        type:<smallint>	-	data: <[]byte{0x0, 0x0}>
        type:<int>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0}>
        type:<bigint>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}>
        type:<varint>	-	data: <[]byte{0x0}>
        type:<float>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0}>
        type:<double>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}>
        type:<decimal>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0, 0x0}>
        type:<uuid>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}>
        type:<timeuuid>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}>
        type:<time>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}>
        type:<date>	-	data: <[]byte{0x80, 0x0, 0x0, 0x0}>
        type:<duration>	-	data: <[]byte{0x0, 0x0, 0x0}>
        type:<timestamp>	-	data: <[]byte{0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}>
        type:<list>	-	data: <[]byte{0x0, 0x0}>
        type:<set>	-	data: <[]byte{0x0, 0x0}>
        type:<map>	-	data: <[]byte{0x0, 0x0}>
        type:<unknown_type_48>	-	data: <[]byte{0xff, 0xff, 0xff, 0xff}>
--- FAIL: TestMarshalZeroValues (0.00s)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants