Skip to content

Patch float with trailing zero for JSON and add useFloatWithTrailingZero flag #1038

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

Merged
merged 8 commits into from
Jun 7, 2025
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions replication/binlogsyncer.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ type BinlogSyncerConfig struct {
// Use decimal.Decimal structure for decimals.
UseDecimal bool

// FloatWithTrailingZero structure for floats.
UseFloatWithTrailingZero bool

// RecvBufferSize sets the size in bytes of the operating system's receive buffer associated with the connection.
RecvBufferSize int

Expand Down Expand Up @@ -197,6 +200,7 @@ func NewBinlogSyncer(cfg BinlogSyncerConfig) *BinlogSyncer {
b.parser.SetParseTime(b.cfg.ParseTime)
b.parser.SetTimestampStringLocation(b.cfg.TimestampStringLocation)
b.parser.SetUseDecimal(b.cfg.UseDecimal)
b.parser.SetUseFloatWithTrailingZero(b.cfg.UseFloatWithTrailingZero)
b.parser.SetVerifyChecksum(b.cfg.VerifyChecksum)
b.parser.SetRowsEventDecodeFunc(b.cfg.RowsEventDecodeFunc)
b.parser.SetTableMapOptionalMetaDecodeFunc(b.cfg.TableMapOptionalMetaDecodeFunc)
Expand Down
31 changes: 26 additions & 5 deletions replication/json_binary.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package replication
import (
"fmt"
"math"
"strconv"

"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/utils"
Expand Down Expand Up @@ -52,6 +53,8 @@ type (
JsonDiffOperation byte
)

type FloatWithTrailingZero float64

const (
// The JSON value in the given path is replaced with a new value.
//
Expand Down Expand Up @@ -96,6 +99,14 @@ func (jd *JsonDiff) String() string {
return fmt.Sprintf("json_diff(op:%s path:%s value:%s)", jd.Op, jd.Path, jd.Value)
}

func (f FloatWithTrailingZero) MarshalJSON() ([]byte, error) {
if float64(f) == float64(int(f)) {
return []byte(strconv.FormatFloat(float64(f), 'f', 1, 64)), nil
}

return []byte(strconv.FormatFloat(float64(f), 'f', -1, 64)), nil
}

func jsonbGetOffsetSize(isSmall bool) int {
if isSmall {
return jsonbSmallOffsetSize
Expand Down Expand Up @@ -124,8 +135,9 @@ func jsonbGetValueEntrySize(isSmall bool) int {
// the common JSON encoding data.
func (e *RowsEvent) decodeJsonBinary(data []byte) ([]byte, error) {
d := jsonBinaryDecoder{
useDecimal: e.useDecimal,
ignoreDecodeErr: e.ignoreJSONDecodeErr,
useDecimal: e.useDecimal,
useFloatWithTrailingZero: e.useFloatWithTrailingZero,
ignoreDecodeErr: e.ignoreJSONDecodeErr,
}

if d.isDataShort(data, 1) {
Expand All @@ -141,9 +153,10 @@ func (e *RowsEvent) decodeJsonBinary(data []byte) ([]byte, error) {
}

type jsonBinaryDecoder struct {
useDecimal bool
ignoreDecodeErr bool
err error
useDecimal bool
useFloatWithTrailingZero bool
ignoreDecodeErr bool
err error
}

func (d *jsonBinaryDecoder) decodeValue(tp byte, data []byte) interface{} {
Expand Down Expand Up @@ -175,6 +188,9 @@ func (d *jsonBinaryDecoder) decodeValue(tp byte, data []byte) interface{} {
case JSONB_UINT64:
return d.decodeUint64(data)
case JSONB_DOUBLE:
if d.useFloatWithTrailingZero {
return d.decodeDoubleWithTrailingZero(data)
}
return d.decodeDouble(data)
case JSONB_STRING:
return d.decodeString(data)
Expand Down Expand Up @@ -395,6 +411,11 @@ func (d *jsonBinaryDecoder) decodeDouble(data []byte) float64 {
return v
}

func (d *jsonBinaryDecoder) decodeDoubleWithTrailingZero(data []byte) FloatWithTrailingZero {
v := d.decodeDouble(data)
return FloatWithTrailingZero(v)
}

func (d *jsonBinaryDecoder) decodeString(data []byte) string {
if d.err != nil {
return ""
Expand Down
Loading
Loading