Skip to content

Commit 790f19b

Browse files
mtopolnikclaude
andcommitted
Use true LE wire order for QWP decimals
The decimal encoder wrote multi-word values with the most significant word first (hi, lo). This made the wire format inconsistent: individual words were little-endian but word order was big-endian. QwpColumnWriter now emits words least-significant-first, matching the byte-level little-endian convention used by all other multi-word QWP types (UUID, LONG256). The test decoder reversal and QwpConstants docs are updated to match. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 0bf65cc commit 790f19b

3 files changed

Lines changed: 14 additions & 10 deletions

File tree

core/src/main/java/io/questdb/client/cutlass/qwp/client/QwpColumnWriter.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -194,19 +194,19 @@ private void writeDecimal128Column(byte scale, long addr, int count) {
194194
long offset = (long) i * 16;
195195
long hi = Unsafe.getUnsafe().getLong(addr + offset);
196196
long lo = Unsafe.getUnsafe().getLong(addr + offset + 8);
197-
buffer.putLong(hi);
198197
buffer.putLong(lo);
198+
buffer.putLong(hi);
199199
}
200200
}
201201

202202
private void writeDecimal256Column(byte scale, long addr, int count) {
203203
buffer.putByte(scale);
204204
for (int i = 0; i < count; i++) {
205205
long offset = (long) i * 32;
206-
buffer.putLong(Unsafe.getUnsafe().getLong(addr + offset));
207-
buffer.putLong(Unsafe.getUnsafe().getLong(addr + offset + 8));
208-
buffer.putLong(Unsafe.getUnsafe().getLong(addr + offset + 16));
209206
buffer.putLong(Unsafe.getUnsafe().getLong(addr + offset + 24));
207+
buffer.putLong(Unsafe.getUnsafe().getLong(addr + offset + 16));
208+
buffer.putLong(Unsafe.getUnsafe().getLong(addr + offset + 8));
209+
buffer.putLong(Unsafe.getUnsafe().getLong(addr + offset));
210210
}
211211
}
212212

core/src/main/java/io/questdb/client/cutlass/qwp/protocol/QwpConstants.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@
2626

2727
/**
2828
* Constants for the QWP v1 binary protocol.
29+
* <p>
30+
* All little-endian encoding in this protocol is byte-level: multi-byte and
31+
* multi-word values are stored with the least significant byte at the lowest
32+
* address.
2933
*/
3034
public final class QwpConstants {
3135

@@ -160,18 +164,18 @@ public final class QwpConstants {
160164

161165
/**
162166
* Column type: DECIMAL128 (16 bytes, 38 digits precision).
163-
* Wire format: [scale (1B in schema)] + [big-endian unscaled value (16B)]
167+
* Wire format: [scale (1B in schema)] + [little-endian unscaled value (16B)]
164168
*/
165169
public static final byte TYPE_DECIMAL128 = 0x14;
166170
/**
167171
* Column type: DECIMAL256 (32 bytes, 77 digits precision).
168-
* Wire format: [scale (1B in schema)] + [big-endian unscaled value (32B)]
172+
* Wire format: [scale (1B in schema)] + [little-endian unscaled value (32B)]
169173
*/
170174
public static final byte TYPE_DECIMAL256 = 0x15;
171175

172176
/**
173177
* Column type: DECIMAL64 (8 bytes, 18 digits precision).
174-
* Wire format: [scale (1B in schema)] + [big-endian unscaled value (8B)]
178+
* Wire format: [scale (1B in schema)] + [little-endian unscaled value (8B)]
175179
*/
176180
public static final byte TYPE_DECIMAL64 = 0x13;
177181
/**
@@ -200,7 +204,7 @@ public final class QwpConstants {
200204
*/
201205
public static final byte TYPE_LONG = 0x05;
202206
/**
203-
* Column type: LONG256 (32 bytes, big-endian).
207+
* Column type: LONG256 (32 bytes, little-endian).
204208
*/
205209
public static final byte TYPE_LONG256 = 0x0D;
206210

@@ -232,7 +236,7 @@ public final class QwpConstants {
232236
*/
233237
public static final byte TYPE_TIMESTAMP_NANOS = 0x10;
234238
/**
235-
* Column type: UUID (16 bytes, big-endian).
239+
* Column type: UUID (16 bytes, little-endian).
236240
*/
237241
public static final byte TYPE_UUID = 0x0C;
238242

core/src/test/java/io/questdb/client/test/cutlass/qwp/client/QwpUdpSenderTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2224,7 +2224,7 @@ private void decodeDecimals(Object[] values, boolean[] nulls, int valueCount, in
22242224
values[row] = null;
22252225
} else {
22262226
byte[] bytes = reader.readBytes(width);
2227-
// wire format is little-endian; BigInteger expects big-endian
2227+
// LE wire format -> BE for BigInteger
22282228
for (int lo = 0, hi = bytes.length - 1; lo < hi; lo++, hi--) {
22292229
byte tmp = bytes[lo];
22302230
bytes[lo] = bytes[hi];

0 commit comments

Comments
 (0)