#20509·databend

bug: cloned scans lose predicate pushdown during decorrelation

Author: dqhl76Created Sep 16, 2026Updated Sep 17, 2026
LabelsC-bug

Version

v1.2.925-patch-13 (5de2db39c045d9d444b13f8c6e55d8f4906976dc), single node, default optimizer settings.

What's wrong?

Decorrelating a scalar subquery clones the outer scan, but the cloned scan loses predicate pushdown. The filter remains above the scan, preventing storage pruning and potentially causing a full scan.

Reproduction

An empty table is sufficient:

sql
CREATE TABLE repro (a INT);

EXPLAIN
SELECT o.a,
       (SELECT COUNT(*) FROM repro AS i WHERE i.a + 1 = o.a) AS cnt
FROM repro AS o
WHERE o.a > 1;

The original outer scan pushes down a > 1:

scan id: 0
push downs: [filters: [is_true(repro.a (#0) > 1)], limit: NONE]

The cloned outer scan does not:

Filter
├── filters: [is_true(a (#4) > 1)]
└── TableScan
    ├── scan id: 2
    └── push downs: [filters: [true], limit: NONE]

Expected: the cloned scan also pushes down a > 1.

Replacing i.a + 1 = o.a with i.a = o.a produces only two scans and avoids the cloned branch.

Cause

clone_outer_scan registers cloned base columns as DerivedColumn. The filter pushdown rule rejects predicates referencing these columns.

Preserving base-column metadata with fresh column and scan IDs should allow normal predicate pushdown on the cloned scan.