Skip to content

fix: prevent enum name truncation in schema-qualified type resolution (#521) - #522

Merged
tianzhou merged 1 commit into
mainfrom
fix/issue-521-enum-name-truncation
Jul 30, 2026
Merged

fix: prevent enum name truncation in schema-qualified type resolution (#521)#522
tianzhou merged 1 commit into
mainfrom
fix/issue-521-enum-name-truncation

Conversation

@tianzhou

Copy link
Copy Markdown
Contributor

Summary

  • Fix enum/composite type names being truncated to 63 characters when the temporary schema prefix (pgschema_tmp_*, 37 chars) plus type name exceeded PostgreSQL's name type limit
  • Root cause: CASE expressions in type-resolution queries mixed name-typed catalog columns (typname, nspname, udt_name) with text expressions, causing PostgreSQL to resolve the CASE result type as name (63-char limit) — truncation happened inside the CASE evaluation, before any outer ::text cast
  • Fix: add explicit ::text casts to bare name-typed columns inside CASE branches across all 9 type-resolution queries in queries.sql and the generated queries.sql.go
  • Add regression test fixture issue_521_enum_truncation with enum names that exceed 63 chars when schema-qualified

Closes #521

Test plan

  • New fixture testdata/diff/create_table/issue_521_enum_truncation/ passes — only the expected ADD COLUMN change, no spurious ALTER TYPE
  • All 29 create_table/ integration tests pass
  • Full TestPlanAndApply suite passes (594s)
  • All unit tests pass (ir/, internal/)

🤖 Generated with Claude Code

…#521)

PostgreSQL's CASE expression type resolution could resolve to the `name`
type (63-char limit) when branches mixed `name`-typed catalog columns
with `text` expressions. This caused schema-qualified enum/composite
type names to be silently truncated when the temporary schema prefix
plus type name exceeded 63 characters, producing spurious ALTER TYPE
statements in migration plans.

Add explicit `::text` casts to bare `name`-typed columns inside CASE
branches (typname, nspname, udt_name) across all 9 type-resolution
queries to ensure the CASE resolves to `text` (unlimited length).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 30, 2026 08:45
Comment thread ir/queries/queries.sql.go
Comment on lines 398 to +410
-- for non-array fixed-length types like name (typelem points to char).
-- Use format_type to preserve typmod for element types (e.g., varchar(128)[] for character varying(128)[])
CASE
WHEN en.nspname = 'pg_catalog' THEN et.typname
WHEN en.nspname = 'pg_catalog' THEN et.typname::text
ELSE quote_ident(en.nspname) || '.' || quote_ident(et.typname)
END || COALESCE(substring(format_type(a.atttypid, a.atttypmod) FROM '\([^)]*\)'), '') || '[]'
WHEN dt.typtype = 'b' THEN
-- Non-array base types: qualify if not in pg_catalog or table's schema
-- Use format_type to preserve typmod for extension types (e.g., vector(384) for pgvector)
CASE
WHEN dn.nspname = 'pg_catalog' THEN c.udt_name
WHEN dn.nspname = 'pg_catalog' THEN c.udt_name::text
WHEN dn.nspname = c.table_schema THEN
dt.typname || COALESCE(substring(format_type(a.atttypid, a.atttypmod) FROM '\([^)]*\)'), '')
dt.typname::text || COALESCE(substring(format_type(a.atttypid, a.atttypmod) FROM '\([^)]*\)'), '')
ELSE
dn.nspname || '.' || dt.typname || COALESCE(substring(format_type(a.atttypid, a.atttypmod) FROM '\([^)]*\)'), '')
dn.nspname::text || '.' || dt.typname::text || COALESCE(substring(format_type(a.atttypid, a.atttypmod) FROM '\([^)]*\)'), '')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Generated output is not reproducible

The changed sqlc-generated constants omit comments that remain in queries.sql, so the next regeneration restores them and creates unrelated generated-file churn that obscures future semantic query changes.

Context Used: CLAUDE.md (source)

Knowledge Base Used: IR Model

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@greptile-apps

greptile-apps Bot commented Jul 30, 2026

Copy link
Copy Markdown

Greptile Summary

The PR prevents PostgreSQL catalog name coercion from truncating resolved type names.

  • Casts catalog identifiers to text inside column, aggregate, composite-attribute, and domain type-resolution CASE expressions.
  • Updates the runtime sqlc query constants with the corresponding casts.
  • Adds a create-table regression fixture covering long schema-qualified enum references.

Confidence Score: 4/5

The PR appears safe to merge, with only non-blocking generated-file reproducibility cleanup recommended.

The runtime SQL includes the intended text casts and the regression fixture checks the affected comparison path; the remaining issue is that two generated constants no longer exactly reflect reproducible sqlc output from the source file.

Files Needing Attention: ir/queries/queries.sql.go

Important Files Changed

Filename Overview
ir/queries/queries.sql Adds inner text casts consistently across the changed type-resolution expressions, preventing CASE evaluation from truncating qualified names.
ir/queries/queries.sql.go Carries the runtime SQL fix but is not fully reproducible from the source because source comments disappeared from two generated constants.
testdata/diff/create_table/issue_521_enum_truncation/new.sql Defines the desired schema with long enum references and the intended added column.
testdata/diff/create_table/issue_521_enum_truncation/old.sql Defines the matching existing enum-backed schema without the new column.
testdata/diff/create_table/issue_521_enum_truncation/plan.json Confirms the regression fixture expects only the intended column addition rather than a spurious type alteration.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
    Catalog[PostgreSQL catalog name values] --> Cast[Cast CASE branches to text]
    Cast --> Resolve[Resolve qualified type name]
    Resolve --> IR[Build normalized IR]
    IR --> Diff[Compare current and desired schemas]
    Diff --> Plan[Emit only the intended migration]
Loading

Reviews (1): Last reviewed commit: "fix: prevent enum name truncation in sch..." | Re-trigger Greptile

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 a PostgreSQL name-type truncation bug in IR type resolution by ensuring CASE expressions return text (not name) when mixing catalog name columns (e.g., typname, nspname, udt_name) with text expressions. This prevents schema-qualified enum/composite names from being truncated when a long temporary schema prefix is involved, avoiding spurious type-change diffs during plan generation.

Changes:

  • Add explicit ::text casts inside CASE branches across the type-resolution SQL queries to prevent name-typed CASE results (63-char truncation).
  • Regenerate/update the corresponding sqlc-generated Go query file to match the SQL changes.
  • Add a regression diff fixture for issue #521 to ensure only the real schema change (ADD COLUMN) is planned.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated no comments.

Show a summary per file
File Description
ir/queries/queries.sql Adds ::text casts inside CASE branches so type-resolution expressions evaluate as text and don’t truncate.
ir/queries/queries.sql.go Updates generated query strings to reflect the SQL ::text casting changes.
testdata/diff/create_table/issue_521_enum_truncation/old.sql Regression fixture: baseline schema with enums whose schema-qualified names exceed 63 chars under temp-schema prefixing.
testdata/diff/create_table/issue_521_enum_truncation/new.sql Adds the intended column change while keeping enum usage stable.
testdata/diff/create_table/issue_521_enum_truncation/diff.sql Expected diff: only ADD COLUMN, no unintended ALTER TYPE/column type changes.
testdata/diff/create_table/issue_521_enum_truncation/plan.sql Expected planned SQL output for the fixture.
testdata/diff/create_table/issue_521_enum_truncation/plan.txt Expected human-readable plan output for the fixture.
testdata/diff/create_table/issue_521_enum_truncation/plan.json Expected structured plan output for the fixture.
Files not reviewed (1)
  • ir/queries/queries.sql.go: Generated file

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

@tianzhou
tianzhou merged commit 325dac2 into main Jul 30, 2026
3 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.

Enum names being truncated in 1.12.1

2 participants