@@ -159,50 +159,48 @@ cdef int convert_number_to_arrow_decimal(ArrowArrayImpl arrow_array,
159159 Converts a NUMBER value stored in the buffer to Arrow DECIMAL128.
160160 """
161161 cdef:
162- char_type c
163- bint has_sign = 0
164- char_type digits[39 ] # 38 digits + sign
165162 OracleNumber * value = & buffer .as_number
166- uint8_t num_chars = 0 , decimal_point_index = 0 , allowed_max_chars = 0
167- int64_t actual_scale = 0
163+ uint8_t num_digits, allowed_max_chars
164+ char_type digits[40 ]
165+ uint8_t actual_scale
166+
167+ # determine if the number can be represented as an Arrow decimal128 value
168+ # only 38 decimal digits are permitted (excluding the sign and decimal
169+ # point)
170+ allowed_max_chars = 38
171+ if value.chars[0 ] == b' -' :
172+ allowed_max_chars += 1
173+ if not value.is_integer:
174+ allowed_max_chars += 1
175+ if value.is_max_negative_value or value.num_chars > allowed_max_chars:
176+ raise ValueError (" Value cannot be represented as Arrow Decimal128" )
168177
169- if value.chars[0 ] == 45 : # minus sign
170- has_sign = True
178+ # integers can be handled directly
179+ if value.is_integer and arrow_array.scale == 0 :
180+ return arrow_array.append_decimal(value.chars, value.num_chars)
171181
182+ # Arrow expects a string of digits without the decimal point; if the number
183+ # does not contain at least the number of digits after the decimal point
184+ # required by the scale of the Arrow array, zeros are appended
172185 if value.is_integer:
173- if has_sign:
174- allowed_max_chars = 39
175- else :
176- allowed_max_chars = 38
177- else : # decimal point
178- if has_sign:
179- allowed_max_chars = 40
180- else :
181- allowed_max_chars = 39
182-
183- # Arrow Decimal128 can only represent values with 38 decimal digits
184- if value.is_max_negative_value or value.num_chars > allowed_max_chars:
185- raise ValueError (" Value cannot be represented as "
186- " Arrow Decimal128" )
187- if value.is_integer:
188- arrow_array.append_decimal(value.chars, value.num_chars)
186+ actual_scale = 0
187+ num_digits = value.num_chars
189188 else :
190- for i in range (value.num_chars):
191- c = value.chars[i]
192- # count all characters except the decimal point
193- if c != 46 :
194- digits[num_chars] = c
195- num_chars += 1
196- else :
197- decimal_point_index = i
198-
199- # Append any trailing zeros.
200- actual_scale = num_chars - decimal_point_index
201- for i in range (abs (arrow_array.scale) - actual_scale):
202- digits[num_chars] = b' 0'
203- num_chars += 1
204- arrow_array.append_decimal(digits, num_chars)
205-
189+ actual_scale = 0
190+ while True :
191+ num_digits = value.num_chars - actual_scale - 1
192+ if value.chars[num_digits] == b' .' :
193+ break
194+ actual_scale += 1
195+ memcpy(digits, value.chars, num_digits)
196+ if actual_scale > 0 :
197+ memcpy(& digits[num_digits], & value.chars[num_digits + 1 ], actual_scale)
198+ num_digits += actual_scale
199+ while actual_scale < arrow_array.scale:
200+ digits[num_digits] = b' 0'
201+ num_digits += 1
202+ actual_scale += 1
203+ arrow_array.append_decimal(digits, num_digits)
206204
207205
208206cdef int convert_number_to_arrow_double(ArrowArrayImpl arrow_array,
0 commit comments