Skip to content

[dbolympics] SanityCheckPlan error when sorting by a function of a product above a projection with a computed column #26430

Open

Description

@JoeryH

Describe the bug

A query that sorts by a scalar function of a product (for example abs(a * b)) fails planning with a SanityCheckPlan error. This happens when the sort's input is a projection with a computed column, above a round-robin repartition.

The sort-preserving merge rejects its input, although the input's ordering is the same as the requirement:

SanityCheckPlan
caused by
Error during planning: Plan: ["SortPreservingMergeExec: [abs(a@0 * b@1) ASC NULLS LAST]", "  SortExec: expr=[abs(a@0 * b@1) ASC NULLS LAST], preserve_partitioning=[true]", "    ProjectionExec: expr=[a@0 as a, b@1 as b, c@2 + 1 as m]", "      RepartitionExec: partitioning=RoundRobinBatch(2), input_partitions=1", "        FilterExec: a@0 > 0", "          DataSourceExec: partitions=1, partition_sizes=[1]"] does not satisfy order requirements: [abs(a@0 * b@1) ASC NULLS LAST]. Child-0 order: [[abs(a@0 * b@1) ASC NULLS LAST]]

To Reproduce

In datafusion-cli at main (63a2801c1). The error is the same on 54.1.0:

set datafusion.execution.target_partitions = 2;
create table t(a double, b double, c double) as values (1, 2, 3), (4, -5, 6);

select a, b, c + 1 as m from t where a > 0 order by abs(a * b);

The same table and settings, with one change to the query each time:

Query Result
select a, b, c + 1 as m from t where a > 0 order by abs(a * b) error
... order by abs(a / b) error
... order by abs(a * 2) error
... order by sqrt(a * b) error
... order by abs(a * b) limit 1 (TopK) error
select a, b, -c as m ... order by abs(a * b) error
... order by abs(a + b) ok
... order by abs(a - b) ok
... order by a * b ok
... order by -(a * b) ok
... order by (a * b) + 1 ok
select a, b ... order by abs(a * b) (no computed column) ok
select a, b, c as m ... order by abs(a * b) (plain column) ok
select a, b, 1 as m ... order by abs(a * b) (literal) ok
... from t order by abs(a * b) (no filter, no repartition) ok

So the failure needs all of these:

  • a scalar function over * or /
  • a computed column in the projection below the sort
  • a repartition below that projection

Expected behavior

The query plans and returns the two rows ordered by abs(a * b).

Additional context

This is different from #26391 and #26283: no sort key here is a constant. #25921 (fixed by #25922) is in the same area, EquivalenceGroup projection, but main includes that fix and still fails.

A workaround is to project the sort key and order by its alias:

select a, b, c + 1 as m, abs(a * b) as k from t where a > 0 order by k;

Activity

  1. 0xamlab commented on Oct 17, 2026

    @0xamlab

    I reproduced this at 484183d with datafusion-cli on the two-row table; the exact same SanityCheckPlan error fires. Instrumenting EquivalenceProperties::ordering_satisfy_requirement shows get_expr_properties(abs(ab)) failing with NotImplemented("Can't create a zero scalar from data_type "Null""). That error originates at datafusion/functions/src/math/abs.rs:179 (Interval::make_zero(&range.lower().data_type())?). Since BinaryExpr::get_properties returns ExprProperties::new_unknown() for Multiply/Divide, abs receives a Null interval and the error short-circuits before the existing [[abs(ab)]] ordering equivalence can satisfy the requirement.

  2. jayzhan211 commented on Oct 24, 2026

    @jayzhan211
    Contributor

    Another way to hit this, with the same cause: abs, sqrt, ln, log2 or cosh over a CASE, which is what COALESCE becomes after simplification. It needs no projection or repartition, and fails with one partition:

    create table t (a bigint, b bigint);
    select row_number() over (order by abs(coalesce(b, 0))) from t;
    SanityCheckPlan
    caused by
    Error during planning: ... does not satisfy order requirements: [abs(CASE WHEN b@0 IS NOT NULL THEN b@0 ELSE 0 END) ASC NULLS LAST]. Child-0 order: [[abs(CASE WHEN b@0 IS NOT NULL THEN b@0 ELSE 0 END) ASC NULLS LAST]]
    

    CaseExpr doesn't implement get_properties, so like a * b it reports the unknown range of type Null, and abs fails to build its zero. Giving * and / real ranges would not fix this one.

    Fixing it where the error is dropped covers both. In update_properties (equivalence/properties/mod.rs), a failing get_properties returns early through ?, so the ordering lookup right below it never runs, although that lookup already knows abs(...) is sorted. I tried this change on main:

    node.data = node
        .expr
        .get_properties(&children_props)
        .unwrap_or_else(|_| ExprProperties::new_unknown());

    With it, the query above, every failing query in this issue's table, and the same queries with ln, log2 and cosh plan and return their rows in the right order. (sqrt(a * b) then stops at execution with cannot take square root of a negative number on the row where a * b is negative.) All sqllogictest files pass.

    This also breaks query q121 of the dbolympics benchmark (#26661).

  3. changed the title [-]SanityCheckPlan error when sorting by a function of a product above a projection with a computed column[/-] [+][dbolympics] SanityCheckPlan error when sorting by a function of a product above a projection with a computed column[/+] on Oct 24, 2026
  4. alamb commented on Oct 24, 2026

    @alamb
    Contributor

    Affects DB Olympics, see: #26661

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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