Skip to content

Commit a821d28

Browse files
committed
marshal: UDT, when values are a map force presence of all elements
User shall send the values in the order specified by the UDT. > A UDT value is composed of successive [bytes] values, one for each field of the UDT > value (in the order defined by the type). A UDT value will generally have one value > for each field of the type it represents, but it is allowed to have less values than > the type has fields. Skipping a value causes DATA CORRUPTION by assigning next field value to the current value and clearing the tailing values.
1 parent e898470 commit a821d28

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

marshal.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -2177,7 +2177,7 @@ func marshalUDT(info TypeInfo, value interface{}) ([]byte, error) {
21772177
for _, e := range udt.Elements {
21782178
val, ok := v[e.Name]
21792179
if !ok {
2180-
continue
2180+
return nil, marshalErrorf("marshal missing map key %q", e.Name)
21812181
}
21822182

21832183
data, err := Marshal(e.Type, val)

marshal_test.go

+37-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
//+build all unit
1+
//go:build all || unit
2+
// +build all unit
23

34
package gocql
45

@@ -1939,6 +1940,41 @@ func TestUnmarshalTuple(t *testing.T) {
19391940
})
19401941
}
19411942

1943+
func TestMarshalUDTMap(t *testing.T) {
1944+
typeInfo := UDTTypeInfo{NativeType{proto: 3, typ: TypeUDT}, "", "xyz", []UDTField{
1945+
{Name: "x", Type: NativeType{proto: 3, typ: TypeInt}},
1946+
{Name: "y", Type: NativeType{proto: 3, typ: TypeInt}},
1947+
{Name: "z", Type: NativeType{proto: 3, typ: TypeInt}},
1948+
}}
1949+
1950+
t.Run("partially bound", func(t *testing.T) {
1951+
value := map[string]interface{}{
1952+
"y": 2,
1953+
"z": 3,
1954+
}
1955+
me := MarshalError(`marshal missing map key "x"`)
1956+
if _, err := Marshal(typeInfo, value); err != me {
1957+
t.Errorf("got error %#v, want %#v", err, me)
1958+
}
1959+
})
1960+
t.Run("fully bound", func(t *testing.T) {
1961+
value := map[string]interface{}{
1962+
"x": 1,
1963+
"y": 2,
1964+
"z": 3,
1965+
}
1966+
expected := []byte("\x00\x00\x00\x04\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x04\x00\x00\x00\x03")
1967+
1968+
data, err := Marshal(typeInfo, value)
1969+
if err != nil {
1970+
t.Errorf("got error %#v", err)
1971+
}
1972+
if !bytes.Equal(data, expected) {
1973+
t.Errorf("got error %x", data)
1974+
}
1975+
})
1976+
}
1977+
19421978
func TestMarshalNil(t *testing.T) {
19431979
types := []Type{
19441980
TypeAscii,

0 commit comments

Comments
 (0)