cockroachdb / cockroachdb/cockroach
pg_class.relnatts excludes dropped columns despite retained pg_attribute entries
Nobody has claimed this yet.
- 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.1Docker 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:
- https://docs.cockroachlabs.com/docs/v26.3/pg-catalog
- https://www.postgresql.org/docs/current/catalog-pg-class.html
- https://www.postgresql.org/docs/current/catalog-pg-attribute.html
Jira issue: CRDB-68547
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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