Skip to content

Placeholder datatype not inferred for Expr::InSubquery #15979

@kczimm

Description

@kczimm

Describe the bug

Parameterized queries with placeholders before IN <subquery> are not inferred. For example,

SELECT * FROM my_table WHERE $1 IN (SELECT A FROM my_table WHERE B > 3);

To Reproduce

// Schema for my_table: A (Int32), B (Int32)
let schema = Arc::new(Schema::new(vec![
    Field::new("A", DataType::Int32, true),
    Field::new("B", DataType::Int32, true),
]));

let source = Arc::new(LogicalTableSource::new(schema.clone()));

// SELECT * FROM my_table WHERE $1 IN (SELECT A FROM my_table WHERE B > 3);
let placeholder = Expr::Placeholder(Placeholder {
    id: "$1".to_string(),
    data_type: None,
});

// Subquery: SELECT A FROM my_table WHERE B > 3
let subquery_filter = Expr::BinaryExpr(BinaryExpr {
    left: Box::new(col("B")),
    op: Operator::Gt,
    right: Box::new(Expr::Literal(ScalarValue::Int32(Some(3)))),
});

let subquery_scan = LogicalPlan::TableScan(TableScan {
    table_name: TableReference::from("my_table"),
    source,
    projected_schema: Arc::new(DFSchema::try_from(schema.clone())?),
    projection: None,
    filters: vec![subquery_filter.clone()],
    fetch: None,
});

let projected_fields = vec![Field::new("A", DataType::Int32, true)];
let projected_schema = Arc::new(DFSchema::from_unqualified_fields(
    projected_fields.into(),
    Default::default(),
)?);

let subquery = Subquery {
    subquery: Arc::new(LogicalPlan::Projection(Projection {
        expr: vec![col("A")],
        input: Arc::new(subquery_scan),
        schema: projected_schema,
    })),
    outer_ref_columns: vec![],
};

let in_subquery = Expr::InSubquery(InSubquery {
    expr: Box::new(placeholder),
    subquery,
    negated: false,
});

let df_schema = DFSchema::try_from(schema)?;

let (inferred_expr, contains_placeholder) =
    in_subquery.infer_placeholder_types(&df_schema)?;

assert!(
    contains_placeholder,
    "Expression should contain a placeholder"
);

match inferred_expr {
    Expr::InSubquery(in_subquery) => match *in_subquery.expr {
        Expr::Placeholder(placeholder) => {
            assert_eq!(
                placeholder.data_type,
                Some(DataType::Int32),
                "Placeholder $1 should infer Int32"
            );
        }
        _ => panic!("Expected Placeholder expression in InSubquery"),
    },
    _ => panic!("Expected InSubquery expression"),
}
assertion `left == right` failed: Placeholder $1 should infer Int32
  left: None
 right: Some(Int32)

Expected behavior

Assertions pass.

Additional context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions