Skip to content

Commit eacdf79

Browse files
kczimmJeadie
authored andcommitted
Infer placeholder datatype for Expr::InSubquery (#80)
UPSTREAM NOTE: Upstream PR has been created but not merged yet. Should be available in DF49 apache#15980
1 parent e026565 commit eacdf79

File tree

1 file changed

+104
-1
lines changed

1 file changed

+104
-1
lines changed

datafusion/expr/src/expr.rs

Lines changed: 104 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1970,6 +1970,27 @@ impl Expr {
19701970
| Expr::SimilarTo(Like { expr, pattern, .. }) => {
19711971
rewrite_placeholder(pattern.as_mut(), expr.as_ref(), schema)?;
19721972
}
1973+
Expr::InSubquery(InSubquery {
1974+
expr,
1975+
subquery,
1976+
negated: _,
1977+
}) => {
1978+
let subquery_schema = subquery.subquery.schema();
1979+
let fields = subquery_schema.fields();
1980+
1981+
// only supports subquery with exactly 1 field
1982+
if let [first_field] = &fields[..] {
1983+
rewrite_placeholder(
1984+
expr.as_mut(),
1985+
&Expr::Column(Column {
1986+
relation: None,
1987+
name: first_field.name().clone(),
1988+
spans: Spans::new(),
1989+
}),
1990+
schema,
1991+
)?;
1992+
}
1993+
}
19731994
Expr::Placeholder(_) => {
19741995
has_placeholder = true;
19751996
}
@@ -3421,7 +3442,8 @@ mod test {
34213442
use crate::expr_fn::col;
34223443
use crate::{
34233444
case, lit, qualified_wildcard, wildcard, wildcard_with_options, ColumnarValue,
3424-
ScalarFunctionArgs, ScalarUDF, ScalarUDFImpl, Volatility,
3445+
LogicalPlan, LogicalTableSource, Projection, ScalarFunctionArgs, ScalarUDF,
3446+
ScalarUDFImpl, TableScan, Volatility,
34253447
};
34263448
use arrow::datatypes::{Field, Schema};
34273449
use sqlparser::ast;
@@ -3483,6 +3505,87 @@ mod test {
34833505
}
34843506
}
34853507

3508+
#[test]
3509+
fn infer_placeholder_in_subquery() -> Result<()> {
3510+
// Schema for my_table: A (Int32), B (Int32)
3511+
let schema = Arc::new(Schema::new(vec![
3512+
Field::new("A", DataType::Int32, true),
3513+
Field::new("B", DataType::Int32, true),
3514+
]));
3515+
3516+
let source = Arc::new(LogicalTableSource::new(schema.clone()));
3517+
3518+
// Simulate: SELECT * FROM my_table WHERE $1 IN (SELECT A FROM my_table WHERE B > 3);
3519+
let placeholder = Expr::Placeholder(Placeholder {
3520+
id: "$1".to_string(),
3521+
data_type: None,
3522+
});
3523+
3524+
// Subquery: SELECT A FROM my_table WHERE B > 3
3525+
let subquery_filter = Expr::BinaryExpr(BinaryExpr {
3526+
left: Box::new(col("B")),
3527+
op: Operator::Gt,
3528+
right: Box::new(Expr::Literal(ScalarValue::Int32(Some(3)))),
3529+
});
3530+
3531+
let subquery_scan = LogicalPlan::TableScan(TableScan {
3532+
table_name: TableReference::from("my_table"),
3533+
source,
3534+
projected_schema: Arc::new(DFSchema::try_from(schema.clone())?),
3535+
projection: None,
3536+
filters: vec![subquery_filter.clone()],
3537+
fetch: None,
3538+
});
3539+
3540+
let projected_fields = vec![Field::new("A", DataType::Int32, true)];
3541+
let projected_schema = Arc::new(DFSchema::from_unqualified_fields(
3542+
projected_fields.into(),
3543+
Default::default(),
3544+
)?);
3545+
3546+
let subquery = Subquery {
3547+
subquery: Arc::new(LogicalPlan::Projection(Projection {
3548+
expr: vec![col("A")],
3549+
input: Arc::new(subquery_scan),
3550+
schema: projected_schema,
3551+
})),
3552+
outer_ref_columns: vec![],
3553+
spans: Spans::new(),
3554+
};
3555+
3556+
let in_subquery = Expr::InSubquery(InSubquery {
3557+
expr: Box::new(placeholder),
3558+
subquery,
3559+
negated: false,
3560+
});
3561+
3562+
let df_schema = DFSchema::try_from(schema)?;
3563+
3564+
let (inferred_expr, contains_placeholder) =
3565+
in_subquery.infer_placeholder_types(&df_schema)?;
3566+
3567+
assert!(
3568+
contains_placeholder,
3569+
"Expression should contain a placeholder"
3570+
);
3571+
3572+
match inferred_expr {
3573+
Expr::InSubquery(in_subquery) => match *in_subquery.expr {
3574+
Expr::Placeholder(placeholder) => {
3575+
assert_eq!(
3576+
placeholder.data_type,
3577+
Some(DataType::Int32),
3578+
"Placeholder $1 should infer Int32"
3579+
);
3580+
}
3581+
_ => panic!("Expected Placeholder expression in InSubquery"),
3582+
},
3583+
_ => panic!("Expected InSubquery expression"),
3584+
}
3585+
3586+
Ok(())
3587+
}
3588+
34863589
#[test]
34873590
fn infer_placeholder_like_and_similar_to() {
34883591
// name LIKE $1

0 commit comments

Comments
 (0)