Skip to content

Fix #6557: Avoid redundant column migrations when using type aliases#7652

Open
DasJott wants to merge 14 commits intogo-gorm:masterfrom
PerryProjects:jfix/#6557
Open

Fix #6557: Avoid redundant column migrations when using type aliases#7652
DasJott wants to merge 14 commits intogo-gorm:masterfrom
PerryProjects:jfix/#6557

Conversation

@DasJott
Copy link
Copy Markdown

@DasJott DasJott commented Nov 13, 2025

  • [ X ] Do only one thing
  • [ X ] Non breaking API changes
  • [ X ] Tested

What did this pull request do?

Improves the mapping of types to aliases.

The mapping keys do not (and CAN not) include any additional information behind the actual type name.
Therefore to check for aliases in a certain mapping we need to strip that info off, like:
varchar(255)[] => varchar.
To really be sure for the mapping to work reliably the types are mapped best in both ways, like:
varchar => character varying, character varying => varchar.
For at least postgres this was not the case for exactly that case.
For not having to touch all the other driver packages, this code simply tries to map the other way around when the first attempt failed.

User Case Description

We had a data struct containing a field pq.StringArray with gorm:"type:varchar[]". That type was returned by postgres as character varying[]. The current code could not map that correctly and therefore on every service restart an unnecessary migration was started (which took very long on a table containing millions of entries).

This is fixed with this PR.

@propel-code-bot
Copy link
Copy Markdown
Contributor

propel-code-bot bot commented Nov 13, 2025

Prevent redundant migrations by improving type alias comparison and adding migration tests

This PR updates column type comparison logic in migrator/migrator.go to better handle aliases and base type matching, reducing unnecessary ALTER TABLE operations when database types differ only by aliases or length qualifiers. It adds comprehensive migration tests in tests/migrate_test.go to validate idempotent behavior for length specifiers, array types (Postgres), generic string types, and bidirectional aliases.

Additionally, test infrastructure changes update tests/go.mod dependency versions and adjust tests/upsert_test.go variable usage to include an extra test user variable.

Key Changes

• Reworked type comparison in migrator/migrator.go to compare base types, strip length/precision, and perform bidirectional alias checks before deciding to AlterColumn
• Added TestMigrateColumnTypeAliases and helper logger types in tests/migrate_test.go to assert no redundant ALTER TABLE statements for alias/array cases
• Updated tests/go.mod versions (e.g., go version and driver/dependency bumps) and adjusted tests/upsert_test.go user variable list

Affected Areas

migrator/migrator.go
tests/migrate_test.go
tests/go.mod
tests/upsert_test.go

This summary was automatically generated by @propel-code-bot

@propel-code-bot propel-code-bot bot changed the title Fixes #6557 - AutoMigrate re-migrates some types Fix #6557: Prevent AutoMigrate from remigrating columns with type aliases Nov 13, 2025
@jinzhu
Copy link
Copy Markdown
Member

jinzhu commented Nov 14, 2025

Hi @DasJott

Can you add some tests?

@propel-code-bot propel-code-bot bot changed the title Fix #6557: Prevent AutoMigrate from remigrating columns with type aliases Fix #6557: Skip redundant migrations for columns with type aliases Dec 1, 2025
@propel-code-bot propel-code-bot bot changed the title Fix #6557: Skip redundant migrations for columns with type aliases Fix #6557: Avoid redundant column migrations when using type aliases Dec 1, 2025
@PerryProjects
Copy link
Copy Markdown

Hey @jinzhu,
Hey @DasJott,

i added some tests for the given changes. Hopefully the tests were sufficient.

Copy link
Copy Markdown
Contributor

@propel-code-bot propel-code-bot bot left a comment

Choose a reason for hiding this comment

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

Suggested guarding type comparisons when database type names are empty to avoid unnecessary ALTERs.

Status: Changes Suggested | Risk: Medium

Issues Identified & Suggestions
  • Handle empty database type names to prevent redundant migrations: migrator/migrator.go
Review Details

📁 6 files reviewed | 💬 1 comments

👍 / 👎 individual comments to help improve reviews for you

// found, smart migrate
fullDataType := strings.TrimSpace(strings.ToLower(m.DB.Migrator().FullDataTypeOf(field).SQL))
realDataType := strings.ToLower(columnType.DatabaseTypeName())
dbDataType := strings.ToLower(columnType.DatabaseTypeName()) // from db
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.

Important

[Logic] If columnType.DatabaseTypeName() returns an empty string (drivers can legally return "" for unsupported types), baseDbType becomes "" and aliasMatch stays false, which sets alterColumn = true and can trigger unnecessary ALTERs on every migration. The previous logic treated empty realDataType as a prefix match and didn’t force an ALTER just because the driver lacked a type name. Can you add a guard so an empty dbDataType doesn’t force alterColumn (e.g., short‑circuit type comparison when dbDataType == "" or treat it as isSameBaseType = true)?

Context for Agents
If `columnType.DatabaseTypeName()` returns an empty string (drivers can legally return "" for unsupported types), `baseDbType` becomes "" and `aliasMatch` stays false, which sets `alterColumn = true` and can trigger unnecessary ALTERs on every migration. The previous logic treated empty `realDataType` as a prefix match and didn’t force an ALTER just because the driver lacked a type name. Can you add a guard so an empty `dbDataType` doesn’t force `alterColumn` (e.g., short‑circuit type comparison when `dbDataType == ""` or treat it as `isSameBaseType = true`)?

File: migrator/migrator.go
Line: 473

fix(migrate_test): update test structure for array types and generic types
fix(migrate_test): ensure no ALTER statements are generated during migrations
propel-code-bot[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@propel-code-bot propel-code-bot bot left a comment

Choose a reason for hiding this comment

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

Found a logic gap in type comparison that could miss array-vs-scalar schema mismatches.

Status: Changes Suggested | Risk: Medium

Issues Identified & Suggestions
  • Detect array-vs-scalar differences before base-type stripping: migrator/migrator.go
Review Details

📁 4 files reviewed | 💬 1 comments

👍 / 👎 individual comments to help improve reviews for you


// strip length/precision specifiers for base-type comparison
baseDbType := dbDataType
if p := strings.IndexAny(dbDataType, "(["); p >= 0 {
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.

Important

[Logic] Array vs scalar mismatch can be missed after stripping "[" in the base-type comparison. If dbDataType includes array notation (e.g., varchar[]) but the struct type is scalar (varchar), baseDbType/baseStructType both become varchar, isSameBaseType becomes true, and alterColumn never flips—leaving the schema incorrect.

Fix: before stripping, detect array-ness and force alterColumn when one side is array and the other isn't, e.g. compare strings.Contains(dbDataType, "[]") with strings.Contains(m.DataTypeOf(field), "[]") and set alterColumn = true (or treat isSameBaseType as false) when they differ.

Context for Agents
Array vs scalar mismatch can be missed after stripping "[" in the base-type comparison. If `dbDataType` includes array notation (e.g., `varchar[]`) but the struct type is scalar (`varchar`), `baseDbType`/`baseStructType` both become `varchar`, `isSameBaseType` becomes true, and `alterColumn` never flips—leaving the schema incorrect.

Fix: before stripping, detect array-ness and force `alterColumn` when one side is array and the other isn't, e.g. compare `strings.Contains(dbDataType, "[]")` with `strings.Contains(m.DataTypeOf(field), "[]")` and set `alterColumn = true` (or treat `isSameBaseType` as false) when they differ.

File: migrator/migrator.go
Line: 487

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.

3 participants