@@ -385,12 +385,6 @@ struct MainContentView: View {
385385 tabManager. tabs = restoredTabs
386386 tabManager. selectedTabId = savedState. selectedTabId
387387 didRestoreTabs = true
388-
389- print ( " [MainContentView] Restored \( restoredTabs. count) tabs from disk " )
390- // Debug: Print query text to verify restoration
391- for (index, tab) in restoredTabs. enumerated ( ) {
392- print ( " [MainContentView] Tab \( index) : \" \( tab. title) \" - Query: \( tab. query. prefix ( 50 ) ) ... " )
393- }
394388 } else if let sessionId = DatabaseManager . shared. currentSessionId,
395389 let session = DatabaseManager . shared. activeSessions [ sessionId] ,
396390 !session. tabs. isEmpty {
@@ -401,51 +395,35 @@ struct MainContentView: View {
401395 tabManager. tabs = session. tabs
402396 tabManager. selectedTabId = session. selectedTabId
403397 didRestoreTabs = true
404-
405- print ( " [MainContentView] Restored \( session. tabs. count) tabs from session " )
406398 }
407- // CRITICAL: Execute query for table tabs to load data
408- // Query tabs only restore text without auto-execution
399+ // Execute query for table tabs to load data
409400 if didRestoreTabs {
410- if let selectedTab = tabManager. selectedTab {
411- print ( " [MainContentView] Restored tab: \( selectedTab. title) , type: \( selectedTab. tabType) , hasQuery: \( !selectedTab. query. isEmpty) " )
401+ if let selectedTab = tabManager. selectedTab,
402+ selectedTab. tabType == . table,
403+ !selectedTab. query. trimmingCharacters ( in: . whitespacesAndNewlines) . isEmpty {
412404
413- if selectedTab. tabType == . table,
414- !selectedTab. query. trimmingCharacters ( in: . whitespacesAndNewlines) . isEmpty {
415- print ( " [MainContentView] Waiting for connection to be ready... " )
416-
417- // CRITICAL: Wait for connection to be established
418- // Without this, query fails with "Not connected to database"
419- var retryCount = 0
420- while retryCount < 50 { // Max 5 seconds
421- if let session = DatabaseManager . shared. currentSession,
422- session. isConnected {
423- print ( " [MainContentView] Connection ready! Executing query for restored table tab: \( selectedTab. title) " )
424-
425- // Small delay to ensure everything is initialized
426- try ? await Task . sleep ( nanoseconds: 100_000_000 ) // 0.1s
427- await MainActor . run {
428- justRestoredTab = true // Prevent lazy load from executing again
429- runQuery ( )
430- }
431- break
405+ // Wait for connection to be established
406+ var retryCount = 0
407+ while retryCount < 50 { // Max 5 seconds
408+ if let session = DatabaseManager . shared. currentSession,
409+ session. isConnected {
410+ // Small delay to ensure everything is initialized
411+ try ? await Task . sleep ( nanoseconds: 100_000_000 ) // 0.1s
412+ await MainActor . run {
413+ justRestoredTab = true // Prevent lazy load from executing again
414+ runQuery ( )
432415 }
433-
434- // Wait 100ms and retry
435- try ? await Task . sleep ( nanoseconds: 100_000_000 )
436- retryCount += 1
416+ break
437417 }
438418
439- if retryCount >= 50 {
440- print ( " [MainContentView] Warning: Connection timeout, query not executed " )
441- }
442- } else if selectedTab . tabType == . query {
443- print ( " [MainContentView] Restored query tab - skipping auto-execution " )
444- } else {
445- print ( " [MainContentView] Restored table tab but no query - skipping auto-execution " )
419+ // Wait 100ms and retry
420+ try ? await Task . sleep ( nanoseconds : 100_000_000 )
421+ retryCount += 1
422+ }
423+
424+ if retryCount >= 50 {
425+ print ( " [MainContentView] ⚠️ Connection timeout, query not executed " )
446426 }
447- } else {
448- print ( " [MainContentView] No selected tab after restore " )
449427 }
450428 }
451429 }
@@ -896,17 +874,19 @@ struct MainContentView: View {
896874 return
897875 }
898876
877+ guard !tabManager. tabs [ index] . isExecuting else {
878+ return
879+ }
880+
899881 // Cancel any previous running query to prevent race conditions
900- // This is critical for SSH connections where rapid sorting can cause
901- // multiple queries to return out of order, leading to EXC_BAD_ACCESS
882+ // IMPORTANT: Only cancel AFTER checking isExecuting, otherwise we cancel
883+ // a valid running query without starting a new one
902884 currentQueryTask? . cancel ( )
903885
904886 // Increment generation - any query with a different generation will be ignored
905887 queryGeneration += 1
906888 let capturedGeneration = queryGeneration
907889
908- guard !tabManager. tabs [ index] . isExecuting else { return }
909-
910890 tabManager. tabs [ index] . isExecuting = true
911891 tabManager. tabs [ index] . executionTime = nil
912892 tabManager. tabs [ index] . errorMessage = nil
@@ -1019,13 +999,16 @@ struct MainContentView: View {
1019999
10201000 // Find tab by ID (index may have changed) - must update on main thread
10211001 await MainActor . run {
1002+
10221003 // ALWAYS update toolbar state first - user should see query completion
10231004 toolbarState. isExecuting = false
10241005 toolbarState. lastQueryDuration = safeExecutionTime
10251006
10261007 // Only update tab if this is still the most recent query
10271008 // This prevents race conditions when navigating quickly between tables
1028- guard capturedGeneration == queryGeneration else { return }
1009+ guard capturedGeneration == queryGeneration else {
1010+ return
1011+ }
10291012 guard !Task. isCancelled else { return }
10301013
10311014 if let idx = tabManager. tabs. firstIndex ( where: { $0. id == tabId } ) {
@@ -1885,7 +1868,6 @@ struct MainContentView: View {
18851868 let newIndex = tabManager. tabs. firstIndex ( where: { $0. id == newId } )
18861869 {
18871870 let newTab = tabManager. tabs [ newIndex]
1888- print ( " [MainContentView] Tab change: \( oldTabId == nil ? " nil " : " tab " ) -> \( newTab. title) (type: \( newTab. tabType) ) " )
18891871
18901872 // CRITICAL: Update these immediately for UI consistency
18911873 selectedRowIndices = newTab. selectedRowIndices
@@ -1912,38 +1894,22 @@ struct MainContentView: View {
19121894 // Otherwise, if lazy load is skipped due to flag=true, flag never resets!
19131895 let shouldSkipLazyLoad = justRestoredTab
19141896 if justRestoredTab {
1915- print ( " [MainContentView] Resetting justRestoredTab flag " )
19161897 justRestoredTab = false
19171898 }
19181899
1919- // LAZY LOAD: Auto-execute query ONLY for table tabs
1920- // Query tabs require manual execution by user (Cmd+Return)
1921- // Skip if we just restored and executed this tab
1922-
1923- // DEBUG: Log all conditions
1924- print ( " [MainContentView] Lazy load check for \( newTab. title) : " )
1925- print ( " - shouldSkipLazyLoad: \( shouldSkipLazyLoad) " )
1926- print ( " - tabType: \( newTab. tabType) " )
1927- print ( " - resultRows.isEmpty: \( newTab. resultRows. isEmpty) " )
1928- print ( " - lastExecutedAt == nil: \( newTab. lastExecutedAt == nil ) " )
1929- print ( " - has query: \( !newTab. query. trimmingCharacters ( in: . whitespacesAndNewlines) . isEmpty) " )
19301900
19311901 if !shouldSkipLazyLoad &&
19321902 newTab. tabType == . table && // Only auto-execute for table tabs
19331903 newTab. resultRows. isEmpty &&
19341904 newTab. lastExecutedAt == nil &&
19351905 !newTab. query. trimmingCharacters ( in: . whitespacesAndNewlines) . isEmpty {
19361906
1937- // CRITICAL: Check connection before executing
1907+ // Check connection before executing
19381908 if let session = DatabaseManager . shared. currentSession, session. isConnected {
1939- print ( " [MainContentView] Lazy loading data for table tab: \( newTab. title) " )
19401909 runQuery ( )
19411910 } else {
1942- print ( " [MainContentView] Table tab needs data but not connected - setting flag " )
19431911 needsLazyLoad = true
19441912 }
1945- } else {
1946- print ( " [MainContentView] Skipping lazy load (one or more conditions not met) " )
19471913 }
19481914 }
19491915 } else {
@@ -2280,7 +2246,15 @@ struct MainContentView: View {
22802246 // For existing tabs, onChange will restore their saved selection
22812247 if needsQuery {
22822248 selectedRowIndices = [ ]
2283- runQuery ( )
2249+
2250+ // Execute query for new/replaced tabs
2251+ // IMPORTANT: Wrapped in Task to ensure SwiftUI processes tab property updates first
2252+ // - For NEW tabs: selectedTabId changes → onChange fires → lazy load also triggers
2253+ // (both will try to run query, but the second will be blocked by isExecuting guard)
2254+ // - For REPLACED tabs: selectedTabId stays same → onChange doesn't fire → we MUST call runQuery
2255+ Task { @MainActor in
2256+ runQuery ( )
2257+ }
22842258 }
22852259 }
22862260
0 commit comments