Skip to content

branch-4.0: [fix](nereids) Allocate fresh ExprId for constants when pushing project into Union #62296#63025

Open
yujun777 wants to merge 2 commits intoapache:branch-4.0from
yujun777:pick_62296_to_upstream_branch-4.0
Open

branch-4.0: [fix](nereids) Allocate fresh ExprId for constants when pushing project into Union #62296#63025
yujun777 wants to merge 2 commits intoapache:branch-4.0from
yujun777:pick_62296_to_upstream_branch-4.0

Conversation

@yujun777
Copy link
Copy Markdown
Contributor

@yujun777 yujun777 commented May 6, 2026

cherry pick from #62296

…ct into Union (apache#62296)

### What problem does this PR solve?

Issue Number: close apache#62294

Problem Summary:

When `PushProjectIntoUnion` folds a parent `Project`'s expression into a
`LogicalUnion`'s `constantExprsList`, the outer `Alias` of a
non-`SlotReference` project expression is preserved by
`ExpressionUtils.replaceNameExpression`. Its `ExprId` then collides with
the new UNION output `ExprId` (which comes from the parent project's
output `Alias`) and is reused across every constant row of the same
column. Downstream rules such as `PushDownFilterThroughSetOperation`
rely on the invariant that each `constantExprsList` row carries
`NamedExpression`s whose `ExprId`s are distinct from the UNION output
and from each other across rows; the collision causes them to
mis-rewrite the plan and return wrong results, e.g.

```sql
WITH tbl0(n) AS (SELECT 1 UNION ALL SELECT 3 UNION ALL SELECT NULL),
     tbl1(n) AS (SELECT 2 UNION ALL SELECT NULL UNION ALL SELECT 1)
SELECT (n*2) AS n FROM tbl0
INTERSECT
SELECT (n*2) AS n FROM tbl1;
```

`PushProjectThroughUnion` has the same class of bug in its mixed-union
constant-row branch: when `MergeOneRowRelationIntoUnion` folds a
`LogicalOneRowRelation` into the union's `constantExprsList`, an outer
`Alias(Cast(slot))` project survives `outerProject.rewriteUp` with its
parent `ExprId` intact, and then the same `ExprId` is reused as the new
UNION output via `project.toSlot()`. The plan-level invariant is broken
even though no current downstream rule appears to mis-handle the
specific shape today.

Fix:
- `PushProjectIntoUnion`: after folding the substituted expression,
re-wrap the result in a fresh `Alias` so each constant cell receives a
new unique `ExprId`. Qualifier and name from the folded `Alias` are
preserved. The `SlotReference` branch is left unchanged because it
already returns the original `NamedExpression` from `constExprs` whose
`ExprId`s are row-distinct and not equal to the UNION output `ExprId`.
- `PushProjectThroughUnion`: same treatment for the constant-row
non-Slot branch — re-wrap the rewritten `Alias` to allocate a fresh
`ExprId`.

Introduced by apache#39450 (closest commit touching the relevant lines; the
file `PushProjectIntoUnion` was originally added by apache#27947).

### Release note

Fix wrong results for INTERSECT/EXCEPT/UNION over constant rows when the
projection contains expressions such as `((col*2) AS col)`, and harden
the parallel `PushProjectThroughUnion` rule against the same class of
ExprId collision.


Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@yujun777
Copy link
Copy Markdown
Contributor Author

yujun777 commented May 6, 2026

run buildall

@hello-stephen
Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@yujun777
Copy link
Copy Markdown
Contributor Author

yujun777 commented May 6, 2026

run buildall

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants