Skip to content

fix(alter): keep an attribute's values when alter() renames it - #1634

Merged
dimitri-yatsenko merged 1 commit into
masterfrom
fix/alter-rename-keeps-data
Oct 21, 2026
Merged

dimitri-yatsenko merged 1 commit into
masterfrom
fix/alter-rename-keeps-data

Conversation

@dimitri-yatsenko

Copy link
Copy Markdown
Member

alter() renames an attribute whose new comment opens with {old_name}. It looked for that marker in the compiled column SQL, where it is not always found. A core type or codec writes its :type: marker in front of the comment (COMMENT ":float32:{value} ..."), and PostgreSQL keeps comments out of the column SQL altogether. In both cases the rename went unnoticed: alter() dropped the old attribute and added the new one, and every value was lost. On MySQL, renaming value : float32 to reading : float32 # {value} left reading at 0.0 in every row; on PostgreSQL, renaming a nullable attribute left it NULL. A required attribute on PostgreSQL failed with a NOT NULL error instead.

The marker is now read from the comment as declared, after any :type: marker. On MySQL the rename becomes a CHANGE, which keeps the values. PostgreSQL has no CHANGE, so alter() now refuses a rename there with a DataJointError before running anything, instead of dropping the attribute.

The new tests rename a required and a nullable core-type attribute of a table holding rows. On MySQL they check that the values survive; on PostgreSQL that the rename is refused and the table keeps its values. All four fail before this change.

Renaming on PostgreSQL itself comes with #1625 in 2.4.

Closes #1631.

`alter()` renames an attribute whose new comment opens with `{old_name}`. It looked for that marker in the compiled column SQL, where it is not always found. A core type or codec writes its `:type:` marker in front of the comment (`COMMENT ":float32:{value} ..."`), and PostgreSQL keeps comments out of the column SQL altogether. In both cases the rename went unnoticed: `alter()` dropped the old attribute and added the new one, and every value was lost. On MySQL, renaming `value : float32` to `reading : float32 # {value}` left `reading` at 0.0 in every row; on PostgreSQL, renaming a nullable attribute left it NULL. A required attribute on PostgreSQL failed with a NOT NULL error instead.

The marker is now read from the comment as declared, after any `:type:` marker. On MySQL the rename becomes a CHANGE, which keeps the values. PostgreSQL has no CHANGE, so `alter()` now refuses a rename there with a DataJointError before running anything, instead of dropping the attribute.

The new tests rename a required and a nullable core-type attribute of a table holding rows. On MySQL they check that the values survive; on PostgreSQL that the rename is refused and the table keeps its values. All four fail before this change.
@dimitri-yatsenko

Copy link
Copy Markdown
Member Author

@MilagrosMarin @lum-agilyti: this, with its backport (#1635), is the last fix holding the v2.3.5 tag. It fixes data loss in 2.3.4, and everything else in v2.3.5 is merged. Could one of you review it? The backport is the same commit.

@MilagrosMarin MilagrosMarin 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.

LGTM. Reading the rename marker from the declared comment, rather than the column SQL, fixes both cases: the :type: prefix on MySQL and the absent comment on PostgreSQL. Refusing the rename on PostgreSQL before any SQL runs is the right stopgap until #1625. The tests check that values survive on MySQL and that the table is untouched on PostgreSQL.

Two small, non-blocking notes:

  1. The description mentions codecs as well as core types, but the tests only rename a float32. A case with a codec attribute (e.g. <blob>) would confirm the (?::[^:]*:)? prefix is skipped there too.
  2. The comment above the PostgreSQL raise describes the old behavior ("Without this check the rename went unnoticed…"). Something like "PostgreSQL has no CHANGE; refuse rather than DROP + ADD" would state the constraint itself.

@dimitri-yatsenko

Copy link
Copy Markdown
Member Author

Thanks, @MilagrosMarin. Merging, then #1635. Both notes go into #1639, which rewrites this code for 2.4: a rename test with a codec attribute such as <blob>, to check that the :type: prefix is skipped there too, and a comment that states the constraint ("PostgreSQL has no CHANGE; refuse rather than DROP + ADD").

@dimitri-yatsenko
dimitri-yatsenko merged commit 15610e5 into master Oct 21, 2026
9 checks passed
@dimitri-yatsenko
dimitri-yatsenko deleted the fix/alter-rename-keeps-data branch October 21, 2026 15:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Indicates an unexpected problem or unintended behavior

Projects

None yet

Development

Successfully merging this pull request may close these issues.

alter() loses an attribute's values when it renames a core-type attribute

2 participants