Skip to content

fix(tabs): keep a restored table tab on its own database and load it after reconnect#1719

Merged
datlechin merged 2 commits into
mainfrom
fix/restore-tab-awaits-connection
Jun 18, 2026
Merged

fix(tabs): keep a restored table tab on its own database and load it after reconnect#1719
datlechin merged 2 commits into
mainfrom
fix/restore-tab-awaits-connection

Conversation

@datlechin

Copy link
Copy Markdown
Member

Problem

Reopening the app with a table tab open on a PostgreSQL connection (whose default database differs from the tab's database, e.g. an SSH-tunneled server) showed a "Query Execution Failed / Not connected to database" alert, and the restored tab opened and then closed without loading its data.

Root cause

Two coupled defects in the restore + reconnect path:

  1. When the restored tab's database differed from the connection's active database, the restore selected the tab, which triggered handleTabChange to call switchDatabase. switchDatabase clears all tabs (correct for a deliberate user switch, since old tabs belong to the old database), so it wiped the very tab being restored. The query actually ran and returned rows, but the tab was already gone.
  2. During the database-switch reconnect the session briefly held a driver whose connection was not yet up, and the auto-load ran against it. The driver threw a plugin-specific "not connected" error (not the shared DatabaseError.notConnected), so it surfaced as the modal. Separately, reconnectSession never re-synced currentSchema from the driver, leaving a stale mismatch that routed restore through a fragile path.

Fix

  • switchDatabase(to:clearTabs:) gains a clearTabs flag (default true, unchanged for user switches). Selecting a tab and the restore paths now pass clearTabs: false, so switching the active database to match a tab keeps that tab and loads it.
  • handleTabChange, restoreConnectionContext, and the deferred handleConnectionStatusChange path preserve the tab and call lazyLoadCurrentTabIfNeeded after the switch.
  • The auto-load now defers and retries (instead of showing a modal) when the driver is not actually .connected, keyed on the driver's connection status rather than a specific error type. It loads on its own once the connection is ready.
  • reconnectSession syncs currentSchema from the reconnected driver, matching the initial connect.
  • restoreSchemaAndRunQuery no longer runs a query when the driver is nil; it defers instead.

User-initiated database switches (toolbar, sidebar "Use as Active Database", quick switcher) keep the tab-clearing behavior.

Tests

  • Added a unit test that restoreSchemaAndRunQuery defers via needsLazyLoad instead of running a query when the driver is not ready.
  • The reconnect schema sync and modal suppression depend on a live driver / alert presentation, so they are verified manually.

Verification

Verified by hand on an SSH PostgreSQL connection whose default database differs from the open table: quit with the table open, reopen, and the tab stays open and loads its rows with no error alert.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5479130f6f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +35 to +39
Task {
await coordinator.switchDatabase(
to: selectedTab.tableContext.databaseName, clearTabs: false
)
coordinator.lazyLoadCurrentTabIfNeeded()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Defer loading until the database switch finishes

When needsLazyLoad is set and the selected restored tab belongs to a different database, this schedules the switch asynchronously but handleConnectionStatusChange still falls through to the unconditional lazyLoadCurrentTabIfNeeded() later in the same method while the session is on the old database. That early load can register the tab's load task and execute the table query before the switch completes, so the post-switch load here is skipped or the tab can show data/errors from the previous database. Return after queuing the switch, or otherwise prevent the lower lazy-load path from running until the context switch is complete.

Useful? React with 👍 / 👎.

}
} else {
executeQueryInternal(sql)
executeQueryInternal(sql, isAutoLoad: true)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep explicit table runs out of auto-load retry mode

This path is used by runQuery() for table tabs, not only by restored/lazy loads. Passing isAutoLoad: true makes explicit table executions such as Run/Refresh enter the new reconnect-error suppression path, so if the driver is disconnected the catch block suppresses the error, sets needsLazyLoad, and may replay the query later without user feedback. Reserve isAutoLoad for actual automatic loads and let explicit table executions report connection failures.

Useful? React with 👍 / 👎.

@datlechin datlechin merged commit 73cc3df into main Jun 18, 2026
2 of 3 checks passed
@datlechin datlechin deleted the fix/restore-tab-awaits-connection branch June 18, 2026 15:24

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c5d50298c2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +99 to +100
await switchDatabase(to: newTab.tableContext.databaseName, clearTabs: false)
lazyLoadCurrentTabIfNeeded()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Restore schema before loading after DB switch

When switching to a table tab in another PostgreSQL database, this path now reconnects the database and immediately lazy-loads the tab, but switchDatabase clears session.currentSchema for plugins that require reconnects (DatabaseManager+Sessions.swift lines 267-272; PostgreSQL sets that capability in PostgreSQLPlugin.swift line 124). For restored/open tabs in a non-default schema, the selected tab's tableContext.schemaName is never restored before lazyLoadCurrentTabIfNeeded(), so schema-dependent metadata/FK/row-edit fetches run against the default schema even though the tab belongs to another schema. Restore newTab.tableContext.schemaName after the database switch and before auto-loading.

Useful? React with 👍 / 👎.

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.

1 participant