Skip to content

Commit bddf7e6

Browse files
kczimmphillipleblanc
authored andcommitted
infer placeholder datatype for InList, Like, SimilarTo
1 parent c118e72 commit bddf7e6

File tree

1 file changed

+139
-17
lines changed

1 file changed

+139
-17
lines changed

datafusion/expr/src/expr.rs

Lines changed: 139 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,23 +1617,38 @@ impl Expr {
16171617
pub fn infer_placeholder_types(self, schema: &DFSchema) -> Result<(Expr, bool)> {
16181618
let mut has_placeholder = false;
16191619
self.transform(|mut expr| {
1620-
// Default to assuming the arguments are the same type
1621-
if let Expr::BinaryExpr(BinaryExpr { left, op: _, right }) = &mut expr {
1622-
rewrite_placeholder(left.as_mut(), right.as_ref(), schema)?;
1623-
rewrite_placeholder(right.as_mut(), left.as_ref(), schema)?;
1624-
};
1625-
if let Expr::Between(Between {
1626-
expr,
1627-
negated: _,
1628-
low,
1629-
high,
1630-
}) = &mut expr
1631-
{
1632-
rewrite_placeholder(low.as_mut(), expr.as_ref(), schema)?;
1633-
rewrite_placeholder(high.as_mut(), expr.as_ref(), schema)?;
1634-
}
1635-
if let Expr::Placeholder(_) = &expr {
1636-
has_placeholder = true;
1620+
match &mut expr {
1621+
// Default to assuming the arguments are the same type
1622+
Expr::BinaryExpr(BinaryExpr { left, op: _, right }) => {
1623+
rewrite_placeholder(left.as_mut(), right.as_ref(), schema)?;
1624+
rewrite_placeholder(right.as_mut(), left.as_ref(), schema)?;
1625+
}
1626+
Expr::Between(Between {
1627+
expr,
1628+
negated: _,
1629+
low,
1630+
high,
1631+
}) => {
1632+
rewrite_placeholder(low.as_mut(), expr.as_ref(), schema)?;
1633+
rewrite_placeholder(high.as_mut(), expr.as_ref(), schema)?;
1634+
}
1635+
Expr::InList(InList {
1636+
expr,
1637+
list,
1638+
negated: _,
1639+
}) => {
1640+
for item in list.iter_mut() {
1641+
rewrite_placeholder(item, expr.as_ref(), schema)?;
1642+
}
1643+
}
1644+
Expr::Like(Like { expr, pattern, .. })
1645+
| Expr::SimilarTo(Like { expr, pattern, .. }) => {
1646+
rewrite_placeholder(pattern.as_mut(), expr.as_ref(), schema)?;
1647+
}
1648+
Expr::Placeholder(_) => {
1649+
has_placeholder = true;
1650+
}
1651+
_ => {}
16371652
}
16381653
Ok(Transformed::yes(expr))
16391654
})
@@ -2839,10 +2854,117 @@ mod test {
28392854
case, lit, qualified_wildcard, wildcard, wildcard_with_options, ColumnarValue,
28402855
ScalarFunctionArgs, ScalarUDF, ScalarUDFImpl, Volatility,
28412856
};
2857+
use arrow::datatypes::{Field, Schema};
28422858
use sqlparser::ast;
28432859
use sqlparser::ast::{Ident, IdentWithAlias};
28442860
use std::any::Any;
28452861

2862+
#[test]
2863+
fn infer_placeholder_in_clause() {
2864+
// SELECT * FROM employees WHERE department_id IN ($1, $2, $3);
2865+
let column = col("department_id");
2866+
let param_placeholders = vec![
2867+
Expr::Placeholder(Placeholder {
2868+
id: "$1".to_string(),
2869+
data_type: None,
2870+
}),
2871+
Expr::Placeholder(Placeholder {
2872+
id: "$2".to_string(),
2873+
data_type: None,
2874+
}),
2875+
Expr::Placeholder(Placeholder {
2876+
id: "$3".to_string(),
2877+
data_type: None,
2878+
}),
2879+
];
2880+
let in_list = Expr::InList(InList {
2881+
expr: Box::new(column),
2882+
list: param_placeholders,
2883+
negated: false,
2884+
});
2885+
2886+
let schema = Arc::new(Schema::new(vec![
2887+
Field::new("name", DataType::Utf8, true),
2888+
Field::new("department_id", DataType::Int32, true),
2889+
]));
2890+
let df_schema = DFSchema::try_from(schema).unwrap();
2891+
2892+
let (inferred_expr, contains_placeholder) =
2893+
in_list.infer_placeholder_types(&df_schema).unwrap();
2894+
2895+
assert!(contains_placeholder);
2896+
2897+
match inferred_expr {
2898+
Expr::InList(in_list) => {
2899+
for expr in in_list.list {
2900+
match expr {
2901+
Expr::Placeholder(placeholder) => {
2902+
assert_eq!(
2903+
placeholder.data_type,
2904+
Some(DataType::Int32),
2905+
"Placeholder {} should infer Int32",
2906+
placeholder.id
2907+
);
2908+
}
2909+
_ => panic!("Expected Placeholder expression"),
2910+
}
2911+
}
2912+
}
2913+
_ => panic!("Expected InList expression"),
2914+
}
2915+
}
2916+
2917+
#[test]
2918+
fn infer_placeholder_like_and_similar_to() {
2919+
// name LIKE $1
2920+
let schema =
2921+
Arc::new(Schema::new(vec![Field::new("name", DataType::Utf8, true)]));
2922+
let df_schema = DFSchema::try_from(schema).unwrap();
2923+
2924+
let like = Like {
2925+
expr: Box::new(col("name")),
2926+
pattern: Box::new(Expr::Placeholder(Placeholder {
2927+
id: "$1".to_string(),
2928+
data_type: None,
2929+
})),
2930+
negated: false,
2931+
case_insensitive: false,
2932+
escape_char: None,
2933+
};
2934+
2935+
let expr = Expr::Like(like.clone());
2936+
2937+
let (inferred_expr, _) = expr.infer_placeholder_types(&df_schema).unwrap();
2938+
match inferred_expr {
2939+
Expr::Like(like) => match *like.pattern {
2940+
Expr::Placeholder(placeholder) => {
2941+
assert_eq!(placeholder.data_type, Some(DataType::Utf8));
2942+
}
2943+
_ => panic!("Expected Placeholder"),
2944+
},
2945+
_ => panic!("Expected Like"),
2946+
}
2947+
2948+
// name SIMILAR TO $1
2949+
let expr = Expr::SimilarTo(like);
2950+
2951+
let (inferred_expr, _) = expr.infer_placeholder_types(&df_schema).unwrap();
2952+
match inferred_expr {
2953+
Expr::SimilarTo(like) => match *like.pattern {
2954+
Expr::Placeholder(placeholder) => {
2955+
assert_eq!(
2956+
placeholder.data_type,
2957+
Some(DataType::Utf8),
2958+
"Placeholder {} should infer Utf8",
2959+
placeholder.id
2960+
);
2961+
}
2962+
_ => panic!("Expected Placeholder expression"),
2963+
},
2964+
_ => panic!("Expected SimilarTo expression"),
2965+
}
2966+
}
2967+
28462968
#[test]
28472969
#[allow(deprecated)]
28482970
fn format_case_when() -> Result<()> {

0 commit comments

Comments
 (0)