Skip to content

Commit e00ecff

Browse files
committed
logicalTypes: fix alternative encoding for decimal types
The alternative is an explicit codec decimal type, additionally, this only worked for a small subset of values that were both valid native and valid binary encoding. Since we want to stay in the native value space, we just need to convert from native primative to native logical type. In order to do this we just do an encode/decode step for decimal logical types.
1 parent e10381a commit e00ecff

File tree

2 files changed

+19
-12
lines changed

2 files changed

+19
-12
lines changed

record.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -117,20 +117,23 @@ func makeRecordCodec(st map[string]*Codec, enclosingNamespace string, schemaMap
117117
// TODO: change to schemaCanonical below
118118
defaultValue = Union(fieldCodec.schemaOriginal, defaultValue)
119119
default:
120-
debug("fieldName: %q; type: %q; defaultValue: %T(%#v)\n", fieldName, c.typeName, defaultValue, defaultValue)
121-
122120
// Support defaults for logical types
123-
if logicalType, ok := fieldSchemaMap["logicalType"]; ok {
124-
if logicalType == "decimal" {
125-
v, ok := defaultValue.(string)
126-
if !ok {
127-
return nil, fmt.Errorf("Record %q field %q: default value ought to have a string type got: %T", c.typeName, fieldName, defaultValue)
128-
}
129-
defaultValue, _, err = fieldCodec.nativeFromBinary([]byte(v))
130-
if err != nil {
131-
return nil, fmt.Errorf("Record %q field %q: default value ought to decode from textual: %w", c.typeName, fieldName, err)
132-
}
121+
if fieldSchemaMap["logicalType"] == "decimal" || typeNameShort == "decimal" {
122+
v, ok := defaultValue.(string)
123+
if !ok {
124+
return nil, fmt.Errorf("Record %q field %q: default value ought to have a string type got: %T", c.typeName, fieldName, defaultValue)
125+
}
126+
// the default is a native byte array, we need to encode it first, then we can decode it into a *big.Rat
127+
encoded, err := bytesBinaryFromNative(nil, v)
128+
if err != nil {
129+
return nil, fmt.Errorf("Record %q field %q: default value ought to be encodable from native binary: %w", c.typeName, fieldName, err)
130+
}
131+
defaultValue, _, err = fieldCodec.nativeFromBinary(encoded)
132+
if err != nil {
133+
return nil, fmt.Errorf("Record %q field %q: default value ought to decode from textual: %w", c.typeName, fieldName, err)
133134
}
135+
} else {
136+
debug("fieldName: %q; type: %q; defaultValue: %T(%#v)\n", fieldName, c.typeName, defaultValue, defaultValue)
134137
}
135138
}
136139

record_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -617,6 +617,10 @@ func TestRecordFieldFixedDefaultValue(t *testing.T) {
617617
testSchemaValid(t, `{"type": "record", "name": "r1", "fields":[{"name": "f1", "type": {"type": "fixed", "name": "someFixed", "size": 1}, "default": "\u0000"}]}`)
618618
}
619619

620+
func TestRecordFieldDecimalDefaultValue(t *testing.T) {
621+
testSchemaValid(t, `{"type": "record", "name": "r1", "fields":[{"name": "f1", "type": {"type": "bytes", "scale": 2, "precision":10, "logicalType":"deicmal"}, "default": "d"}]}`)
622+
}
623+
620624
func TestRecordFieldDefaultValueTypes(t *testing.T) {
621625
t.Run("success", func(t *testing.T) {
622626
codec, err := NewCodec(`{"type": "record", "name": "r1", "fields":[{"name": "someBoolean", "type": "boolean", "default": true},{"name": "someBytes", "type": "bytes", "default": "0"},{"name": "someDouble", "type": "double", "default": 0},{"name": "someFloat", "type": "float", "default": 0},{"name": "someInt", "type": "int", "default": 0},{"name": "someLong", "type": "long", "default": 0},{"name": "someString", "type": "string", "default": "0"}, {"name":"someTimestamp", "type":"long", "logicalType":"timestamp-millis","default":0}, {"name": "someDecimal", "type": "bytes", "logicalType": "decimal", "precision": 4, "scale": 2, "default":"\u0000"}]}`)

0 commit comments

Comments
 (0)