Skip to content

fix(orca): merge colid->attno mapping in CStatistics::AppendStats to avoid extended-stats crash - #1966

Open
yjhjstz wants to merge 1 commit into
apache:mainfrom
yjhjstz:fix/orca-extstats-appendstats-attno
Open

fix(orca): merge colid->attno mapping in CStatistics::AppendStats to avoid extended-stats crash#1966
yjhjstz wants to merge 1 commit into
apache:mainfrom
yjhjstz:fix/orca-extstats-appendstats-attno

Conversation

@yjhjstz

@yjhjstz yjhjstz commented Sep 7, 2026

Copy link
Copy Markdown
Member

When a memo group's cached statistics lack columns needed by a later derivation request (e.g. a ROLLUP expanded into a CTE whose consumers request different column sets), the missing columns are derived separately and merged via CStatistics::AppendStats(). That merge copied histograms and widths only, so the colid -> attno mapping (added for extended statistics) diverged from the histogram map: a column could have a histogram but no attno entry.

ApplyCorrelatedStatsToScaleFactorFilterCalculation() then dereferenced the result of the attno lookup without a null check and crashed the coordinator with SIGSEGV whenever the table had any extended statistics object with stored data and a filter referenced one of the appended columns (e.g. TPC-DS Q67 after CREATE STATISTICS (ndistinct) on item/date_dim). Reproduced on main with a cassert build: colid 11 had a histogram (5 entries) but the attno map only held 4 entries, attnum was NULL at CExtendedStatsProcessor.cpp:280. This is the same class of bug as the CTE remapping fix in 124a048e8c6 (gpdb#16212), which repaired CopyStatsWithRemap() but not AppendStats().

Fix both layers:

  • CStatistics::AppendStats() now also merges the colid -> attno mapping (copy-on-write, since the mapping is shared by refcount across stats objects, see ScaleStats()) and adopts the input's extended-stats info when none is set, restoring the invariant that every column with a histogram has an attno entry.

  • CExtendedStatsProcessor now null-checks the attno and histogram lookups and skips clauses it cannot translate, falling back to the independence assumption, matching what ApplyCorrelatedStatsToNDistinctCalculation() already does. Also bail out gracefully if no ndistinct item matches the attribute set.

  • CExtendedStatsProcessor also skips system columns (attno <= 0): extended statistics never cover them, and feeding a negative attno into CBitSet::ExchangeSet() would convert it to a huge unsigned bit index. The backend rejects these clauses too (dependency_is_compatible_clause()).

Add a regression test with the minimized reproduction: a ROLLUP over a join where the dimension table has ndistinct extended statistics and the filter column is appended to the scan group's stats after the initial derivation. Verified the gporca test passes with both optimizer=on and optimizer=off answer files.

Ported from warehouse-pg/warehouse-pg#251.

Fixes #1949

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


…avoid extended-stats crash

When a memo group's cached statistics lack columns needed by a later
derivation request (e.g. a ROLLUP expanded into a CTE whose consumers
request different column sets), the missing columns are derived
separately and merged via CStatistics::AppendStats(). That merge copied
histograms and widths only, so the colid -> attno mapping (added for
extended statistics) diverged from the histogram map: a column could
have a histogram but no attno entry.

ApplyCorrelatedStatsToScaleFactorFilterCalculation() then dereferenced
the result of the attno lookup without a null check and crashed the
coordinator with SIGSEGV whenever the table had any extended statistics
object with stored data and a filter referenced one of the appended
columns (e.g. TPC-DS Q67 after CREATE STATISTICS (ndistinct) on
item/date_dim). Reproduced on main with a cassert build: colid 11 had a
histogram (5 entries) but the attno map only held 4 entries, attnum was
NULL at CExtendedStatsProcessor.cpp:280. This is the same class of bug
as the CTE remapping fix in 124a048e8c6 (gpdb#16212), which repaired
CopyStatsWithRemap() but not AppendStats().

Fix both layers:

* CStatistics::AppendStats() now also merges the colid -> attno mapping
  (copy-on-write, since the mapping is shared by refcount across stats
  objects, see ScaleStats()) and adopts the input's extended-stats info
  when none is set, restoring the invariant that every column with a
  histogram has an attno entry.

* CExtendedStatsProcessor now null-checks the attno and histogram
  lookups and skips clauses it cannot translate, falling back to the
  independence assumption, matching what
  ApplyCorrelatedStatsToNDistinctCalculation() already does. Also bail
  out gracefully if no ndistinct item matches the attribute set.

* CExtendedStatsProcessor also skips system columns (attno <= 0):
  extended statistics never cover them, and feeding a negative attno
  into CBitSet::ExchangeSet() would convert it to a huge unsigned bit
  index. The backend rejects these clauses too
  (dependency_is_compatible_clause()).

Add a regression test with the minimized reproduction: a ROLLUP over a
join where the dimension table has ndistinct extended statistics and
the filter column is appended to the scan group's stats after the
initial derivation. Verified the gporca test passes with both
optimizer=on and optimizer=off answer files.

Ported from warehouse-pg/warehouse-pg#251.

Co-authored-by: Junfeng Yang <junfengyang@link.cuhk.edu.hk>
@yjhjstz
yjhjstz marked this pull request as draft September 7, 2026 01:41
@yjhjstz
yjhjstz marked this pull request as ready for review September 7, 2026 16:34
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.

[Bug] ORCA: QD segfault in CExtendedStatsProcessor when extended statistics (dependencies) do not cover all filtered columns

1 participant