Skip to content

BETWEEN optimization in SQL codegen never triggers due to span comparison #5737

@queelius

Description

@queelius

Bug Description

The try_into_between function in prqlc/prqlc/src/sql/gen_expr.rs is designed to optimize a >= low AND a <= high into a BETWEEN low AND high. However, this optimization never triggers because the equality check a_l == b_l compares rq::Expr values including their span field.

Since the two references to column a in a >= 5 && a <= 10 originate from different source positions, they have different span values, causing the equality check to always fail.

Reproduction

from t | filter (a >= 5 && a <= 10)

Expected output:

SELECT * FROM t WHERE a BETWEEN 5 AND 10

Actual output:

SELECT * FROM t WHERE a >= 5 AND a <= 10

Root Cause

rq::Expr (in prqlc/prqlc/src/ir/rq/expr.rs) derives PartialEq, which compares both kind and span:

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Expr {
    pub kind: ExprKind,
    pub span: Option<Span>,
}

In try_into_between, the check if a_l == b_l compares the full Expr including spans. The two column references to a have the same CId (same column) but different Span values (different source positions), so the comparison fails.

Suggested Fix

Compare only the kind field instead of the full Expr:

// Before:
if a_l == b_l {

// After:
if a_l.kind == b_l.kind {

Impact

This is not a correctness bug -- the generated SQL is semantically equivalent. It's a dead-code / missed-optimization bug. The BETWEEN optimization code has likely never worked since it was written.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions