Skip to content

Data grid keeps showing the previous table's column headers after switching tables #2548

Description

@twinn1013

Description

Describe the bug

On the macOS build, when switching from one table to another in the database tree, the data tab shows the new table's rows, but the column headers still show the previous table's columns (captions, sort order and column numbering). The column counter (e.g. "Columns (6/6)") is already correct, so the internal state is fine — only the header area is not repainted.

The stale header stays until something else forces a repaint: pressing F5, scrolling the grid, resizing the window, or the app losing focus. Without any interaction it can stay wrong for a long time.

Screenshots

Image *Correct headers right after connecting.* Image *After switching to another table: rows belong to the new table, headers still belong to the previous one.* Image *Another switch: headers are a mix of two previous tables.*

Root cause (analyzed with lldb on the release binary)

The data grid is lazily loaded inside OnBeforePaint (TMainForm.DataGridBeforePaint), i.e. inside a paint cycle of the VirtualTree. The paint order in laz.VirtualTrees is: paint the header first, then PaintTree fires OnBeforePaint. So the header is always painted with the old columns before they get replaced.

All repaint requests issued afterwards during the load are discarded, because Cocoa drops invalidations that are issued while a paint cycle is running:

  • TVTHeader.Invalidate (resolves to DelphiCompat.RedrawWindowLCLIntf.InvalidateRect) — issued in-paint, discarded
  • the full Invalidate from TBaseVirtualTree.EndUpdate — also issued in-paint, discarded

I verified this with lldb breakpoints on the 12.20.1.1 binary: during a table switch, every header/tree invalidation fires with DataGridBeforePaint + the paint cycle in its backtrace, and after the load no screen invalidation for the grid follows at all — until an external event (scroll/resize/focus) finally triggers one, which is exactly when the header heals.

This also explains why Windows and Linux are unaffected: there the same invalidations survive being issued during a paint.

Fix

A small Darwin-only fix works reliably here: at the end of DataGridBeforePaint, queue Application.QueueAsyncCall with a deferred vt.Invalidate, so one repaint runs right after the current paint cycle finishes. No query re-execution, no effect on other platforms. Tested on an M-series Mac — headers now update instantly on every table switch.

HeidiSQL version and OS

12.20.1.1 (macOS 26.2)

Database server version

MariaDB or MySQL 9.6.0

Reproduction recipe

  1. Connect to any server (reproduced with MariaDB, but the server type doesn't matter)
  2. Click table A in the database tree, let the data tab load
  3. Click table B
  4. Header still shows table A's columns while the grid shows table B's data
  5. Scroll, resize or press F5 → header corrects itself

Reproducible on every table switch.

Error/Backtrace

Metadata

Metadata

Assignees

Labels

bugDefective behaviour in HeidiSQLmacosAffects the macOS app bundle

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions