Skip to content

Commit 1598624

Browse files
committed
sql/pgwire: fix precision loss in binary decimal decoding
Decimal decoding implementation was ignoring trailing zeros after the decimal point that were implicitly added by the dscale value, resulting precision losses. For example, 1.23000 could be decoded as 1.23. This commit fixes it by adding missing zeros. Release note: None Epic: CRDB-57092 Fixes: #158093
1 parent 0f2bc7b commit 1598624

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

pkg/sql/pgwire/pgwirebase/encoding.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,9 +655,19 @@ func DecodeDatum(
655655
// is larger than our calculated dscale, truncate our buffer to match the
656656
// desired dscale.
657657
dscale := (alloc.pgNum.Ndigits - (alloc.pgNum.Weight + 1)) * PGDecDigits
658+
658659
if overScale := dscale - alloc.pgNum.Dscale; overScale > 0 {
659660
dscale -= overScale
660661
decDigits = decDigits[:len(decDigits)-int(overScale)]
662+
} else if overScale < 0 {
663+
z := -overScale
664+
if dscale < 0 {
665+
z = alloc.pgNum.Dscale
666+
}
667+
for i := int16(0); i < z; i++ {
668+
decDigits = append(decDigits, '0')
669+
dscale++
670+
}
661671
}
662672

663673
decString := encoding.UnsafeConvertBytesToString(decDigits)

pkg/sql/pgwire/testdata/pgtest/decimal

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,40 @@ ReadyForQuery
8181
{"Type":"DataRow","Values":[{"binary":"00010001000000000001"},{"binary":"00010001000000000001"},{"binary":"0001000100000000000a"}]}
8282
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
8383
{"Type":"ReadyForQuery","TxStatus":"I"}
84+
85+
# ResultFormatCodes [1] = FormatBinary
86+
# [0, 2, 0, 0, 0, 0, 0, 5, 0, 1, 8fc] = binary 1.23000
87+
# [0, 2, 0, 0, 0, 0, 0, a, 0, 1, 8fc] = binary 1.2300000000
88+
# [0, 1, 0, 0, 0, 0, 0, a, 0, 1] = binary 1.0000000000
89+
send
90+
Parse {"Name": "s3", "Query": "SELECT $1::decimal, $2::decimal, $3::decimal"}
91+
Bind {"DestinationPortal": "p3", "PreparedStatement": "s3", "ParameterFormatCodes": [1], "Parameters": [{"binary":"0002000000000005000108fc"}, {"binary":"000200000000000a000108fc"}, {"binary": "000100000000000a0001"}]}
92+
Execute {"Portal": "p3"}
93+
Sync
94+
----
95+
96+
until
97+
ReadyForQuery
98+
----
99+
{"Type":"ParseComplete"}
100+
{"Type":"BindComplete"}
101+
{"Type":"DataRow","Values":[{"text":"1.23000"},{"text":"1.2300000000"},{"text":"1.0000000000"}]}
102+
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
103+
{"Type":"ReadyForQuery","TxStatus":"I"}
104+
105+
# [0, 1, 0, 1, 0, 0, 0, 3, 0, 1] = binary 1.000E+4
106+
send
107+
Parse {"Name": "s4", "Query": "SELECT $1::decimal"}
108+
Bind {"DestinationPortal": "p4", "PreparedStatement": "s4", "ParameterFormatCodes": [1], "Parameters": [{"binary":"00010001000000030001"}]}
109+
Execute {"Portal": "p4"}
110+
Sync
111+
----
112+
113+
until
114+
ReadyForQuery
115+
----
116+
{"Type":"ParseComplete"}
117+
{"Type":"BindComplete"}
118+
{"Type":"DataRow","Values":[{"text":"1.000E+4"}]}
119+
{"Type":"CommandComplete","CommandTag":"SELECT 1"}
120+
{"Type":"ReadyForQuery","TxStatus":"I"}

0 commit comments

Comments
 (0)