Skip to content

fix(plugin-postgresql): list a partitioned table once and nest its partitions (#1984) - #1989

Merged
datlechin merged 1 commit into
mainfrom
fix/1984-postgres-partition-children
Jul 29, 2026
Merged

fix(plugin-postgresql): list a partitioned table once and nest its partitions (#1984)#1989
datlechin merged 1 commit into
mainfrom
fix/1984-postgres-partition-children

Conversation

@datlechin

Copy link
Copy Markdown
Member

Fixes #1984.

Problem

information_schema.tables is defined as WHERE c.relkind IN ('r','v','f','p') and reports table_type = 'BASE TABLE' for both a partitioned parent (relkind='p') and every one of its partition children (relkind='r'). The table listing had no way to tell them apart, so a table split into hundreds of partitions buried the rest of the schema, and the children also filled up autocomplete, Cmd+K, and the export picker.

Why not relispartition

The issue suggested AND c.relispartition IS NOT TRUE. That column only exists from PostgreSQL 10, and referencing a missing column fails at parse time, which no CASE or version guard inside the statement can rescue. Verified against a live PostgreSQL 9.6.24:

ERROR:  column c.relispartition does not exist

42703 is not in the driver's fallback ladder, so that change would have replaced a cluttered table list with no table list at all on PostgreSQL 9.x.

This uses pg_inherits joined to the parent's relkind instead. pg_inherits, pg_class, pg_namespace, and the relkind column all exist back to PostgreSQL 8, and relkind IN ('p','I') is a value comparison, so on older servers it simply matches nothing, which is correct because they have no declarative partitioning. No version gate and no capability probe are needed.

Rows still come from information_schema.tables, so its privilege filtering (pg_has_role / has_table_privilege / has_any_column_privilege) is preserved. Querying pg_class directly instead would have been a privilege regression: verified on PG 18, a role granted SELECT on one table saw 1 row through information_schema and 9 through a naive pg_class query.

Legacy INHERITS children stay listed on purpose. Their parent is an ordinary table (relkind='r'), and they are independently useful tables rather than one parent's implementation detail.

What changed

  • Query (PostgreSQLSchemaQueries.fetchTables): new includePartitionAwareness flag that labels a parent as PARTITIONED TABLE and drops its children.
  • Fallback ladder (PostgreSQLPluginDriver): the old flat two-arm catch could not express "the same SQLSTATE means a different missing catalog at each rung", and a second 42P01 from the first retry was uncaught. It is now an ordered list, extracted to PostgreSQLTableListingLadder so the ordering is unit-testable. Partition awareness degrades last, since it is the only rung that changes which rows come back rather than which columns.
  • Nesting: a partitioned parent is expandable in the sidebar NSOutlineView and lazily loads its direct partitions on disclosure, recursing for subpartitioned children. Expansion state persists, per the HIG outline-view guidance to retain expansion choices. Loading is lazy by design: DataGrip's partition-nesting regression (DBE-13678) came from eager introspection.
  • Export dialog: fetchTablesForSchema ran its own raw information_schema.tables query, bypassing the plugin, so export would have kept listing every partition. It now calls driver.fetchTables(schema:), which also deletes a hardcoded Oracle SQL branch that was living in a View. fetchTablesForDatabase is deliberately left alone: MySQL's fetchTables(schema:) ignores its schema argument (WHERE TABLE_SCHEMA = DATABASE()), so routing it would return the wrong database's tables.
  • Table count: fetchDatabaseMetadata counted partition children too. Fixed with the same anti-join.

ABI

Additive. scripts/check-pluginkit-abi.sh reports exactly two additions (the fetchPartitions requirement and its default implementation) and zero removals, so no currentPluginKitVersion bump and no plugin re-release. A driver that never implements it resolves through the protocol default, covered by a test. Needs the abi-additive label.

Verification

Against live PostgreSQL 18.4 and 9.6.24 with a fixture covering multi-level subpartitions, a DEFAULT partition, legacy INHERITS, a view, and a materialized view:

Check Result
PG 18 before 4 partition children listed as siblings of orders
PG 18 after children gone, parent labelled PARTITIONED TABLE
Legacy INHERITS child kept
PG 9.6 parses and runs, filters nothing
Privilege filtering preserved (1 row, not 9)
Subpartition recursion grandchild listed under the subpartitioned child
fetchPartitions on an inheritance parent 0 rows
Degraded fallback query reverts cleanly, no pg_catalog reference
Table count 5 vs 9

49 tests pass, 0 failures.

PostgreSQLFetchTablesCommentTests.baseQueryStaysPortable asserted the query contains no pg_catalog.pg_class. It is re-pointed at the fully degraded fallback shape, where that guarantee still has to hold, rather than deleted.

Not covered

  • TimescaleDB chunks. They use legacy inheritance in _timescaledb_internal, a different mechanism this filter deliberately does not touch. Worth a follow-up.
  • A partitioned table in Recents shows the plain table icon, because RecentTableEntry only persists an isView boolean. Materialized views and foreign tables already share that pre-existing limitation.
  • A role granted SELECT on a partition child but not its parent previously saw that child and now sees neither. pgAdmin and DBeaver behave the same way.

Test plan

  1. Connect to PostgreSQL 10+ with a partitioned table.
  2. The parent appears once, with its own icon, and the children are gone.
  3. Expand the parent to see its partitions; expand a subpartitioned one again.
  4. Open a partition; it behaves like any other table.
  5. Confirm the children are absent from autocomplete, Cmd+K, and the export picker.
  6. Collapse and relaunch; expansion state is restored.
  7. On a pre-10 server, the table list still loads.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@datlechin datlechin added the abi-additive PluginKit ABI diff reviewed as additive; no version bump needed label Jul 29, 2026
@mintlify

mintlify Bot commented Jul 29, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jul 29, 2026, 2:33 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@mintlify

mintlify Bot commented Jul 29, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟡 Building Jul 29, 2026, 2:33 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@datlechin
datlechin merged commit c668c7c into main Jul 29, 2026
3 checks passed
@datlechin
datlechin deleted the fix/1984-postgres-partition-children branch July 29, 2026 02:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

abi-additive PluginKit ABI diff reviewed as additive; no version bump needed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PostgreSQL: Partition child tables are displayed as separate tables in schema browser

1 participant