cockroachdb / cockroachdb/cockroach

pg_class.relnatts excludes dropped columns despite retained pg_attribute entries

Open
#175,647 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug O-community X-blathers-triaged
Dominant language
Go
Stars
32.5k
Forks
4.1k
PR merge metrics
PR metrics pending

Description

Describe the problem
Hi, CockroachDB developer. Thanks for reading my report. I find a bug in pg_class.relnatts.
After DROP COLUMN, CockroachDB retains the corresponding pg_attribute row with attisdropped = true and its original attnum, but decreases pg_class.relnatts to the number of live columns.

This is inconsistent with PostgreSQL catalog semantics, where relnatts includes dropped-column placeholders and therefore equals the number of positive-numbered pg_attribute entries.

To reproduce

DROP DATABASE IF EXISTS test_relnatts CASCADE;
CREATE DATABASE test_relnatts;
USE test_relnatts;

CREATE TABLE t0 (c0 INT PRIMARY KEY, c1 INT, c2 INT);
ALTER TABLE t0 DROP COLUMN c2;

SELECT c.relname, c.relnatts, COUNT(a.attnum) AS attr_cnt
FROM pg_catalog.pg_class AS c
LEFT JOIN pg_catalog.pg_attribute AS a
  ON a.attrelid = c.oid AND a.attnum > 0
WHERE c.relname = 't0'
GROUP BY c.oid, c.relname, c.relnatts;
relname | relnatts | attr_cnt
--------+----------+---------
t0      |        2 |        3

SELECT attname, attnum, attisdropped
FROM pg_catalog.pg_attribute
WHERE attrelid = 't0'::regclass AND attnum > 0
ORDER BY attnum;
            attname            | attnum | attisdropped
-------------------------------+--------+---------------
  c0                           |      1 |      f
  c1                           |      2 |      f
  ........pg.dropped.3........ |      3 |      t

Actual behavior
The dropped column remains as ........pg.dropped.3........ with attnum = 3 and attisdropped = true, while relnatts is 2.

relname | relnatts | attr_cnt
--------+----------+---------
t0      |        2 |        3

Expected behavior
pg_class.relnatts should be 3, matching the three positive-numbered pg_attribute entries, including the dropped-column placeholder:

relname | relnatts | attr_cnt
--------+----------+---------
t0      |        3 |        3

Environment

  • CockroachDB: CCL v26.3.1, built 2026-08-24
  • Deployment: official cockroachdb/cockroach:v26.3.1 Docker image
  • Host: Linux x86-64, Ubuntu 20.04
  • Clients: built-in CockroachDB SQL CLI and JDBC

Additional context
CockroachDB documents that its pg_catalog tables correspond to PostgreSQL system catalogs. In PostgreSQL, pg_class.relnatts includes dropped-column placeholders, which remain in pg_attribute with attisdropped = true. Therefore, PostgreSQL returns:

relname | relnatts | attr_cnt
--------+----------+---------
t0      |        3 |        3

CockroachDB instead returns 2 | 3, making pg_class inconsistent with pg_attribute. This may cause PostgreSQL-compatible schema-introspection tools, drivers, ORMs, migration utilities, and catalog-consistency checks to miscount columns or report malformed catalog metadata after a column is dropped.

References:

Jira issue: CRDB-68547

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by running the supplied SQL reproduction and compare pg_class.relnatts with the positive-numbered pg_attribute rows after DROP COLUMN. Trace the implementation of these pg_catalog values and check how PostgreSQL handles dropped-column placeholders. Done means relnatts reports 3 for the example and remains consistent with the retained pg_attribute entries.

Written by the indexing model from the issue text.

Assessment

Tech stack
sql
Domain
databases
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.