| 128 | } |
| 129 | |
| 130 | llvm::Value * nativeCast(llvm::IRBuilderBase & b, const DataTypePtr & from_type, llvm::Value * value, const DataTypePtr & to_type) |
| 131 | { |
| 132 | if (from_type->equals(*to_type)) |
| 133 | { |
| 134 | return value; |
| 135 | } |
| 136 | if (from_type->isNullable() && to_type->isNullable()) |
| 137 | { |
| 138 | auto * inner = nativeCast(b, removeNullable(from_type), b.CreateExtractValue(value, {0}), to_type); |
| 139 | return b.CreateInsertValue(inner, b.CreateExtractValue(value, {1}), {1}); |
| 140 | } |
| 141 | if (from_type->isNullable()) |
| 142 | { |
| 143 | return nativeCast(b, removeNullable(from_type), b.CreateExtractValue(value, {0}), to_type); |
| 144 | } |
| 145 | if (to_type->isNullable()) |
| 146 | { |
| 147 | auto * to_native_type = toNativeType(b, to_type); |
| 148 | auto * inner = nativeCast(b, from_type, value, removeNullable(to_type)); |
| 149 | return b.CreateInsertValue(llvm::Constant::getNullValue(to_native_type), inner, {0}); |
| 150 | } |
| 151 | auto * from_native_type = toNativeType(b, from_type); |
| 152 | auto * to_native_type = toNativeType(b, to_type); |
| 153 | |
| 154 | /// Handle scale conversion for DateTime/DateTime64/Time/Time64 types. |
| 155 | /// When converting between types with different scales (e.g., DateTime with implicit |
| 156 | /// scale 0 to DateTime64 with scale 3), we need to multiply/divide by the appropriate |
| 157 | /// power of 10, not just cast the integer value. |
| 158 | /// Note: Decimal types are NOT handled here because JIT-compiled aggregate functions |
| 159 | /// (e.g., avg) already manage Decimal scale conversion themselves. |
| 160 | { |
| 161 | auto get_effective_scale = [](const DataTypePtr & type) -> std::optional<UInt32> |
| 162 | { |
| 163 | WhichDataType which(type); |
| 164 | if (which.isDateTime() || which.isTime()) |
| 165 | return 0u; |
| 166 | if (which.isDateTime64()) |
| 167 | return typeid_cast<const DataTypeDateTime64 *>(type.get())->getScale(); |
| 168 | if (which.isTime64()) |
| 169 | return typeid_cast<const DataTypeTime64 *>(type.get())->getScale(); |
| 170 | return std::nullopt; |
| 171 | }; |
| 172 | |
| 173 | auto from_scale = get_effective_scale(from_type); |
| 174 | auto to_scale = get_effective_scale(to_type); |
| 175 | |
| 176 | if (from_scale && to_scale && *from_scale != *to_scale) |
| 177 | { |
| 178 | /// First widen/narrow the integer type if needed. |
| 179 | if (from_native_type != to_native_type) |
| 180 | value = b.CreateIntCast(value, to_native_type, typeIsSigned(*from_type)); |
| 181 | |
| 182 | UInt32 scale_diff = (*to_scale > *from_scale) ? (*to_scale - *from_scale) : (*from_scale - *to_scale); |
| 183 | unsigned bit_width = to_native_type->getIntegerBitWidth(); |
| 184 | llvm::APInt scale_factor(bit_width, 1); |
| 185 | for (UInt32 i = 0; i < scale_diff; ++i) |
| 186 | scale_factor *= 10; |
| 187 | auto * scale_constant = llvm::ConstantInt::get(b.getContext(), scale_factor); |
no test coverage detected