@@ -280,11 +280,18 @@ struct QueryTab: Identifiable, Equatable {
280280
281281 // Results — stored in a reference-type buffer to avoid CoW duplication
282282 // of large data when the struct is mutated (MEM-1 fix).
283- // Note: When QueryTab is copied (struct CoW), copies share the same RowBuffer
284- // instance. This is intentional — RowBuffer is a reference type specifically to
285- // avoid duplicating large result arrays on every struct mutation.
283+ //
284+ // Shared reference semantics: When QueryTab is copied (struct CoW), copies share
285+ // the same RowBuffer instance. This is intentional — RowBuffer is a reference type
286+ // specifically to avoid duplicating large result arrays on every struct mutation.
287+ // Mutations to rowBuffer (e.g., evict/restore) affect all copies that share this
288+ // reference. Use `rowBuffer.copy()` when you need an independent snapshot.
286289 var rowBuffer : RowBuffer
287290
291+ /// Whether this tab's row data has been evicted to save memory.
292+ /// Convenience accessor for `rowBuffer.isEvicted`.
293+ var isEvicted : Bool { rowBuffer. isEvicted }
294+
288295 // Backward-compatible computed accessors for result data
289296 var resultColumns : [ String ] {
290297 get { rowBuffer. columns }
@@ -436,34 +443,43 @@ struct QueryTab: Identifiable, Equatable {
436443
437444 /// Build a clean base query for a table tab (no filters/sort).
438445 /// Used when restoring table tabs from persistence to avoid stale WHERE clauses.
439- @MainActor static func buildBaseTableQuery(
446+ ///
447+ /// - Parameters:
448+ /// - tableName: The table to query.
449+ /// - pageSize: Number of rows per page.
450+ /// - editorLanguage: The editor language for this database type.
451+ /// - paginationStyle: SQL pagination style (LIMIT vs OFFSET/FETCH).
452+ /// - offsetFetchOrderBy: ORDER BY clause for OFFSET/FETCH pagination.
453+ /// - pluginDriver: Optional plugin driver for NoSQL query building.
454+ /// - quoteIdentifier: Identifier quoting function.
455+ static func buildBaseTableQuery(
440456 tableName: String ,
441- databaseType: DatabaseType ,
442- quoteIdentifier: ( ( String ) -> String ) ? = nil
457+ pageSize: Int ,
458+ editorLanguage: EditorLanguage = . sql,
459+ paginationStyle: SQLDialectDescriptor . PaginationStyle = . limit,
460+ offsetFetchOrderBy: String = " ORDER BY (SELECT NULL) " ,
461+ pluginDriver: ( any PluginDatabaseDriver ) ? = nil ,
462+ quoteIdentifier: @escaping ( String ) -> String
443463 ) -> String {
444- let quote = quoteIdentifier ?? quoteIdentifierFromDialect ( PluginManager . shared. sqlDialect ( for: databaseType) )
445- let pageSize = AppSettingsManager . shared. dataGrid. defaultPageSize
446-
447464 // Use plugin's query builder when available (NoSQL drivers like etcd, Redis)
448- if let pluginDriver = PluginManager . shared . queryBuildingDriver ( for : databaseType ) ,
465+ if let pluginDriver,
449466 let pluginQuery = pluginDriver. buildBrowseQuery (
450467 table: tableName, sortColumns: [ ] , columns: [ ] , limit: pageSize, offset: 0
451468 ) {
452469 return pluginQuery
453470 }
454471
455- switch PluginManager . shared . editorLanguage ( for : databaseType ) {
472+ switch editorLanguage {
456473 case . javascript:
457474 let escaped = tableName. replacingOccurrences ( of: " \\ " , with: " \\ \\ " ) . replacingOccurrences ( of: " \" " , with: " \\ \" " )
458475 return " db[ \" \( escaped) \" ].find({}).limit( \( pageSize) ) "
459476 case . bash:
460477 return " SCAN 0 MATCH * COUNT \( pageSize) "
461478 default :
462- let quotedName = quote ( tableName)
463- switch PluginManager . shared . paginationStyle ( for : databaseType ) {
479+ let quotedName = quoteIdentifier ( tableName)
480+ switch paginationStyle {
464481 case . offsetFetch:
465- let orderBy = PluginManager . shared. offsetFetchOrderBy ( for: databaseType)
466- return " SELECT * FROM \( quotedName) \( orderBy) OFFSET 0 ROWS FETCH NEXT \( pageSize) ROWS ONLY; "
482+ return " SELECT * FROM \( quotedName) \( offsetFetchOrderBy) OFFSET 0 ROWS FETCH NEXT \( pageSize) ROWS ONLY; "
467483 case . limit:
468484 return " SELECT * FROM \( quotedName) LIMIT \( pageSize) ; "
469485 }
@@ -585,7 +601,13 @@ final class QueryTabManager {
585601
586602 let pageSize = AppSettingsManager . shared. dataGrid. defaultPageSize
587603 let query = QueryTab . buildBaseTableQuery (
588- tableName: tableName, databaseType: databaseType, quoteIdentifier: quoteIdentifier
604+ tableName: tableName,
605+ pageSize: pageSize,
606+ editorLanguage: PluginManager . shared. editorLanguage ( for: databaseType) ,
607+ paginationStyle: PluginManager . shared. paginationStyle ( for: databaseType) ,
608+ offsetFetchOrderBy: PluginManager . shared. offsetFetchOrderBy ( for: databaseType) ,
609+ pluginDriver: PluginManager . shared. queryBuildingDriver ( for: databaseType) ,
610+ quoteIdentifier: quoteIdentifier ?? quoteIdentifierFromDialect ( PluginManager . shared. sqlDialect ( for: databaseType) )
589611 )
590612 var newTab = QueryTab (
591613 title: tableName,
@@ -607,7 +629,13 @@ final class QueryTabManager {
607629 ) {
608630 let pageSize = AppSettingsManager . shared. dataGrid. defaultPageSize
609631 let query = QueryTab . buildBaseTableQuery (
610- tableName: tableName, databaseType: databaseType, quoteIdentifier: quoteIdentifier
632+ tableName: tableName,
633+ pageSize: pageSize,
634+ editorLanguage: PluginManager . shared. editorLanguage ( for: databaseType) ,
635+ paginationStyle: PluginManager . shared. paginationStyle ( for: databaseType) ,
636+ offsetFetchOrderBy: PluginManager . shared. offsetFetchOrderBy ( for: databaseType) ,
637+ pluginDriver: PluginManager . shared. queryBuildingDriver ( for: databaseType) ,
638+ quoteIdentifier: quoteIdentifier ?? quoteIdentifierFromDialect ( PluginManager . shared. sqlDialect ( for: databaseType) )
611639 )
612640 var newTab = QueryTab (
613641 title: tableName,
@@ -638,12 +666,16 @@ final class QueryTabManager {
638666 return false
639667 }
640668
669+ let pageSize = AppSettingsManager . shared. dataGrid. defaultPageSize
641670 let query = QueryTab . buildBaseTableQuery (
642671 tableName: tableName,
643- databaseType: databaseType,
644- quoteIdentifier: quoteIdentifier
672+ pageSize: pageSize,
673+ editorLanguage: PluginManager . shared. editorLanguage ( for: databaseType) ,
674+ paginationStyle: PluginManager . shared. paginationStyle ( for: databaseType) ,
675+ offsetFetchOrderBy: PluginManager . shared. offsetFetchOrderBy ( for: databaseType) ,
676+ pluginDriver: PluginManager . shared. queryBuildingDriver ( for: databaseType) ,
677+ quoteIdentifier: quoteIdentifier ?? quoteIdentifierFromDialect ( PluginManager . shared. sqlDialect ( for: databaseType) )
645678 )
646- let pageSize = AppSettingsManager . shared. dataGrid. defaultPageSize
647679
648680 // Build locally and write back once to avoid 14 CoW copies (UI-11).
649681 var tab = tabs [ selectedIndex]
0 commit comments