Skip to content

Commit 22f45bb

Browse files
committed
.
1 parent f86f753 commit 22f45bb

3 files changed

Lines changed: 43 additions & 6 deletions

File tree

datafusion/expr-common/src/type_coercion/binary.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ pub fn type_union_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<D
891891
/// inspect whether an operand is a literal. This allows `int_col < '5'`
892892
/// (cast the literal) while rejecting `text_col < 5` (type mismatch).
893893
pub fn comparison_coercion(lhs_type: &DataType, rhs_type: &DataType) -> Option<DataType> {
894-
if lhs_type == rhs_type {
894+
if lhs_type.equals_datatype(rhs_type) {
895895
// same type => equality is possible
896896
return Some(lhs_type.clone());
897897
}

datafusion/optimizer/src/analyzer/type_coercion.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use datafusion_common::config::ConfigOptions;
3131
use datafusion_common::tree_node::{Transformed, TreeNode, TreeNodeRewriter};
3232
use datafusion_common::{
3333
Column, DFSchema, DFSchemaRef, DataFusionError, Result, ScalarValue, TableReference,
34-
exec_err, internal_datafusion_err, internal_err, not_impl_err, plan_datafusion_err,
34+
exec_err, internal_err, not_impl_err, plan_datafusion_err,
3535
plan_err,
3636
};
3737
use datafusion_expr::expr::{
@@ -662,31 +662,40 @@ impl TreeNodeRewriter for TypeCoercionRewriter<'_> {
662662
high,
663663
}) => {
664664
let expr_type = expr.get_type(self.schema)?;
665-
// Cast string literal bounds to the expression's numeric type
665+
let low_type = low.get_type(self.schema)?;
666+
// Try casting string literals to the other side's numeric
667+
// type in both directions, mirroring BinaryExpr behavior.
668+
// This handles both `int_col BETWEEN '1' AND '10'` and
669+
// `'5' BETWEEN 1 AND 10`.
666670
let low = try_cast_string_literal_to_type(&low, &expr_type)?
667671
.map(Box::new)
668672
.unwrap_or(low);
669673
let high = try_cast_string_literal_to_type(&high, &expr_type)?
670674
.map(Box::new)
671675
.unwrap_or(high);
676+
let expr =
677+
try_cast_string_literal_to_type(&expr, &low_type)?
678+
.map(Box::new)
679+
.unwrap_or(expr);
680+
let expr_type = expr.get_type(self.schema)?;
672681
let low_type = low.get_type(self.schema)?;
673682
let low_coerced_type = comparison_coercion(&expr_type, &low_type)
674683
.ok_or_else(|| {
675-
internal_datafusion_err!(
684+
plan_datafusion_err!(
676685
"Failed to coerce types {expr_type} and {low_type} in BETWEEN expression"
677686
)
678687
})?;
679688
let high_type = high.get_type(self.schema)?;
680689
let high_coerced_type = comparison_coercion(&expr_type, &high_type)
681690
.ok_or_else(|| {
682-
internal_datafusion_err!(
691+
plan_datafusion_err!(
683692
"Failed to coerce types {expr_type} and {high_type} in BETWEEN expression"
684693
)
685694
})?;
686695
let coercion_type =
687696
comparison_coercion(&low_coerced_type, &high_coerced_type)
688697
.ok_or_else(|| {
689-
internal_datafusion_err!(
698+
plan_datafusion_err!(
690699
"Failed to coerce types {expr_type} and {high_type} in BETWEEN expression"
691700
)
692701
})?;

datafusion/sqllogictest/test_files/string_numeric_coercion.slt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,30 @@ SELECT * FROM t_int WHERE column1 NOT BETWEEN '5' AND '100';
242242
325
243243
499
244244

245+
# -------------------------------------------------
246+
# String literal expression with numeric bounds
247+
# (reverse direction: cast the expression, not just the bounds)
248+
# -------------------------------------------------
249+
250+
query B
251+
SELECT '5' BETWEEN 1 AND 10;
252+
----
253+
true
254+
255+
query B
256+
SELECT '0' BETWEEN 1 AND 10;
257+
----
258+
false
259+
260+
query B
261+
SELECT '5' NOT BETWEEN 1 AND 10;
262+
----
263+
false
264+
265+
# Non-numeric string literal with numeric bounds should error
266+
statement error Arrow error: Cast error: Cannot cast string 'hello' to value of Int64 type
267+
SELECT 'hello' BETWEEN 1 AND 10;
268+
245269
# -------------------------------------------------
246270
# Decimal column with string literal comparisons
247271
# -------------------------------------------------
@@ -300,6 +324,10 @@ SELECT * FROM t_mixed WHERE column2 = column1;
300324
statement error Can not find compatible types to compare Utf8 with \[Int64, Int64\]
301325
SELECT * FROM t_mixed WHERE column2 IN (5, 10);
302326

327+
# text column BETWEEN numeric literals
328+
statement error Failed to coerce types Utf8 and Int64 in BETWEEN expression
329+
SELECT * FROM t_mixed WHERE column2 BETWEEN 1 AND 10;
330+
303331
statement ok
304332
DROP TABLE t_mixed;
305333

0 commit comments

Comments
 (0)