Skip to content

fix: emit PARTITION OF for partition children on create path (#496)#498

Merged
tianzhou merged 6 commits into
mainfrom
fix/issue-496-partition-of-create-path
Jul 3, 2026
Merged

fix: emit PARTITION OF for partition children on create path (#496)#498
tianzhou merged 6 commits into
mainfrom
fix/issue-496-partition-of-create-path

Conversation

@tianzhou

@tianzhou tianzhou commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #496. Partition children were rendered as standalone CREATE TABLE with inlined columns, dropping the PARTITION OF ... FOR VALUES attachment clause. The parent ended up with zero attached partitions and could not route inserts.

  • Add PartitionOf, PartitionOfSchema, PartitionBound fields to ir.Table
  • Populate them from pg_inherits / pg_get_expr(relpartbound) during catalog inspection
  • generateTableSQL() emits CREATE TABLE IF NOT EXISTS <child> PARTITION OF <parent> <bound>; when the table is a partition child
  • Add partition parent→child edges to topological sort so parents are always created before children
  • Normalize PartitionOfSchema in the temp→target schema replacement pass

Test plan

  • New diff test: issue_496_partition_of_create_path — LIST partitioning with 3 children (2 value-based + DEFAULT), from-scratch create
  • Integration test passes including idempotency (re-plan after apply → "No changes detected")
  • Existing partition tests pass (issue_495 convergence, issue_418 partitioned parent index)
  • Full diff test suite passes
  • Full integration test suite passes

🤖 Generated with Claude Code

Partition children were rendered as standalone CREATE TABLE with inlined
columns, dropping the PARTITION OF ... FOR VALUES attachment clause. The
parent ended up with zero attached partitions and could not route inserts.

Add PartitionOf/PartitionBound metadata to the IR Table struct, populate
it from pg_inherits during inspection, and emit the correct PARTITION OF
syntax in generateTableSQL. Also add partition parent→child edges to the
topological sort so parents are always created before their children.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 3, 2026 05:18

Copilot AI 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.

Pull request overview

Fixes the create-path behavior for partitioned tables by teaching the IR/diff engine about partition parent/child attachments so partition children are created with PARTITION OF ... FOR VALUES ... (or DEFAULT) instead of detached standalone tables. This addresses #496 where from-scratch applies produced non-functional partitioned parents with zero attached partitions.

Changes:

  • Extend ir.Table with partition-child metadata (PartitionOf, PartitionOfSchema, PartitionBound) and populate it from pg_inherits + pg_get_expr(relpartbound).
  • Update table DDL generation to emit CREATE TABLE ... PARTITION OF ... <bound>; for partition children.
  • Add partition parent → child dependencies to table topological sorting to ensure parents are created before their partitions, and add a new diff fixture for the reported scenario.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
ir/ir.go Adds partition-child metadata fields to ir.Table.
ir/inspector.go Populates partition-child metadata during inspection while building partition mappings.
internal/diff/table.go Emits PARTITION OF DDL for partition children on the create path.
internal/diff/topological.go Ensures partition parents sort before children (dependency edge).
cmd/plan/plan.go Normalizes partition parent schema during temp→target schema rewrite.
testdata/diff/create_table/issue_496_partition_of_create_path/* New diff test fixture for LIST partition create-path attachment.
testdata/diff/create_table/issue_495_partition_constraint_convergence/plan.json Expected-plan hash update.
testdata/diff/online/issue_418_partitioned_parent_index/plan.json Expected-plan hash update.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread cmd/plan/plan.go Outdated
Comment thread internal/diff/table.go
Comment thread ir/inspector.go Outdated
@greptile-apps

greptile-apps Bot commented Jul 3, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a correctness bug where partition child tables were incorrectly emitted as standalone CREATE TABLE statements with inlined columns instead of CREATE TABLE ... PARTITION OF ... FOR VALUES ..., causing partitioned parents to have zero attached children and breaking insert routing.

  • Adds PartitionOf, PartitionOfSchema, and PartitionBound to ir.Table, populated via pg_inherits/pg_get_expr(relpartbound, …) in the inspector.
  • generateTableSQL now emits the PARTITION OF <parent> <bound> form for partition children, and topologicallySortTables adds parent→child edges so parents are always created first.
  • A new diff test (issue_496_partition_of_create_path) covers LIST partitioning with two value-based partitions and a DEFAULT partition, validated end-to-end including idempotency.

Confidence Score: 4/5

Safe to merge for the common case; the fix correctly handles the create-from-scratch partition path for all standard LIST/RANGE/HASH bound types.

The core fix is well-structured and the new test covers the important end-to-end flow including idempotency. One gap stands out: PartitionBound is an expression field derived from pg_get_expr on the embedded temp instance and may contain schema-qualified type casts, yet it is the only expression field in normalizeSchemaNames that is not passed through replaceString/stripQualifiers. Every other analogous field (check clauses, default values, trigger conditions, policy expressions) receives that treatment. When a partition bound references a custom type, the generated DDL would carry the temp-schema name and fail at apply time.

cmd/plan/plan.go — the PartitionBound normalization gap in normalizeSchemaNames

Important Files Changed

Filename Overview
cmd/plan/plan.go Adds PartitionOfSchema normalization in normalizeSchemaNames but omits the corresponding normalization of PartitionBound, which is an expression field following the same pattern as CheckClause, DefaultValue, and Condition.
internal/diff/table.go Early return for partition children correctly emits PARTITION OF DDL; returns nil for deferred constraints, meaning any non-inherited constraints explicitly added to a child are silently dropped on the create path.
internal/diff/topological.go Correctly adds partition parent→child dependency edges using the same Kahn's algorithm pattern as FK edges; fallback to tableA.Schema when PartitionOfSchema is empty mirrors the existing FK approach.
ir/inspector.go Populates new partition metadata fields on child tables in buildPartitionMapping; correctly guards with child.PartitionBound.Valid before setting PartitionBound.
ir/ir.go Clean IR extension: three new optional fields (PartitionOf, PartitionOfSchema, PartitionBound) added to Table with proper JSON tags and omitempty.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant User as UserSQL
    participant EmbPG as EmbeddedPostgres
    participant Inspector as Inspector
    participant Plan as PlanCmd
    participant Diff as TableDiff
    participant Topo as TopologicalSort
    participant TargetDB as TargetDB

    User->>EmbPG: Apply SQL files
    EmbPG-->>Inspector: Schema inspected
    Inspector->>Inspector: buildPartitionMapping sets PartitionOf, PartitionBound on child
    Inspector-->>Plan: Desired IR with partition metadata

    Plan->>Plan: normalizeSchemaNames replaces temp schema in PartitionOfSchema
    Note over Plan: PartitionBound not normalized here

    Plan->>Topo: topologicallySortTables
    Topo->>Topo: Add parent to child edge for partition dep
    Topo-->>Plan: Sorted parent before child

    Plan->>Diff: generateTableSQL for child table
    Diff->>Diff: PartitionOf and PartitionBound both set, early return
    Diff-->>Plan: CREATE TABLE child PARTITION OF parent FOR VALUES

    Plan->>TargetDB: Execute DDL in order
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant User as UserSQL
    participant EmbPG as EmbeddedPostgres
    participant Inspector as Inspector
    participant Plan as PlanCmd
    participant Diff as TableDiff
    participant Topo as TopologicalSort
    participant TargetDB as TargetDB

    User->>EmbPG: Apply SQL files
    EmbPG-->>Inspector: Schema inspected
    Inspector->>Inspector: buildPartitionMapping sets PartitionOf, PartitionBound on child
    Inspector-->>Plan: Desired IR with partition metadata

    Plan->>Plan: normalizeSchemaNames replaces temp schema in PartitionOfSchema
    Note over Plan: PartitionBound not normalized here

    Plan->>Topo: topologicallySortTables
    Topo->>Topo: Add parent to child edge for partition dep
    Topo-->>Plan: Sorted parent before child

    Plan->>Diff: generateTableSQL for child table
    Diff->>Diff: PartitionOf and PartitionBound both set, early return
    Diff-->>Plan: CREATE TABLE child PARTITION OF parent FOR VALUES

    Plan->>TargetDB: Execute DDL in order
Loading

Reviews (1): Last reviewed commit: "fix: emit PARTITION OF for partition chi..." | Re-trigger Greptile

Comment thread cmd/plan/plan.go Outdated
Comment thread internal/diff/table.go Outdated
- Normalize PartitionBound expression in normalizeSchemaNames to prevent
  temp-schema type casts from leaking into DDL (Copilot/Greptile P1)
- Fall back to child's schema when PartitionOfSchema is empty in
  generateTableSQL to avoid invalid ".<parent>" reference (Copilot)
- Hoist getOrCreateSchema outside loop in buildPartitionMapping (Copilot)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…496)

Address review feedback on PR #498:
- Broaden conparentid filter from FK-only to ALL constraint types
  (AND c.conparentid = 0) so inherited partition constraint copies are
  excluded from IR while child-specific constraints are preserved
- Include child-specific constraints inline in PARTITION OF statement,
  with proper FK deferral support
- Add timezone offset normalization in dump test comparison for
  cross-platform pg_get_expr consistency
- Update dump test expected outputs (issue_409, issue_472) to use
  PARTITION OF syntax
- Update issue_495 plan.json fingerprint hash

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • ir/queries/queries.sql.go: Generated file

Comment thread cmd/dump/dump_integration_test.go Outdated
Update tzOffsetRe to match offsets like +05:30 and +05:45, not just
whole-hour offsets like -08.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 17 out of 18 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • ir/queries/queries.sql.go: Generated file

Comment thread internal/diff/table.go
tianzhou and others added 2 commits July 3, 2026 00:42
pg_get_expr returns timestamps in the server's local timezone, causing
partition bounds and fingerprint hashes to differ across platforms.
Setting timezone=UTC ensures consistent output on all machines.

- Update Sakila dump expected output for PARTITION OF rendering
- Update issue_418 plan hash to match UTC-based fingerprint

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Emit CREATE UNLOGGED TABLE for partition children when the table is
marked as unlogged, matching the regular create path behavior.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Copilot AI 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.

Pull request overview

Copilot reviewed 19 out of 20 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • ir/queries/queries.sql.go: Generated file

@tianzhou tianzhou merged commit e91f550 into main Jul 3, 2026
2 checks passed
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.

apply creates partition children as detached standalone tables (drops PARTITION OF ... FOR VALUES) — parent gets 0 attached partitions (v1.11.1)

2 participants