Skip to content

Panic in decorrelate optimizer with correlated subquery over UNION #19574

@TCeason

Description

@TCeason

Summary
Databend panics in the decorrelate optimizer when a correlated subquery contains a set operation (UNION or UNION ALL).

The panic is:

panicked at src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_plan.rs:684:59:
called `Option::unwrap()` on a `None` value

Minimal Reproducer

This shorter query reproduces the same panic on the current local server (127.0.0.1:8001):

SELECT *
FROM (VALUES (1)) t(f1)
WHERE EXISTS (
  SELECT 1
  UNION
  SELECT 2 WHERE f1 = 1
);

Observed result:

[1104]called `Option::unwrap()` on a `None` value

The same shape also reproduces with UNION ALL:

SELECT *
FROM (VALUES (1)) t(f1)
WHERE EXISTS (
  SELECT 1
  UNION ALL
  SELECT 2 WHERE f1 = 1
);

Non-Reproducer

Removing the set operation avoids the panic:

SELECT *
FROM (VALUES (1)) t(f1)
WHERE EXISTS (
  SELECT 2 WHERE f1 = 1
);

This succeeds, so the bug is not caused by correlation alone. The trigger is correlation combined with a set-op subquery.

Suspected Root Cause

The panic backtrace points to the decorrelation path:

  • try_decorrelate_subquery
  • flatten_sub_aggregate
  • flatten_sub_union_all

At src/query/sql/src/planner/optimizer/optimizers/operator/decorrelate/flatten_plan.rs:684, the optimizer assumes every correlated column already has a mapping in derived_columns:

let new = *self.derived_columns.get(&old).unwrap();

Based on the reproducer and stack, one UNION branch does not populate that mapping, but the merged correlated column set still expects it, so unwrap() panics.

Trigger Pattern

The trigger appears to be all of:

  1. A correlated subquery.
  2. The subquery is rewritten by decorrelation.
  3. The subquery contains a set operation (UNION or UNION ALL).
  4. At least one set-op branch references an outer column while another branch does not.

The minimal reproducer matches that shape exactly.

Suggested Fix Direction

Two likely fixes:

  1. Make flatten_sub_union_all robust when derived_columns does not contain a correlated column mapping.
  2. Normalize or synthesize correlated columns consistently for every set-op branch before merging branch outputs.

A defensive guard would stop the panic, but the correct fix is to preserve column mapping consistency across all union branches during decorrelation.

Validation Command

Used to verify the reproducer:

bendsql -h 127.0.0.1 -P 8001 -u root -D default -n --output=null --query="SELECT * FROM (VALUES (1)) t(f1) WHERE EXISTS (SELECT 1 UNION SELECT 2 WHERE f1 = 1);"

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: something isn't workingagent-issueAgent-created issue marker

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions