| 218 | } |
| 219 | |
| 220 | llvm::Value * nativeCastWithDecimalScale( |
| 221 | llvm::IRBuilderBase & b, const DataTypePtr & from_type, llvm::Value * value, const DataTypePtr & to_type) |
| 222 | { |
| 223 | if (from_type->equals(*to_type)) |
| 224 | return value; |
| 225 | |
| 226 | if (from_type->isNullable() && to_type->isNullable()) |
| 227 | { |
| 228 | auto * inner_value = b.CreateExtractValue(value, {0}); |
| 229 | auto * is_null = b.CreateExtractValue(value, {1}); |
| 230 | auto * inner = nativeCastWithDecimalScale(b, removeNullable(from_type), inner_value, removeNullable(to_type)); |
| 231 | auto * to_native_type = toNativeType(b, to_type); |
| 232 | llvm::Value * result = llvm::Constant::getNullValue(to_native_type); |
| 233 | result = b.CreateInsertValue(result, inner, {0}); |
| 234 | return b.CreateInsertValue(result, is_null, {1}); |
| 235 | } |
| 236 | if (from_type->isNullable()) |
| 237 | { |
| 238 | return nativeCastWithDecimalScale(b, removeNullable(from_type), b.CreateExtractValue(value, {0}), to_type); |
| 239 | } |
| 240 | if (to_type->isNullable()) |
| 241 | { |
| 242 | auto * to_native_type = toNativeType(b, to_type); |
| 243 | auto * inner = nativeCastWithDecimalScale(b, from_type, value, removeNullable(to_type)); |
| 244 | return b.CreateInsertValue(llvm::Constant::getNullValue(to_native_type), inner, {0}); |
| 245 | } |
| 246 | |
| 247 | WhichDataType from_w(*from_type); |
| 248 | WhichDataType to_w(*to_type); |
| 249 | |
| 250 | /// Only intercept conversions involving `Decimal` here. Everything else |
| 251 | /// — including `DateTime` / `DateTime64` / `Time` / `Time64` scale lifts — |
| 252 | /// is already handled correctly by `nativeCast`. |
| 253 | if (to_w.isDecimal() || from_w.isDecimal()) |
| 254 | { |
| 255 | auto * from_native_type = toNativeType(b, from_type); |
| 256 | auto * to_native_type = toNativeType(b, to_type); |
| 257 | const UInt32 to_scale = to_w.isDecimal() ? getDecimalScale(*to_type) : 0; |
| 258 | const UInt32 from_scale = from_w.isDecimal() ? getDecimalScale(*from_type) : 0; |
| 259 | |
| 260 | /// Build LLVM integer constant for `10^n` of the requested bit width. |
| 261 | auto pow10_int_const = [&](unsigned bit_width, UInt32 n) -> llvm::ConstantInt * |
| 262 | { |
| 263 | llvm::APInt v(bit_width, 1); |
| 264 | for (UInt32 i = 0; i < n; ++i) |
| 265 | v *= 10; |
| 266 | return llvm::cast<llvm::ConstantInt>(llvm::ConstantInt::get(b.getContext(), v)); |
| 267 | }; |
| 268 | |
| 269 | /// Build LLVM floating-point constant for `10^n` from an `APInt` of the requested bit width. |
| 270 | /// This goes through `APFloat::convertFromAPInt` rather than `APInt::getZExtValue` so that |
| 271 | /// it stays correct when `10^n` does not fit in 64 bits (e.g. `Decimal128` with `scale = 38`, |
| 272 | /// or `Decimal256` with even larger scales). |
| 273 | auto pow10_fp_const = [&](unsigned bit_width, UInt32 n, llvm::Type * fp_type) -> llvm::Constant * |
| 274 | { |
| 275 | llvm::APInt v(bit_width, 1); |
| 276 | for (UInt32 i = 0; i < n; ++i) |
| 277 | v *= 10; |
no test coverage detected