feat(datagrid)!: add an On Update column for MySQL and MariaDB timestamps (#2005) - #2007
Merged
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2005.
The issue asked for a missing field. Tracing it found an active corruption bug sitting behind it, so this fixes both.
The data-loss bug
EditableColumnDefinition.from(_:)hardcodedonUpdate: nil, so the value the server reported was thrown away on every load. MySQL'sgenerateModifyColumnSQLrestates the whole column definition, andMODIFY/CHANGE COLUMNdrops whatever the restated definition omits.The result: editing any attribute of a MySQL or MariaDB column that already had
ON UPDATE CURRENT_TIMESTAMPsilently stripped the clause on save. A rename, a comment, a charset change, anything. No error, no warning. This is DataGrip's DBE-4079 verbatim: "can lead to column property loss by simply renaming the column."PostgreSQL and SQL Server emit per-attribute
ALTER COLUMNand were never exposed. ClickHouse uses the same full-redefinition shape but has no attribute of this kind modelled yet.The field
StructureColumnFieldgains.onUpdate, ordered next to.defaultValuesince it is that clause's companion. It renders as a YES/NO dropdown through the existingcustomDropdownOptionspath, the same one already driving Nullable, Primary Key, and Auto Inc, so the grid, the inspector, and the Create Table sheet all pick it up with no separate wiring.Why a dropdown and not a combo box. The HIG points at a combo box for "a list plus arbitrary text", but the vocabulary here is genuinely closed. The emit whitelist only accepts
CURRENT_TIMESTAMPforms and silently discards anything else, and MySQL requires the fractional precision to match the column's own type, so a hand-typedCURRENT_TIMESTAMP(3)on aTIMESTAMP(6)column is just a server error. A combo box would let people type values that visibly stick in the cell and then vanish at save time. Sequel Ace, the one tool that has had this right for a decade, uses a fixed popup for the same reason.Why not a raw
Extrapassthrough. It would collide with the existing first-class Auto Inc column, and readinginformation_schema.COLUMNS.EXTRAstraight into DDL is what shipped syntax errors in TablePlus (#1078) and DBeaver (#7850, #13577), because MySQL 8.0.13+ puts the non-DDL tokenDEFAULT_GENERATEDin that column. The parser here matches a substring and re-emits a canonical expression, so a compoundEXTRAvalue parses correctly and no server token ever reaches generated SQL.MySQL DDL builder
buildColumnDefinitionSQLandgenerateMoveColumnSQLwere independently repeating the same eight clauses, including a verbatim copy of theON UPDATEblock. Both now share one builder.Fractional-second precision is derived from the column's declared type rather than stored or typed, so a
TIMESTAMP(6)column getsON UPDATE CURRENT_TIMESTAMP(6), and a stale(6)carried on aDATETIME(3)column is corrected instead of trusted.That builder also fixes a sibling bug in the same function: the default branch accepted
CURRENT_TIMESTAMPandCURRENT_TIMESTAMP()but notCURRENT_TIMESTAMP(6), so aTIMESTAMP(6)column's default was quoted intoDEFAULT 'CURRENT_TIMESTAMP(6)'and the ALTER failed. Auto-deriving precision makes those columns reachable, so leaving it would have shipped a landmine next to the new feature.Breaking PluginKit change
StructureColumnFieldwas marked@frozen, so adding a case is breaking. It is also un-frozen here, in the same bump.The release work is identical either way, and the case set was never closed: PostgreSQL already populates
identityKindandisGeneratedwith no home in this enum, and SQL Server computed columns, ClickHouse default-kinds, and SQLite generated columns are all the same shape. Paying the bump once and un-freezing means the next per-engine field is additive and free. By CLAUDE.md's own criterion ("mark@frozenonly when an exhaustive switch forces it and its case set is genuinely closed") the marking was already wrong.scripts/check-pluginkit-abi.sh mainconfirms it, including one consequence I had not predicted:Un-freezing also drops the synthesized
BitwiseCopyableconformance, since a resilient enum's layout is not statically known across the module boundary. That independently confirms the breaking classification. It is a compiler-synthesized marker protocol, not a requirement any plugin implements, and the raised version floor rejects a stale plugin before it could observe the difference.Do not add the
abi-additivelabel. This diff is breaking on two counts.Release order matters
currentPluginKitVersionandminimumCompatiblePluginKitVersionboth go 18 → 19, with all 29 pluginInfo.plistfiles..github/workflows/build.ymlgatesCreate GitHub Releaseoncheck-registry-readiness.py, soscripts/release-all-plugins.sh 19must run before or with the app release across the 16 registry plugins. Otherwise the release job fails and users on the new app hitnoCompatibleBinary.MariaDB needs three declarations, not one
Worth knowing for review. MariaDB is registered as an additional type id on the MySQL plugin, and
registerVariantdiscards the plugin-built snapshot wholesale when a curated default exists. MariaDB's live field list is therefore the hardcoded literal inPluginMetadataRegistry, notMySQLPlugin.swift. Editing only the plugin would have shipped the field to MySQL and silently skipped MariaDB.StructureColumnFieldRegistrationTestsguards this: it asserts the two engines agree and that both offer the field.Tests
21 new cases in
MySQLColumnDefinitionSQLTests, plus coverage inColumnDefinitionTests(including theDEFAULT_GENERATEDcompound-token case),StructureEditingSupportBooleanParsingTests, andStructureColumnFieldRegistrationTests.MySQLCreateTableTests.swifthas never run, and this is why the new tests are not in it. The MySQL plugin is not a module inTableProTests. Pure-logic files are compiled into the test target via pbxprojmembershipExceptionsand called with no import at all, which is why#if canImport(MySQLDriverPlugin)is false and all 12 tests in that file compile to nothing. The new clause logic lives inMySQLColumnDefinitionSQL.swift, added to that exception set, and the new tests are verified to actually execute. The 12 pre-existing dead tests coverCREATE TABLEassembly and would needgenerateCreateTableSQLextracted as well; left alone here rather than widen scope, but it is a real gap worth its own issue.Verification
swiftlint lint --strictclean. Local swiftformat cannot run against the repo config (version drift), so it was not run.TableProTestsfailing-case IDs diffed against a stashed clean tree: 76 before, 75 after. The suite is already red in a headless run. The only deltas are one network test and one timer test flipping, and three pasteboard tests flipping the other way, all in areas this change does not touch.StructureGridDelegateAddRowTestsSQLite cases fail on cleanmain, independently of this work.SHOW FULL COLUMNSandINFORMATION_SCHEMAread paths use different queries, and the parser is deliberately case-insensitive so a casing difference between them cannot matter, but a live sanity check on both engines is worth doing before merge.