Skip to content

fix: emit USING clause for ALTER COLUMN TYPE when base types differ (#537) - #541

Merged
tianzhou merged 10 commits into
mainfrom
fix/issue-537-using-clause-builtin-types
Aug 14, 2026
Merged

fix: emit USING clause for ALTER COLUMN TYPE when base types differ (#537)#541
tianzhou merged 10 commits into
mainfrom
fix/issue-537-using-clause-builtin-types

Conversation

@tianzhou

Copy link
Copy Markdown
Contributor

Summary

Closes #537

Test plan

  • Existing alter_column_types and alter_column_quoted_identifier golden files updated and passing
  • New issue_537_alter_column_type_using fixture (text→integer) passes diff and integration tests
  • Full integration test suite passes

🤖 Generated with Claude Code

…537)

needsUsingClause now compares normalized base type names instead of
relying on built-in type classification. This ensures a USING clause is
emitted for any type change where the base types differ (e.g. text →
integer), while omitting it when only modifiers change (e.g. numeric(18,6)
→ numeric(20,6)).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings August 14, 2026 10:14
Extends the fixture to include a column with a default value, verifying
the DROP DEFAULT → ALTER TYPE USING → SET DEFAULT sequencing works
correctly when USING is needed.

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

greptile-apps Bot commented Aug 14, 2026

Copy link
Copy Markdown

Greptile Summary

The PR broadens explicit USING-clause generation for ALTER COLUMN TYPE operations by comparing normalized base type names and adds a regression fixture for text-to-integer conversion.

Confidence Score: 4/5

The quoted custom-type case collision should be fixed before merging because it can still generate an ALTER COLUMN TYPE statement that PostgreSQL rejects.

The new normalization lowercases case-sensitive quoted type names, allowing distinct custom types to compare equal and suppressing the explicit cast required for a reachable migration.

Files Needing Attention: internal/diff/column.go

Important Files Changed

Filename Overview
internal/diff/column.go Replaces built-in-type classification with base-name comparison, but lowercasing quoted custom type identifiers can incorrectly suppress a required USING clause.
testdata/diff/create_table/issue_537_alter_column_type_using/old.sql Adds the current-schema side of the text-to-integer regression fixture.
testdata/diff/create_table/issue_537_alter_column_type_using/new.sql Adds the desired-schema side of the text-to-integer regression fixture.
testdata/diff/create_table/issue_537_alter_column_type_using/diff.sql Verifies generation of an explicit integer cast for the reported text-to-integer migration.

Reviews (1): Last reviewed commit: "fix: emit USING clause for ALTER COLUMN ..." | Re-trigger Greptile

Comment thread internal/diff/column.go Outdated

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 ALTER TABLE ... ALTER COLUMN ... TYPE planning by ensuring a USING col::newtype clause is emitted when the base type changes, preventing PostgreSQL SQLSTATE 42804 for non-implicitly-castable built-in type conversions (issue #537).

Changes:

  • Rewrites needsUsingClause to compare normalized base type names and emit USING col::newtype when the base types differ.
  • Updates existing golden fixtures to reflect USING being added for built-in→built-in type changes.
  • Adds a new regression fixture covering text → integer (issue_537_alter_column_type_using).

Reviewed changes

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

Show a summary per file
File Description
internal/diff/column.go Updates type-change logic to decide when to emit a USING cast expression.
testdata/diff/create_table/issue_537_alter_column_type_using/plan.txt New regression plan output for text → integer with USING.
testdata/diff/create_table/issue_537_alter_column_type_using/plan.sql New regression SQL output with USING.
testdata/diff/create_table/issue_537_alter_column_type_using/plan.json New regression JSON plan output with USING.
testdata/diff/create_table/issue_537_alter_column_type_using/old.sql New fixture: old schema uses text.
testdata/diff/create_table/issue_537_alter_column_type_using/new.sql New fixture: new schema uses integer.
testdata/diff/create_table/issue_537_alter_column_type_using/diff.sql New expected diff SQL for the regression case.
testdata/diff/create_table/alter_column_types/plan.txt Updates golden plan text to include USING for built-in type changes.
testdata/diff/create_table/alter_column_types/plan.sql Updates golden plan SQL to include USING for built-in type changes.
testdata/diff/create_table/alter_column_types/plan.json Updates golden plan JSON steps to include USING for built-in type changes.
testdata/diff/create_table/alter_column_types/diff.sql Updates expected diff SQL to include USING for built-in type changes.
testdata/diff/create_table/alter_column_quoted_identifier/plan.txt Updates golden plan text to include USING while preserving quoted column identifier.
testdata/diff/create_table/alter_column_quoted_identifier/plan.sql Updates golden plan SQL to include USING while preserving quoted column identifier.
testdata/diff/create_table/alter_column_quoted_identifier/plan.json Updates golden plan JSON step to include USING while preserving quoted column identifier.
testdata/diff/create_table/alter_column_quoted_identifier/diff.sql Updates expected diff SQL to include USING while preserving quoted column identifier.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread internal/diff/column.go
tianzhou and others added 2 commits August 14, 2026 03:21
Adds text→integer columns (with and without default) to the existing
alter_column_types test instead of a separate fixture, keeping the test
suite consolidated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Quoted identifiers are case-sensitive in PostgreSQL. Only lowercase
unquoted types so that distinct quoted custom types like "Foo" vs "foo"
are not collapsed, which would suppress a required USING clause.

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 11 out of 11 changed files in this pull request and generated 1 comment.

Suppressed comments (1)

internal/diff/column.go:117

  • The PR description says a new regression fixture "issue_537_alter_column_type_using" was added, but there are no files in the repo matching "issue_537" (grep/glob). The regression coverage appears to be implemented by extending the existing create_table/alter_column_types fixture instead; please either add the promised dedicated fixture or update the PR description to reflect the actual test change.
// needsUsingClause determines if a type conversion requires a USING clause.
//
// PostgreSQL rejects bare ALTER COLUMN TYPE when no implicit cast exists between
// the old and new types (SQLSTATE 42804). When the base type names differ, we
// always emit USING col::newtype — a redundant USING is harmless when an implicit

Comment thread internal/diff/column.go Outdated
tianzhou and others added 3 commits August 14, 2026 03:41
…pe test

Stop stripping [] so scalar↔array type changes (integer vs integer[])
correctly emit USING. Also add a "MyStatus"→"mystatus" column to the
alter_column_types fixture to cover quoted custom type case sensitivity.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adds integer→integer[] column to prove USING is emitted when only
array-ness changes.

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 11 out of 11 changed files in this pull request and generated no new comments.

Suppressed comments (2)

internal/diff/column.go:133

  • normalizeBaseTypeName currently truncates the type string at the first "(", which drops important suffixes like array brackets and time zone qualifiers. For example, "character varying(128)[]" (used in the repo; see issue_420_varchar_array_length_modifier) normalizes to "character varying", making scalar↔array changes appear identical and potentially causing needsUsingClause to skip a required USING clause (leading to SQLSTATE 42804 at apply). Strip typmod while preserving any suffix after the closing ")" (e.g. "varchar(128)[]" → "varchar[]"; "timestamp(6) with time zone" → "timestamp with time zone").
func normalizeBaseTypeName(typeName string) string {
	t := typeName
	if idx := strings.Index(t, "("); idx != -1 {
		t = t[:idx]
	}

testdata/diff/create_table/alter_column_types/old.sql:16

  • PR description says a new regression fixture issue_537_alter_column_type_using was added, but there are no matching files/strings in the repo. The textinteger regression appears to have been added by expanding the existing alter_column_types fixture (arfcn_dl). Please either add the named fixture or update the PR description so it matches what actually changed.
    arfcn_dl text DEFAULT 'unknown',
    priority text,
    flag public."MyStatus" DEFAULT 'active'::"MyStatus",

tianzhou and others added 2 commits August 14, 2026 04:07
PostgreSQL cannot cast between unrelated enum types even with USING,
so "MyStatus"→"mystatus" fails at apply time (SQLSTATE 42846). The
quoted-type normalization logic is still covered by the diff-level test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
PostgreSQL cannot cast integer to integer[] even with USING (SQLSTATE
42846). The array suffix preservation in normalizeBaseTypeName is still
covered by the diff-level test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Strip only the parenthesized modifier (e.g. "(128)") while keeping
suffixes like "[]" and "with time zone" that follow. Prevents
timestamp(6) with time zone and character varying(128)[] from losing
meaningful type identity during normalization.

Adds unit tests for normalizeBaseTypeName and needsUsingClause covering
typmod+suffix, scalar↔array, quoted identifiers, and timezone variants.

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 12 out of 12 changed files in this pull request and generated 1 comment.

Comment thread internal/diff/column.go

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 12 out of 12 changed files in this pull request and generated no new comments.

Suppressed comments (1)

internal/diff/column.go:120

  • PR description says a new regression fixture issue_537_alter_column_type_using was added, but there are no new testdata/**/issue_537* files in this change set. Instead, the repro seems to be covered by extending the existing testdata/diff/create_table/alter_column_types fixture. Please either update the PR description/test plan to match what was actually added, or include the promised fixture so future readers can locate the regression easily.
// needsUsingClause determines if a type conversion requires a USING clause.
//
// PostgreSQL rejects bare ALTER COLUMN TYPE when no implicit cast exists between
// the old and new types (SQLSTATE 42804). When the base type names differ, we
// always emit USING col::newtype — a redundant USING is harmless when an implicit
// cast exists, but a missing one breaks the migration. When only modifiers change
// (e.g. numeric(18,6) → numeric(20,6)), no USING is needed.
func needsUsingClause(oldType, newType string) bool {

@tianzhou
tianzhou merged commit 24cb9d1 into main Aug 14, 2026
2 checks passed
@tianzhou
tianzhou deleted the fix/issue-537-using-clause-builtin-types branch August 14, 2026 11:54
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.

ALTER COLUMN TYPE omits USING clause for non-implicitly-castable built-in type changes (SQLSTATE 42804)

2 participants