liukun4515 commented on code in PR #3245:
URL: https://github.com/apache/arrow-datafusion/pull/3245#discussion_r954620922
##########
datafusion/optimizer/src/pre_cast_lit_in_comparison.rs:
##########
@@ -200,47 +160,110 @@ fn is_comparison_op(op: &Operator) -> bool {
}
fn is_support_data_type(data_type: &DataType) -> bool {
- // TODO support decimal with other data type
matches!(
data_type,
- DataType::Int8 | DataType::Int16 | DataType::Int32 | DataType::Int64
+ DataType::Int8
+ | DataType::Int16
+ | DataType::Int32
+ | DataType::Int64
+ | DataType::Decimal128(_, _)
)
}
-fn can_integer_literal_cast_to_type(
- integer_lit_value: &ScalarValue,
+fn try_cast_literal_to_type(
+ lit_value: &ScalarValue,
target_type: &DataType,
-) -> Result<bool> {
- if integer_lit_value.is_null() {
+) -> Result<(bool, Option<ScalarValue>)> {
+ if lit_value.is_null() {
// null value can be cast to any type of null value
- return Ok(true);
+ return Ok((true, Some(ScalarValue::try_from(target_type)?)));
}
+ let mul = match target_type {
+ DataType::Int8 | DataType::Int16 | DataType::Int32 | DataType::Int64
=> 1_i128,
+ DataType::Decimal128(_, scale) => 10_i128.pow(*scale as u32),
+ other_type => {
+ return Err(DataFusionError::Internal(format!(
+ "Error target data type {:?}",
+ other_type
+ )));
+ }
+ };
let (target_min, target_max) = match target_type {
DataType::Int8 => (i8::MIN as i128, i8::MAX as i128),
DataType::Int16 => (i16::MIN as i128, i16::MAX as i128),
DataType::Int32 => (i32::MIN as i128, i32::MAX as i128),
DataType::Int64 => (i64::MIN as i128, i64::MAX as i128),
+ DataType::Decimal128(precision, _) => (
+ MIN_DECIMAL_FOR_EACH_PRECISION[*precision - 1],
+ MAX_DECIMAL_FOR_EACH_PRECISION[*precision - 1],
+ ),
other_type => {
return Err(DataFusionError::Internal(format!(
"Error target data type {:?}",
other_type
- )))
+ )));
}
};
- let lit_value = match integer_lit_value {
- ScalarValue::Int8(Some(v)) => *v as i128,
- ScalarValue::Int16(Some(v)) => *v as i128,
- ScalarValue::Int32(Some(v)) => *v as i128,
- ScalarValue::Int64(Some(v)) => *v as i128,
+ let lit_value_target_type = match lit_value {
+ ScalarValue::Int8(Some(v)) => (*v as i128).checked_mul(mul),
+ ScalarValue::Int16(Some(v)) => (*v as i128).checked_mul(mul),
+ ScalarValue::Int32(Some(v)) => (*v as i128).checked_mul(mul),
+ ScalarValue::Int64(Some(v)) => (*v as i128).checked_mul(mul),
+ ScalarValue::Decimal128(Some(v), _, scale) => {
+ let lit_scale_mul = 10_i128.pow(*scale as u32);
+ if mul >= lit_scale_mul {
+ // Example:
+ // lit is decimal(123,3,2)
+ // target type is decimal(5,3)
+ // the lit can be converted to the decimal(1230,5,3)
+ (*v).checked_mul(mul / lit_scale_mul)
+ } else if (*v) % (lit_scale_mul / mul) == 0 {
+ // Example:
+ // lit is decimal(123000,10,3)
+ // target type is int32: the lit can be converted to INT32(123)
+ // target type is decimal(10,2): the lit can be converted to
decimal(12300,10,2)
+ Some(*v / (lit_scale_mul / mul))
+ } else {
+ // can't convert the lit decimal to the target data type
+ None
+ }
+ }
other_value => {
return Err(DataFusionError::Internal(format!(
"Invalid literal value {:?}",
other_value
- )))
+ )));
}
};
- Ok(lit_value >= target_min && lit_value <= target_max)
+ match lit_value_target_type {
+ None => Ok((false, None)),
+ Some(value) => {
+ match value >= target_min && value <= target_max {
Review Comment:
Done
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]