Skip to content

Placeholder datatype not inferred for Expr::Comparison (ANY/ALL) #22475

@HairstonE

Description

@HairstonE

Describe the bug

Parameterized queries with placeholders on the LHS of = ANY <subquery>,
<> ALL <subquery> (and other quantified comparison operators) are not
inferred. For example,

SELECT * FROM my_table WHERE $1 = ANY (SELECT A FROM my_table WHERE B > 3);
SELECT * FROM my_table WHERE $1 <> ALL (SELECT A FROM my_table WHERE B > 3);

To Reproduce

To reproduce ANY:

      // WHERE $1 = ANY (SELECT a FROM t) -- parallel to infer_placeholder_in_subquery
      let subquery_field = Field::new("a", DataType::Int32, false);
      let subquery_schema = Arc::new(
          DFSchema::from_unqualified_fields(
              vec![subquery_field].into(),
              Default::default(),
          )
          .unwrap(),
      );
      let subquery = Subquery {
          subquery: Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
              produce_one_row: false,
              schema: subquery_schema,
          })),
          outer_ref_columns: vec![],
          spans: Spans::new(),
      };

      let set_cmp = Expr::SetComparison(SetComparison {
          expr: Box::new(Expr::Placeholder(Placeholder {
              id: "$1".to_string(),
              field: None,
          })),
          subquery,
          op: Operator::Eq,
          quantifier: SetQuantifier::Any,
      });

      let outer_schema = DFSchema::empty();
      let (inferred_expr, contains_placeholder) =
          set_cmp.infer_placeholder_types(&outer_schema).unwrap();

      assert!(contains_placeholder);

      match inferred_expr {
          Expr::SetComparison(sc) => match *sc.expr {
              Expr::Placeholder(p) => {
                  let inferred = p.field.expect("placeholder field should be Int32");
                  assert_eq!(inferred.data_type(), &DataType::Int32);
                  assert!(inferred.is_nullable());
              }
              _ => panic!("Expected Placeholder expression in SetComparison"),
          },
          _ => panic!("Expected SetComparison expression"),
      }
  }

To reproduce ALL:

      // WHERE $1 <> ALL (SELECT a FROM t)
      // ALL goes through the same `SetComparison` Expr variant as ANY;
      // infer_placeholder_types has no SetComparison arm, so the
      // placeholder type is left unset regardless of quantifier.
      let subquery_field = Field::new("a", DataType::Int32, false);
      let subquery_schema = Arc::new(
          DFSchema::from_unqualified_fields(
              vec![subquery_field].into(),
              Default::default(),
          )
          .unwrap(),
      );
      let subquery = Subquery {
          subquery: Arc::new(LogicalPlan::EmptyRelation(EmptyRelation {
              produce_one_row: false,
              schema: subquery_schema,
          })),
          outer_ref_columns: vec![],
          spans: Spans::new(),
      };

      let set_cmp = Expr::SetComparison(SetComparison {
          expr: Box::new(Expr::Placeholder(Placeholder {
              id: "$1".to_string(),
              field: None,
          })),
          subquery,
          op: Operator::NotEq,
          quantifier: SetQuantifier::All,
      });

      let outer_schema = DFSchema::empty();
      let (inferred_expr, contains_placeholder) =
          set_cmp.infer_placeholder_types(&outer_schema).unwrap();

      assert!(contains_placeholder);

      match inferred_expr {
          Expr::SetComparison(sc) => {
              assert_eq!(sc.quantifier, SetQuantifier::All);
              match *sc.expr {
                  Expr::Placeholder(p) => {
                      let inferred =
                          p.field.expect("placeholder field should be Int32");
                      assert_eq!(inferred.data_type(), &DataType::Int32);
                      assert!(inferred.is_nullable());
                  }
                  _ => panic!("Expected Placeholder expression in SetComparison"),
              }
          }
          _ => panic!("Expected SetComparison expression"),
      }
  }
---- infer_placeholder_set_comparison_any stdout ----
  panicked at expr.rs:3991:44: placeholder field should be Int32

  ---- infer_placeholder_set_comparison_all stdout ----
  panicked at expr.rs:4046:37: placeholder field should be Int32

Expected behavior

Assertions should pass.

Additional context

Issue was prompted by comments on this PR

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No fields configured for Bug.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions