Skip to content

Commit 0df015e

Browse files
kczimmsgrebnov
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 984f1b6 commit 0df015e

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
@@ -1775,6 +1775,27 @@ impl Expr {
17751775
| Expr::SimilarTo(Like { expr, pattern, .. }) => {
17761776
rewrite_placeholder(pattern.as_mut(), expr.as_ref(), schema)?;
17771777
}
1778+
Expr::InSubquery(InSubquery {
1779+
expr,
1780+
subquery,
1781+
negated: _,
1782+
}) => {
1783+
let subquery_schema = subquery.subquery.schema();
1784+
let fields = subquery_schema.fields();
1785+
1786+
// only supports subquery with exactly 1 field
1787+
if let [first_field] = &fields[..] {
1788+
rewrite_placeholder(
1789+
expr.as_mut(),
1790+
&Expr::Column(Column {
1791+
relation: None,
1792+
name: first_field.name().clone(),
1793+
spans: Spans::new(),
1794+
}),
1795+
schema,
1796+
)?;
1797+
}
1798+
}
17781799
Expr::Placeholder(_) => {
17791800
has_placeholder = true;
17801801
}
@@ -3198,7 +3219,8 @@ mod test {
31983219
use crate::expr_fn::col;
31993220
use crate::{
32003221
case, lit, qualified_wildcard, wildcard, wildcard_with_options, ColumnarValue,
3201-
ScalarFunctionArgs, ScalarUDF, ScalarUDFImpl, Volatility,
3222+
LogicalPlan, LogicalTableSource, Projection, ScalarFunctionArgs, ScalarUDF,
3223+
ScalarUDFImpl, TableScan, Volatility,
32023224
};
32033225
use arrow::datatypes::{Field, Schema};
32043226
use sqlparser::ast;
@@ -3260,6 +3282,87 @@ mod test {
32603282
}
32613283
}
32623284

3285+
#[test]
3286+
fn infer_placeholder_in_subquery() -> Result<()> {
3287+
// Schema for my_table: A (Int32), B (Int32)
3288+
let schema = Arc::new(Schema::new(vec![
3289+
Field::new("A", DataType::Int32, true),
3290+
Field::new("B", DataType::Int32, true),
3291+
]));
3292+
3293+
let source = Arc::new(LogicalTableSource::new(schema.clone()));
3294+
3295+
// Simulate: SELECT * FROM my_table WHERE $1 IN (SELECT A FROM my_table WHERE B > 3);
3296+
let placeholder = Expr::Placeholder(Placeholder {
3297+
id: "$1".to_string(),
3298+
data_type: None,
3299+
});
3300+
3301+
// Subquery: SELECT A FROM my_table WHERE B > 3
3302+
let subquery_filter = Expr::BinaryExpr(BinaryExpr {
3303+
left: Box::new(col("B")),
3304+
op: Operator::Gt,
3305+
right: Box::new(Expr::Literal(ScalarValue::Int32(Some(3)))),
3306+
});
3307+
3308+
let subquery_scan = LogicalPlan::TableScan(TableScan {
3309+
table_name: TableReference::from("my_table"),
3310+
source,
3311+
projected_schema: Arc::new(DFSchema::try_from(schema.clone())?),
3312+
projection: None,
3313+
filters: vec![subquery_filter.clone()],
3314+
fetch: None,
3315+
});
3316+
3317+
let projected_fields = vec![Field::new("A", DataType::Int32, true)];
3318+
let projected_schema = Arc::new(DFSchema::from_unqualified_fields(
3319+
projected_fields.into(),
3320+
Default::default(),
3321+
)?);
3322+
3323+
let subquery = Subquery {
3324+
subquery: Arc::new(LogicalPlan::Projection(Projection {
3325+
expr: vec![col("A")],
3326+
input: Arc::new(subquery_scan),
3327+
schema: projected_schema,
3328+
})),
3329+
outer_ref_columns: vec![],
3330+
spans: Spans::new(),
3331+
};
3332+
3333+
let in_subquery = Expr::InSubquery(InSubquery {
3334+
expr: Box::new(placeholder),
3335+
subquery,
3336+
negated: false,
3337+
});
3338+
3339+
let df_schema = DFSchema::try_from(schema)?;
3340+
3341+
let (inferred_expr, contains_placeholder) =
3342+
in_subquery.infer_placeholder_types(&df_schema)?;
3343+
3344+
assert!(
3345+
contains_placeholder,
3346+
"Expression should contain a placeholder"
3347+
);
3348+
3349+
match inferred_expr {
3350+
Expr::InSubquery(in_subquery) => match *in_subquery.expr {
3351+
Expr::Placeholder(placeholder) => {
3352+
assert_eq!(
3353+
placeholder.data_type,
3354+
Some(DataType::Int32),
3355+
"Placeholder $1 should infer Int32"
3356+
);
3357+
}
3358+
_ => panic!("Expected Placeholder expression in InSubquery"),
3359+
},
3360+
_ => panic!("Expected InSubquery expression"),
3361+
}
3362+
3363+
Ok(())
3364+
}
3365+
32633366
#[test]
32643367
fn infer_placeholder_like_and_similar_to() {
32653368
// name LIKE $1

0 commit comments

Comments
 (0)