From 16ef4b8ac2ac879ca8bc92149c9e954438d44275 Mon Sep 17 00:00:00 2001 From: "rosenfield.albert" Date: Tue, 31 Mar 2009 09:22:09 +0000 Subject: [PATCH] Remove accurate row counting, as requested by InnoDB users. Also removed for MyISAM, for ease of maintenance. 10.000 rows is guessed at, and the scrollbar is adjusted to a constant +20% of seen/guessed rows. Fixes issue #940. --- source/main.pas | 147 ++++++++++++++++++++++++++++++------------------ 1 file changed, 93 insertions(+), 54 deletions(-) diff --git a/source/main.pas b/source/main.pas index 74beb923..049ca3ad 100644 --- a/source/main.pas +++ b/source/main.pas @@ -24,6 +24,15 @@ uses mysqlquery, createdatabase, createtable, tbl_properties, SynRegExpr, WideStrUtils, ZDbcLogging, ExtActns, CommCtrl, routine_editor, options; +const + // The InnoDB folks are raging over the lack of count(*) support + // in the storage engine. To avoid count(*), the first of these + // constants decide how many rows the data area should estimate + // in any table. The second value decides how many percent above the + // number of seen (or simulated) rows the scrollbar should project. + SIMULATE_INITIAL_ROWS = 10000; + SIMULATE_MORE_ROWS = 20; + type TMainForm = class(TForm) MainMenu1: TMainMenu; @@ -740,10 +749,12 @@ type procedure LoadRecentFilter(Sender: TObject); procedure actCreateRoutineExecute(Sender: TObject); procedure actEditRoutineExecute(Sender: TObject); + procedure DataGridScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer); procedure ListTablesEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; var Allowed: Boolean); procedure DBtreeExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode); private + ReachedEOT : Boolean; FDelimiter: String; ServerUptime : Integer; time_connected : Cardinal; @@ -779,7 +790,7 @@ type function GetActiveData: PGridResult; procedure WaitForQueryCompletion(WaitForm: TfrmQueryProgress; query: TMySqlQuery; ForceDialog: Boolean); function RunThreadedQuery(AQuery: WideString; ForceDialog: Boolean): TMysqlQuery; - procedure DisplayRowCountStats(MatchingRows: Int64); + procedure DisplayRowCountStats(MatchingRows: Int64 = -1); procedure insertFunction(Sender: TObject); function GetActiveDatabase: WideString; function GetSelectedTable: WideString; @@ -856,6 +867,7 @@ type FDataGridSort : TOrderColArray; DataGridCurrentSelect, DataGridCurrentFullSelect, + DataGridCurrentFrom, DataGridCurrentFilter, DataGridCurrentSort : WideString; @@ -3518,7 +3530,6 @@ var rx : TRegExpr; ColType : String; ColExists, ShowIt : Boolean; - Count, MatchingRows : Int64; OldOffsetXY : TPoint; procedure InitColumn(name: WideString; ColType: String; Visible: Boolean); @@ -3735,8 +3746,9 @@ begin select_from := ' FROM '+mask(ActiveDatabase)+'.'+mask(SelectedTable); // Final SELECT segments - DataGridCurrentSelect := select_base + select_from; - DataGridCurrentFullSelect := select_base_full + select_from; + DataGridCurrentSelect := select_base; + DataGridCurrentFullSelect := select_base_full; + DataGridCurrentFrom := select_from; DataGridCurrentFilter := SynMemoFilter.Text; if Length(FDataGridSort) > 0 then DataGridCurrentSort := ComposeOrderClause(FDataGridSort) @@ -3749,38 +3761,15 @@ begin if DataGridCurrentSort <> '' then tbtnDataSorting.ImageIndex := 108 else tbtnDataSorting.ImageIndex := 107; - try - ShowStatus('Counting rows...'); - sl_query.Add('SELECT COUNT(*)'); - sl_query.Add(select_from); - // Apply custom WHERE filter - if DataGridCurrentFilter <> '' then sl_query.Add('WHERE ' + DataGridCurrentFilter); - MatchingRows := MakeInt(GetVar(sl_query.Text)); - count := MatchingRows; - if count > GRIDMAXTOTALROWS then - count := GRIDMAXTOTALROWS; - except - on E:Exception do begin - // Most likely we have a wrong filter-clause when this happens - // Put the user with his nose onto the wrong filter - // either specified by user or - // created by HeidiSQL by using the search box - SynMemoFilter.Color := $008080FF; // light pink - DataGrid.Header.Options := DataGrid.Header.Options - [hoVisible]; - MessageDlg( E.Message, mtError, [mbOK], 0 ); - raise; - end; - end; - ShowStatus( STATUS_MSG_READY ); - debug('mem: initializing browse rows (internal data).'); try - SetLength(FDataGridResult.Rows, count); - for i := 0 to count - 1 do begin + ReachedEOT := False; + SetLength(FDataGridResult.Rows, SIMULATE_INITIAL_ROWS * (100 + SIMULATE_MORE_ROWS) div 100); + for i := 0 to SIMULATE_INITIAL_ROWS * (100 + SIMULATE_MORE_ROWS) div 100 - 1 do begin FDataGridResult.Rows[i].Loaded := False; end; debug('mem: initializing browse rows (grid).'); - DataGrid.RootNodeCount := count; + DataGrid.RootNodeCount := SIMULATE_INITIAL_ROWS * (100 + SIMULATE_MORE_ROWS) div 100; except DataGrid.RootNodeCount := 0; SetLength(FDataGridResult.Rows, 0); @@ -3794,7 +3783,7 @@ begin DataGrid.OffsetXY := Point(0, 0); // Scroll to top left FreeAndNil(PrevTableColWidths); // Throw away remembered, manually resized column widths end; - DisplayRowCountStats(MatchingRows); + DisplayRowCountStats(); dataselected := true; PageControlMainChange(Self); @@ -3841,27 +3830,20 @@ begin break; end; end; - if rows_total = -1 then begin - // Fallback for cases in which the user checked the "Prefer SHOW TABLES" option - rows_total := StrToInt64( GetVar( 'SELECT COUNT(*) FROM ' + mask( SelectedTable ), 0 ) ); + + if rows_total > -1 then begin + lblDataTop.Caption := lblDataTop.Caption + FormatNumber(rows_total) + ' rows total'; + if IsInnodb then lblDataTop.Caption := lblDataTop.Caption + ' (approximately)'; + end; + + if MatchingRows = GRIDMAXTOTALROWS then begin + lblDataTop.Caption := lblDataTop.Caption + ', limited to ' + FormatNumber( GRIDMAXTOTALROWS); + end else if MatchingRows = rows_total then begin + lblDataTop.Caption := lblDataTop.Caption + ', filter matches all rows'; + end else if IsFiltered and (MatchingRows > -1) then begin + lblDataTop.Caption := lblDataTop.Caption + ', ' + FormatNumber(MatchingRows) + ' matches filter'; end; - lblDataTop.Caption := lblDataTop.Caption + FormatNumber( rows_total ) + ' rows total'; - if IsInnodb then - lblDataTop.Caption := lblDataTop.Caption + ' (approximately!)' - end else begin - // Don't fetch rowcount from views to fix bug #1844952 - rows_total := -1; - lblDataTop.Caption := lblDataTop.Caption + ' [View]'; end; - - if( MatchingRows <> rows_total ) and IsFiltered then - lblDataTop.Caption := lblDataTop.Caption + ', ' + FormatNumber(MatchingRows) + ' matching to filter'; - - if ( MatchingRows >= rows_total ) and IsFiltered then - lblDataTop.Caption := lblDataTop.Caption + ', filter matches all rows'; - - if MatchingRows > DataGrid.RootNodeCount then - lblDataTop.Caption := lblDataTop.Caption + ', limited to '+FormatNumber(DataGrid.RootNodeCount); end; @@ -7621,7 +7603,7 @@ begin if Sender = DataGrid then res := @FDataGridResult else res := @FQueryGridResult; if (not res.Rows[Node.Index].Loaded) and (res.Rows[Node.Index].State <> grsInserted) then begin - query := DataGridCurrentSelect; + query := DataGridCurrentSelect + DataGridCurrentFrom; // Passed WhereClause has prio over current filter, fixes bug #754 if WhereClause <> '' then begin query := query + ' WHERE ' + WhereClause; @@ -7672,6 +7654,7 @@ var query: WideString; ds: TDataSet; i, j: LongInt; + hi: LongInt; regCrashIndicName: String; begin if Sender = DataGrid then res := @FDataGridResult @@ -7681,9 +7664,9 @@ begin limit := TVirtualStringTree(Sender).RootNodeCount - start; if limit > GridMaxRows then limit := GridMaxRows; if FullWidth then - query := DataGridCurrentFullSelect + query := DataGridCurrentFullSelect + DataGridCurrentFrom else - query := DataGridCurrentSelect; + query := DataGridCurrentSelect + DataGridCurrentFrom; if DataGridCurrentFilter <> '' then query := query + ' WHERE ' + DataGridCurrentFilter; if DataGridCurrentSort <> '' then query := query + ' ORDER BY ' + DataGridCurrentSort; query := query + WideFormat(' LIMIT %d, %d', [start, limit]); @@ -7701,6 +7684,16 @@ begin limit := ds.RecordCount; TVirtualStringTree(Sender).RootNodeCount := start + limit; SetLength(res.Rows, start + limit); + ReachedEOT := true; + end; + if not ReachedEOT then begin + hi := start + limit; + if hi < SIMULATE_INITIAL_ROWS then hi := SIMULATE_INITIAL_ROWS; + hi := hi * (100 + SIMULATE_MORE_ROWS) div 100; + Sender.BeginUpdate; + TVirtualStringTree(Sender).RootNodeCount := Cardinal(hi); + SetLength(res.Rows, hi); + Sender.EndUpdate; end; debug(Format('mem: loaded data chunk from row %d to %d', [start, limit])); @@ -9236,6 +9229,52 @@ begin RoutineEditForm.ShowModal; end; +procedure TMainForm.DataGridScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer); +var + query: String; + count: Int64; +begin + // If the user moves the scrollbar all the way to the bottom of the data grid, + // for example by pressing CTRL+END, jump to the bottom of table data. + if ReachedEOT then Exit; + if tsThumbTracking in Sender.TreeStates then Exit; + if Int64(- Sender.OffsetY - DeltaY) < Int64(Sender.RootNode.TotalHeight) then Exit; + + // First, figure out how many rows the table contains. + ShowStatus('Counting rows...'); + query := 'SELECT COUNT(*)' + DataGridCurrentFrom; + if DataGridCurrentFilter <> '' then query := query + ' WHERE ' + DataGridCurrentFilter; + try + count := MakeInt(GetVar(query)); + // Work around a memory allocation bug in VirtualTree. + if count > GRIDMAXTOTALROWS then count := GRIDMAXTOTALROWS; + except + on E: Exception do begin + MessageDlg(E.Message, mtError, [mbOK], 0); + Exit; + end; + end; + ShowStatus(STATUS_MSG_READY); + + // Then, adjust the data grid and data containers. + debug('mem: initializing browse rows (internal data).'); + try + SetLength(FDataGridResult.Rows, count); + debug('mem: initializing browse rows (grid).'); + DataGrid.RootNodeCount := count; + ReachedEOT := True; + DisplayRowCountStats(count); + except + DataGrid.RootNodeCount := 0; + SetLength(FDataGridResult.Rows, 0); + PageControlMain.ActivePage := tabTable; + raise; + end; + + // Finally, jump to the last row. + Sender.ScrollIntoView(Sender.GetLast, False); +end; + procedure TMainForm.DBtreeExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode);