Skip to content

ORCA: fix CTE column-pruning misalignment across consumers - #1883

Open
yjhjstz wants to merge 1 commit into
apache:mainfrom
yjhjstz:cte-multiconsumer-column-pruning
Open

ORCA: fix CTE column-pruning misalignment across consumers#1883
yjhjstz wants to merge 1 commit into
apache:mainfrom
yjhjstz:cte-multiconsumer-column-pruning

Conversation

@yjhjstz

@yjhjstz yjhjstz commented Aug 5, 2026

Copy link
Copy Markdown
Member

When a CTE has multiple consumers requiring different column subsets, the producer's shared-scan output is pruned to the union of all consumers' required columns (CTranslatorDXLToExpr::PruneCTEs). But each consumer independently decided its own output columns in CPhysicalCTEConsumer from its own per-column GetUsage(). A consumer that considers all of its columns used (e.g. SELECT a.*) kept every column with an identity index map, while the producer emitted only the pruned union. The consumer then read the shared tuple by stale positions, producing wrong results (a join key read from the wrong slot -> LEFT JOIN yields NULLs) and "invalid attnum N for relation shareX_refY" during EXPLAIN.

Drive the consumer's kept columns from the producer's finalized used mask (CLogicalCTEProducer::UsedMask) -- the single source of truth -- so every consumer exposes exactly the producer's surviving columns. When the producer was not pruned the mask is NULL and behavior is unchanged.

Add a regression test (cte_prune_multi_consumer) covering multi-consumer CTEs where a SELECT * consumer is referenced directly with a join key. It asserts the EXPLAIN no longer errors and returns correct results; the ORCA path is exercised with shared scans and matches the Postgres planner.

Fixes #ISSUE_Number

What does this PR do?

Type of Change

  • Bug fix (non-breaking change)
  • New feature (non-breaking change)
  • Breaking change (fix or feature with breaking changes)
  • Documentation update

Breaking Changes

Test Plan

  • Unit tests added/updated
  • Integration tests added/updated
  • Passed make installcheck
  • Passed make -C src/test installcheck-cbdb-parallel

Impact

Performance:

User-facing changes:

Dependencies:

Checklist

Additional Context

CI Skip Instructions


When a CTE has multiple consumers requiring different column subsets,
the producer's shared-scan output is pruned to the union of all
consumers' required columns (CTranslatorDXLToExpr::PruneCTEs). But each
consumer independently decided its own output columns in
CPhysicalCTEConsumer from its own per-column GetUsage(). A consumer that
considers all of its columns used (e.g. SELECT a.*) kept every column
with an identity index map, while the producer emitted only the pruned
union. The consumer then read the shared tuple by stale positions,
producing wrong results (a join key read from the wrong slot -> LEFT
JOIN yields NULLs) and "invalid attnum N for relation shareX_refY"
during EXPLAIN.

Drive the consumer's kept columns from the producer's finalized used
mask (CLogicalCTEProducer::UsedMask) -- the single source of truth --
so every consumer exposes exactly the producer's surviving columns.
When the producer was not pruned the mask is NULL and behavior is
unchanged.

Add a regression test (cte_prune_multi_consumer) covering multi-consumer
CTEs where a SELECT * consumer is referenced directly with a join key.
It asserts the EXPLAIN no longer errors and returns correct results;
the ORCA path is exercised with shared scans and matches the Postgres
planner.
@yjhjstz
yjhjstz requested a review from jiaqizho August 5, 2026 04:58
@yjhjstz
yjhjstz marked this pull request as ready for review August 5, 2026 05:14

@jiaqizho jiaqizho left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

CCTEInfo *pcteinfo = COptCtxt::PoctxtFromTLS()->Pcteinfo();
CLogicalCTEProducer *popProducer =
CLogicalCTEProducer::PopConvert(pcteinfo->PexprCTEProducer(m_id)->Pop());
BOOL *producer_umask = popProducer->UsedMask();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Since producer_umask represents the finalized layout and is only read here, declared as const BOOL *?

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.

3 participants