Skip to content

Commit e9391d4

Browse files
committed
Add an option to decode numeric values with a trailing fractional zero
The new `numeric_decode_binary_ex` decoder variant is able to append a trailing fractional zero digit to numeric values with zero scale.
1 parent 484e352 commit e9391d4

File tree

2 files changed

+25
-1
lines changed

2 files changed

+25
-1
lines changed

codecs/__init__.pxd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,8 @@ cdef numeric_encode_text(CodecContext settings, WriteBuffer buf, obj)
120120
cdef numeric_decode_text(CodecContext settings, FRBuffer * buf)
121121
cdef numeric_encode_binary(CodecContext settings, WriteBuffer buf, obj)
122122
cdef numeric_decode_binary(CodecContext settings, FRBuffer * buf)
123+
cdef numeric_decode_binary_ex(CodecContext settings, FRBuffer * buf,
124+
bint trail_fract_zero)
123125

124126

125127
# Void

codecs/numeric.pyx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,11 @@ cdef numeric_encode_binary(CodecContext settings, WriteBuffer buf, obj):
129129
# For this reason the below code is pure overhead and is ~25% slower
130130
# than the simple text decoder above. That said, we need the binary
131131
# decoder to support binary COPY with numeric values.
132-
cdef numeric_decode_binary(CodecContext settings, FRBuffer *buf):
132+
cdef numeric_decode_binary_ex(
133+
CodecContext settings,
134+
FRBuffer *buf,
135+
bint trail_fract_zero,
136+
):
133137
cdef:
134138
uint16_t num_pgdigits = <uint16_t>hton.unpack_int16(frb_read(buf, 2))
135139
int16_t weight = hton.unpack_int16(frb_read(buf, 2))
@@ -140,6 +144,7 @@ cdef numeric_decode_binary(CodecContext settings, FRBuffer *buf):
140144
int16_t pgdigit
141145
object pydigits
142146
ssize_t num_pydigits
147+
ssize_t actual_num_pydigits
143148
ssize_t buf_size
144149
int64_t exponent
145150
int64_t abs_exponent
@@ -183,6 +188,7 @@ cdef numeric_decode_binary(CodecContext settings, FRBuffer *buf):
183188
1 + # leading zero
184189
1 + # decimal dot
185190
num_pydigits + # digits
191+
1 + # possible trailing zero padding
186192
2 + # exponent indicator (E-,E+)
187193
exponent_chars + # exponent
188194
1 # null terminator char
@@ -231,6 +237,18 @@ cdef numeric_decode_binary(CodecContext settings, FRBuffer *buf):
231237
# trailing zeros.
232238
bufptr += dscale_left
233239

240+
if trail_fract_zero:
241+
# Check if the number of rendered digits matches the exponent,
242+
# and if so, add another trailing zero, so the result always
243+
# appears with a decimal point.
244+
actual_num_pydigits = bufptr - charbuf - 2
245+
if sign == NUMERIC_NEG:
246+
actual_num_pydigits -= 1
247+
248+
if actual_num_pydigits == abs_exponent:
249+
bufptr[0] = <char>b'0'
250+
bufptr += 1
251+
234252
if exponent != 0:
235253
bufptr[0] = b'E'
236254
if exponent < 0:
@@ -253,6 +271,10 @@ cdef numeric_decode_binary(CodecContext settings, FRBuffer *buf):
253271
cpython.PyMem_Free(charbuf)
254272

255273

274+
cdef numeric_decode_binary(CodecContext settings, FRBuffer *buf):
275+
return numeric_decode_binary_ex(settings, buf, False)
276+
277+
256278
cdef inline char *_unpack_digit_stripping_lzeros(char *buf, int64_t pgdigit):
257279
cdef:
258280
int64_t d

0 commit comments

Comments
 (0)