2626_logger = logging .getLogger (__name__ )
2727
2828
29- def _binary_to_decimal128 (binary_data ):
29+ def _binary_to_decimal128 (binary_data , scale = None ):
3030 """
3131 Convert binary data to Decimal128.
32-
32+
3333 The binary data represents a 128-bit decimal number in IEEE 754-2008 Decimal128 format.
3434 Based on the Java implementation from e6data's JDBC driver.
35-
35+
3636 Args:
3737 binary_data (bytes): Binary representation of Decimal128
38-
38+ scale (int, optional): Scale parameter for decimal precision. If None,
39+ attempts to decode from IEEE format or defaults to 0.
40+
3941 Returns:
4042 Decimal: Python Decimal object
4143 """
@@ -59,7 +61,7 @@ def _binary_to_decimal128(binary_data):
5961
6062 # Handle IEEE 754-2008 Decimal128 binary format
6163 if len (binary_data ) == 16 : # Decimal128 should be exactly 16 bytes
62- return _decode_decimal128_binary_java_style (binary_data )
64+ return _decode_decimal128_binary_java_style (binary_data , scale )
6365 else :
6466 _logger .warning (f"Invalid Decimal128 binary length: { len (binary_data )} bytes, expected 16" )
6567 return Decimal ('0' )
@@ -73,16 +75,17 @@ def _binary_to_decimal128(binary_data):
7375 return Decimal ('0' )
7476
7577
76- def _decode_decimal128_binary_java_style (binary_data ):
78+ def _decode_decimal128_binary_java_style (binary_data , scale = None ):
7779 """
7880 Decode IEEE 754-2008 Decimal128 binary format following Java implementation.
79-
81+
8082 Based on the Java implementation from e6data's JDBC driver getFieldDataFromChunk method.
8183 This method follows the same logic as the Java BigDecimal creation from ByteBuffer.
82-
84+
8385 Args:
8486 binary_data (bytes): 16-byte binary representation
85-
87+ scale (int, optional): Scale parameter for decimal precision
88+
8689 Returns:
8790 Decimal: Python Decimal object
8891 """
@@ -103,17 +106,21 @@ def _decode_decimal128_binary_java_style(binary_data):
103106 if big_int_value == 0 :
104107 return Decimal ('0' )
105108
106- # The Java code creates BigDecimal from BigInteger with scale 0
107- # This means we treat the integer value as the unscaled value
108- # However, for Decimal128, we need to handle the scaling properly
109-
110- # Try to create decimal directly from the integer value
111- decimal_value = Decimal (big_int_value )
109+ # The Java code creates BigDecimal from BigInteger with the provided scale
110+ # If scale is provided, use it to create the properly scaled decimal
111+ if scale is not None :
112+ # Create decimal with the specified scale (like Java's BigDecimal constructor)
113+ # This treats big_int_value as the unscaled value
114+ decimal_value = Decimal (big_int_value ) / (Decimal (10 ) ** scale )
115+ else :
116+ # Fallback: try to create decimal directly from the integer value
117+ decimal_value = Decimal (big_int_value )
112118
113119 # Check if this produces a reasonable decimal value
114120 # Decimal128 should represent normal decimal numbers
115- if abs (decimal_value ) < Decimal ('1E-6143' ) or abs (decimal_value ) > Decimal (
116- '9.999999999999999999999999999999999E+6144' ):
121+ # Only check range if scale was not provided (backward compatibility)
122+ if scale is None and (abs (decimal_value ) < Decimal ('1E-6143' ) or abs (decimal_value ) > Decimal (
123+ '9.999999999999999999999999999999999E+6144' )):
117124 # Value is outside normal Decimal128 range, try alternative interpretation
118125 return _decode_decimal128_alternative (binary_data )
119126
@@ -624,10 +631,12 @@ def get_column_from_chunk(vector: Vector) -> list:
624631 if vector .isConstantVector :
625632 # For constant vectors, get the binary data and convert it once
626633 binary_data = vector .data .numericDecimal128ConstantData .data
634+ # Get scale with backward compatibility for older engines
635+ scale = getattr (vector .data .numericDecimal128ConstantData , 'scale' , None )
627636
628637 # Convert binary data to BigDecimal equivalent
629638 if binary_data :
630- decimal_value = _binary_to_decimal128 (binary_data )
639+ decimal_value = _binary_to_decimal128 (binary_data , scale )
631640 else :
632641 decimal_value = Decimal ('0' )
633642
@@ -639,13 +648,16 @@ def get_column_from_chunk(vector: Vector) -> list:
639648 value_array .append (decimal_value )
640649 else :
641650 # For non-constant vectors, process each row individually
651+ # Get scale from decimal128Data (with backward compatibility)
652+ scale = getattr (vector .data .decimal128Data , 'scale' , None )
653+
642654 for row in range (vector .size ):
643655 if get_null (vector , row ):
644656 value_array .append (None )
645657 continue
646658 # Get binary data for this row
647659 binary_data = vector .data .decimal128Data .data [row ]
648- decimal_value = _binary_to_decimal128 (binary_data )
660+ decimal_value = _binary_to_decimal128 (binary_data , scale )
649661 value_array .append (decimal_value )
650662 else :
651663 value_array .append (None )
0 commit comments