mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-26 19:20:17 +08:00
Implement a second tab on the table tools dialog: "Find text on server". Scans all tables with OR'd LIKE clauses for a given text. User can restrict that search to a data type category (integer, text, etc.). Fixes issue #529.
This commit is contained in:
@ -160,6 +160,8 @@ const
|
||||
REGNAME_TOOLSWINWIDTH = 'TableTools_WindowWidth';
|
||||
REGNAME_TOOLSWINHEIGHT = 'TableTools_WindowHeight';
|
||||
REGNAME_TOOLSTREEWIDTH = 'TableTools_TreeWidth';
|
||||
REGNAME_TOOLSFINDTEXT = 'TableTools_FindText';
|
||||
REGNAME_TOOLSSKIPMB = 'TableTools_SkipMB';
|
||||
REGNAME_USERMNGR_WINWIDTH = 'Usermanager_WindowWidth';
|
||||
REGNAME_USERMNGR_WINHEIGHT = 'Usermanager_WindowHeight';
|
||||
REGNAME_SELECTDBO_WINWIDTH = 'SelectDBO_WindowWidth';
|
||||
|
@ -196,6 +196,8 @@ type
|
||||
procedure SelectNode(VT: TVirtualStringTree; Node: PVirtualNode); overload;
|
||||
function DateBackFriendlyCaption(d: TDateTime): String;
|
||||
procedure InheritFont(AFont: TFont);
|
||||
function FieldContent(ds: TDataSet; ColName: WideString): WideString;
|
||||
function GetTableSize(ds: TDataSet): Int64;
|
||||
var
|
||||
MainReg : TRegistry;
|
||||
|
||||
@ -3077,6 +3079,26 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
// Fetch content from a row cell, avoiding NULLs to cause AVs
|
||||
function FieldContent(ds: TDataSet; ColName: WideString): WideString;
|
||||
begin
|
||||
Result := '';
|
||||
if (ds.FindField(colName) <> nil) and (not ds.FindField(ColName).IsNull) then
|
||||
Result := ds.FieldByName(ColName).AsWideString;
|
||||
end;
|
||||
|
||||
|
||||
function GetTableSize(ds: TDataSet): Int64;
|
||||
var
|
||||
d, i: String;
|
||||
begin
|
||||
d := FieldContent(ds, 'Data_length');
|
||||
i := FieldContent(ds, 'Index_length');
|
||||
if (d = '') or (i = '') then Result := -1
|
||||
else Result := MakeInt(d) + MakeInt(i);
|
||||
end;
|
||||
|
||||
|
||||
end.
|
||||
|
||||
|
||||
|
@ -1515,6 +1515,9 @@ object MainForm: TMainForm
|
||||
object menuMaintenance: TMenuItem
|
||||
Action = actMaintenance
|
||||
end
|
||||
object actFindTextOnServer1: TMenuItem
|
||||
Action = actFindTextOnServer
|
||||
end
|
||||
object N7: TMenuItem
|
||||
Caption = '-'
|
||||
end
|
||||
@ -1703,6 +1706,14 @@ object MainForm: TMainForm
|
||||
ImageIndex = 39
|
||||
OnExecute = actMaintenanceExecute
|
||||
end
|
||||
object actFindTextOnServer: TAction
|
||||
Category = 'Tools'
|
||||
Caption = 'Find text on server'
|
||||
Hint = 'Searches selected tables for text occurences'
|
||||
ImageIndex = 30
|
||||
ShortCut = 24646
|
||||
OnExecute = actFindTextOnServerExecute
|
||||
end
|
||||
object actCopyAsHTML: TAction
|
||||
Tag = 49
|
||||
Category = 'Export/Import'
|
||||
@ -6070,6 +6081,9 @@ object MainForm: TMainForm
|
||||
object menuMaintenance2: TMenuItem
|
||||
Action = actMaintenance
|
||||
end
|
||||
object Findtextonserver1: TMenuItem
|
||||
Action = actFindTextOnServer
|
||||
end
|
||||
object menuEmptyTables: TMenuItem
|
||||
Action = actEmptyTables
|
||||
end
|
||||
|
@ -449,6 +449,9 @@ type
|
||||
actFilterPanel: TAction;
|
||||
actFindInVT1: TMenuItem;
|
||||
TimerFilterVT: TTimer;
|
||||
actFindTextOnServer: TAction;
|
||||
actFindTextOnServer1: TMenuItem;
|
||||
Findtextonserver1: TMenuItem;
|
||||
procedure refreshMonitorConfig;
|
||||
procedure loadWindowConfig;
|
||||
procedure saveWindowConfig;
|
||||
@ -545,7 +548,6 @@ type
|
||||
procedure ValidateControls(Sender: TObject);
|
||||
procedure ValidateQueryControls(Sender: TObject);
|
||||
procedure RefreshQueryHelpers;
|
||||
function FieldContent(ds: TDataSet; ColName: WideString): WideString;
|
||||
procedure LoadDatabaseProperties(db: WideString);
|
||||
procedure ShowHost;
|
||||
procedure ShowDatabase(db: WideString);
|
||||
@ -733,6 +735,7 @@ type
|
||||
procedure comboOnlyDBsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
|
||||
procedure actFilterPanelExecute(Sender: TObject);
|
||||
procedure TimerFilterVTTimer(Sender: TObject);
|
||||
procedure actFindTextOnServerExecute(Sender: TObject);
|
||||
private
|
||||
ReachedEOT : Boolean;
|
||||
FDelimiter: String;
|
||||
@ -778,7 +781,6 @@ type
|
||||
function GetSelectedTable: TListNode;
|
||||
procedure SetSelectedDatabase(db: WideString);
|
||||
procedure SetVisibleListColumns( List: TVirtualStringTree; Columns: WideStrings.TWideStringList );
|
||||
function GetTableSize(ds: TDataSet): Int64;
|
||||
procedure ToggleFilterPanel(ForceVisible: Boolean = False);
|
||||
function GetSelectedTableColumns: TDataset;
|
||||
function GetSelectedTableKeys: TDataset;
|
||||
@ -1972,6 +1974,16 @@ begin
|
||||
// optimize / repair... tables
|
||||
if TableToolsDialog = nil then
|
||||
TableToolsDialog := TfrmTableTools.Create(Self);
|
||||
TableToolsDialog.PageControlTools.ActivePage := TableToolsDialog.tabMaintenance;
|
||||
TableToolsDialog.ShowModal;
|
||||
end;
|
||||
|
||||
procedure TMainForm.actFindTextOnServerExecute(Sender: TObject);
|
||||
begin
|
||||
// Find text on server
|
||||
if TableToolsDialog = nil then
|
||||
TableToolsDialog := TfrmTableTools.Create(Self);
|
||||
TableToolsDialog.PageControlTools.ActivePage := TableToolsDialog.tabFind;
|
||||
TableToolsDialog.ShowModal;
|
||||
end;
|
||||
|
||||
@ -4021,18 +4033,6 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
// Fetch content from a row cell, avoiding NULLs to cause AVs
|
||||
function TMainForm.FieldContent(ds: TDataSet; ColName: WideString): WideString;
|
||||
begin
|
||||
Result := '';
|
||||
if
|
||||
(ds.FindField(colName) <> nil) and
|
||||
(not ds.FindField(ColName).IsNull)
|
||||
then
|
||||
Result := ds.FieldByName(ColName).AsWideString;
|
||||
end;
|
||||
|
||||
|
||||
procedure TMainForm.LoadDatabaseProperties(db: WideString);
|
||||
var
|
||||
i, img : Integer;
|
||||
@ -7171,16 +7171,6 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
function TMainForm.GetTableSize(ds: TDataSet): Int64;
|
||||
var
|
||||
d, i: String;
|
||||
begin
|
||||
d := FieldContent(ds, 'Data_length');
|
||||
i := FieldContent(ds, 'Index_length');
|
||||
if (d = '') or (i = '') then Result := -1
|
||||
else Result := MakeInt(d) + MakeInt(i);
|
||||
end;
|
||||
|
||||
function TMainForm.DbTableListCachedAndValid(db: WideString): Boolean;
|
||||
var
|
||||
ds: TDataSet;
|
||||
|
@ -96,7 +96,7 @@ object frmTableTools: TfrmTableTools
|
||||
object lblResults: TLabel
|
||||
AlignWithMargins = True
|
||||
Left = 0
|
||||
Top = 164
|
||||
Top = 191
|
||||
Width = 380
|
||||
Height = 13
|
||||
Margins.Left = 0
|
||||
@ -106,9 +106,9 @@ object frmTableTools: TfrmTableTools
|
||||
end
|
||||
object ResultGrid: TVirtualStringTree
|
||||
Left = 0
|
||||
Top = 180
|
||||
Top = 207
|
||||
Width = 380
|
||||
Height = 156
|
||||
Height = 129
|
||||
Align = alClient
|
||||
Header.AutoSizeIndex = -1
|
||||
Header.DefaultHeight = 17
|
||||
@ -138,11 +138,11 @@ object frmTableTools: TfrmTableTools
|
||||
Top = 0
|
||||
Width = 380
|
||||
Height = 161
|
||||
ActivePage = Maintenance
|
||||
ActivePage = tabMaintenance
|
||||
Align = alTop
|
||||
Images = MainForm.PngImageListMain
|
||||
TabOrder = 1
|
||||
object Maintenance: TTabSheet
|
||||
object tabMaintenance: TTabSheet
|
||||
Caption = 'Maintenance'
|
||||
ImageIndex = 39
|
||||
DesignSize = (
|
||||
@ -188,7 +188,7 @@ object frmTableTools: TfrmTableTools
|
||||
Height = 17
|
||||
Caption = 'Quick'
|
||||
TabOrder = 1
|
||||
OnClick = MaintenanceOptionClick
|
||||
OnClick = ValidateControls
|
||||
end
|
||||
object chkFast: TCheckBox
|
||||
Left = 81
|
||||
@ -197,7 +197,7 @@ object frmTableTools: TfrmTableTools
|
||||
Height = 17
|
||||
Caption = 'Fast'
|
||||
TabOrder = 2
|
||||
OnClick = MaintenanceOptionClick
|
||||
OnClick = ValidateControls
|
||||
end
|
||||
object chkMedium: TCheckBox
|
||||
Left = 81
|
||||
@ -206,7 +206,7 @@ object frmTableTools: TfrmTableTools
|
||||
Height = 17
|
||||
Caption = 'Medium'
|
||||
TabOrder = 3
|
||||
OnClick = MaintenanceOptionClick
|
||||
OnClick = ValidateControls
|
||||
end
|
||||
object chkExtended: TCheckBox
|
||||
Left = 184
|
||||
@ -215,7 +215,7 @@ object frmTableTools: TfrmTableTools
|
||||
Height = 17
|
||||
Caption = 'Extended'
|
||||
TabOrder = 4
|
||||
OnClick = MaintenanceOptionClick
|
||||
OnClick = ValidateControls
|
||||
end
|
||||
object chkChanged: TCheckBox
|
||||
Left = 184
|
||||
@ -224,7 +224,7 @@ object frmTableTools: TfrmTableTools
|
||||
Height = 17
|
||||
Caption = 'Changed'
|
||||
TabOrder = 5
|
||||
OnClick = MaintenanceOptionClick
|
||||
OnClick = ValidateControls
|
||||
end
|
||||
object btnExecuteMaintenance: TButton
|
||||
Left = 80
|
||||
@ -242,7 +242,7 @@ object frmTableTools: TfrmTableTools
|
||||
Height = 17
|
||||
Caption = 'Use FRM file'
|
||||
TabOrder = 7
|
||||
OnClick = MaintenanceOptionClick
|
||||
OnClick = ValidateControls
|
||||
end
|
||||
object btnHelp: TButton
|
||||
Left = 294
|
||||
@ -255,6 +255,97 @@ object frmTableTools: TfrmTableTools
|
||||
OnClick = btnHelpClick
|
||||
end
|
||||
end
|
||||
object tabFindInDB: TTabSheet
|
||||
Caption = 'Find text'
|
||||
ImageIndex = 30
|
||||
DesignSize = (
|
||||
372
|
||||
132)
|
||||
object lblFindText: TLabel
|
||||
Left = 3
|
||||
Top = 14
|
||||
Width = 60
|
||||
Height = 13
|
||||
Caption = 'Text to find:'
|
||||
end
|
||||
object lblDataTypes: TLabel
|
||||
Left = 80
|
||||
Top = 77
|
||||
Width = 151
|
||||
Height = 13
|
||||
Caption = 'Restrict search to column types'
|
||||
end
|
||||
object memoFindText: TTntMemo
|
||||
Left = 80
|
||||
Top = 11
|
||||
Width = 289
|
||||
Height = 57
|
||||
Anchors = [akLeft, akTop, akRight, akBottom]
|
||||
ScrollBars = ssVertical
|
||||
TabOrder = 0
|
||||
OnChange = ValidateControls
|
||||
end
|
||||
object btnFindText: TButton
|
||||
Left = 80
|
||||
Top = 99
|
||||
Width = 75
|
||||
Height = 25
|
||||
Anchors = [akLeft, akBottom]
|
||||
Caption = 'Find'
|
||||
TabOrder = 1
|
||||
OnClick = ExecuteOperation
|
||||
end
|
||||
object comboDataTypes: TComboBox
|
||||
Left = 264
|
||||
Top = 74
|
||||
Width = 105
|
||||
Height = 21
|
||||
Style = csDropDownList
|
||||
Anchors = [akLeft, akTop, akRight]
|
||||
ItemHeight = 13
|
||||
TabOrder = 2
|
||||
end
|
||||
end
|
||||
end
|
||||
object pnlSkipLargeTables: TPanel
|
||||
Left = 0
|
||||
Top = 161
|
||||
Width = 380
|
||||
Height = 27
|
||||
Align = alTop
|
||||
BevelOuter = bvNone
|
||||
TabOrder = 2
|
||||
object lblSkipLargeTables: TLabel
|
||||
Left = 0
|
||||
Top = 6
|
||||
Width = 107
|
||||
Height = 13
|
||||
Caption = 'Skip tables larger than'
|
||||
end
|
||||
object lblSkipLargeTablesMB: TLabel
|
||||
Left = 184
|
||||
Top = 6
|
||||
Width = 87
|
||||
Height = 13
|
||||
Caption = 'MB (0 = unlimited)'
|
||||
end
|
||||
object editSkipLargeTables: TEdit
|
||||
Left = 122
|
||||
Top = 3
|
||||
Width = 40
|
||||
Height = 21
|
||||
TabOrder = 0
|
||||
Text = '20'
|
||||
end
|
||||
object udSkipLargeTables: TUpDown
|
||||
Left = 162
|
||||
Top = 3
|
||||
Width = 16
|
||||
Height = 21
|
||||
Associate = editSkipLargeTables
|
||||
Position = 20
|
||||
TabOrder = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -10,7 +10,7 @@ interface
|
||||
|
||||
uses
|
||||
Windows, SysUtils, Classes, Controls, Forms, StdCtrls, ComCtrls, Buttons,
|
||||
WideStrings, WideStrUtils, VirtualTrees, ExtCtrls, Db, Contnrs, Graphics;
|
||||
WideStrings, WideStrUtils, VirtualTrees, ExtCtrls, Db, Contnrs, Graphics, TntStdCtrls;
|
||||
|
||||
type
|
||||
TfrmTableTools = class(TForm)
|
||||
@ -22,7 +22,7 @@ type
|
||||
ResultGrid: TVirtualStringTree;
|
||||
lblResults: TLabel;
|
||||
PageControlTools: TPageControl;
|
||||
Maintenance: TTabSheet;
|
||||
tabMaintenance: TTabSheet;
|
||||
comboOperation: TComboBox;
|
||||
lblOperation: TLabel;
|
||||
chkQuick: TCheckBox;
|
||||
@ -34,6 +34,17 @@ type
|
||||
chkUseFrm: TCheckBox;
|
||||
lblOptions: TLabel;
|
||||
btnHelp: TButton;
|
||||
tabFindInDB: TTabSheet;
|
||||
lblFindText: TLabel;
|
||||
memoFindText: TTntMemo;
|
||||
btnFindText: TButton;
|
||||
comboDataTypes: TComboBox;
|
||||
lblDataTypes: TLabel;
|
||||
pnlSkipLargeTables: TPanel;
|
||||
lblSkipLargeTables: TLabel;
|
||||
editSkipLargeTables: TEdit;
|
||||
udSkipLargeTables: TUpDown;
|
||||
lblSkipLargeTablesMB: TLabel;
|
||||
procedure FormDestroy(Sender: TObject);
|
||||
procedure FormCreate(Sender: TObject);
|
||||
procedure FormShow(Sender: TObject);
|
||||
@ -53,18 +64,20 @@ type
|
||||
procedure ResultGridGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
|
||||
TextType: TVSTTextType; var CellText: WideString);
|
||||
procedure TreeObjectsChecked(Sender: TBaseVirtualTree; Node: PVirtualNode);
|
||||
procedure MaintenanceOptionClick(Sender: TObject);
|
||||
procedure ResultGridHeaderClick(Sender: TVTHeader; HitInfo: TVTHeaderHitInfo);
|
||||
procedure ResultGridCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode;
|
||||
Column: TColumnIndex; var Result: Integer);
|
||||
procedure ResultGridPaintText(Sender: TBaseVirtualTree; const TargetCanvas: TCanvas; Node: PVirtualNode;
|
||||
Column: TColumnIndex; TextType: TVSTTextType);
|
||||
procedure ValidateControls(Sender: TObject);
|
||||
private
|
||||
{ Private declarations }
|
||||
FResults: TObjectList;
|
||||
procedure ValidateControls(Sender: TObject);
|
||||
FRealResultCounter: Integer;
|
||||
procedure ProcessTableNode(Sender: TObject; Node: PVirtualNode);
|
||||
procedure AddResults(SQL: WideString);
|
||||
procedure AddNotes(Col1, Col2, Col3, Col4: WideString);
|
||||
procedure UpdateResultGrid;
|
||||
public
|
||||
{ Public declarations }
|
||||
end;
|
||||
@ -72,17 +85,28 @@ type
|
||||
|
||||
implementation
|
||||
|
||||
uses main, helpers;
|
||||
uses main, helpers, mysql_structures;
|
||||
|
||||
const
|
||||
STRSKIPPED = 'Skipped - ';
|
||||
|
||||
{$R *.DFM}
|
||||
|
||||
|
||||
procedure TfrmTableTools.FormCreate(Sender: TObject);
|
||||
var
|
||||
i: Integer;
|
||||
begin
|
||||
// Restore GUI setup
|
||||
Width := GetRegValue(REGNAME_TOOLSWINWIDTH, Width);
|
||||
Height := GetRegValue(REGNAME_TOOLSWINHEIGHT, Height);
|
||||
TreeObjects.Width := GetRegValue(REGNAME_TOOLSTREEWIDTH, TreeObjects.Width);
|
||||
memoFindText.Text := Utf8Decode(GetRegValue(REGNAME_TOOLSFINDTEXT, ''));
|
||||
comboDatatypes.Items.Add('All data types');
|
||||
for i:=Low(DatatypeCategories) to High(DatatypeCategories) do
|
||||
comboDatatypes.Items.Add(DatatypeCategories[i].Name);
|
||||
comboDatatypes.ItemIndex := GetRegValue(REGNAME_TOOLSDATATYPE, 0);
|
||||
udSkipLargeTables.Position := GetRegValue(REGNAME_TOOLSSKIPMB, udSkipLargeTables.Position);
|
||||
SetWindowSizeGrip( Self.Handle, True );
|
||||
InheritFont(Font);
|
||||
FixVT(TreeObjects);
|
||||
@ -99,6 +123,9 @@ begin
|
||||
MainReg.WriteInteger( REGNAME_TOOLSWINWIDTH, Width );
|
||||
MainReg.WriteInteger( REGNAME_TOOLSWINHEIGHT, Height );
|
||||
MainReg.WriteInteger( REGNAME_TOOLSTREEWIDTH, TreeObjects.Width);
|
||||
MainReg.WriteString( REGNAME_TOOLSFINDTEXT, Utf8Encode(memoFindText.Text));
|
||||
MainReg.WriteInteger( REGNAME_TOOLSSKIPMB, udSkipLargeTables.Position);
|
||||
MainReg.WriteInteger( REGNAME_TOOLSDATATYPE, comboDatatypes.ItemIndex);
|
||||
end;
|
||||
|
||||
|
||||
@ -130,9 +157,12 @@ end;
|
||||
|
||||
|
||||
procedure TfrmTableTools.ValidateControls(Sender: TObject);
|
||||
var
|
||||
SomeChecked: Boolean;
|
||||
begin
|
||||
btnExecuteMaintenance.Enabled := (Pos(STR_NOTSUPPORTED, comboOperation.Text) = 0) and
|
||||
(TreeObjects.CheckedCount > 0);
|
||||
SomeChecked := TreeObjects.CheckedCount > 0;
|
||||
btnExecuteMaintenance.Enabled := (Pos(STR_NOTSUPPORTED, comboOperation.Text) = 0) and SomeChecked;
|
||||
btnFindText.Enabled := SomeChecked and (memoFindText.Text <> '');
|
||||
// CHECKSUM's options are mutually exclusive
|
||||
if comboOperation.Text = 'Checksum' then begin
|
||||
if (Sender = chkExtended) and chkExtended.Checked then chkQuick.Checked := False
|
||||
@ -205,11 +235,6 @@ begin
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmTableTools.MaintenanceOptionClick(Sender: TObject);
|
||||
begin
|
||||
ValidateControls(Sender);
|
||||
end;
|
||||
|
||||
procedure TfrmTableTools.ExecuteOperation(Sender: TObject);
|
||||
var
|
||||
DBNode, TableNode: PVirtualNode;
|
||||
@ -217,6 +242,7 @@ begin
|
||||
Screen.Cursor := crHourGlass;
|
||||
ResultGrid.Clear;
|
||||
FResults.Clear;
|
||||
FRealResultCounter := 0;
|
||||
TreeObjects.SetFocus;
|
||||
DBNode := TreeObjects.GetFirstChild(TreeObjects.GetFirst);
|
||||
while Assigned(DBNode) do begin
|
||||
@ -235,20 +261,76 @@ end;
|
||||
|
||||
procedure TfrmTableTools.ProcessTableNode(Sender: TObject; Node: PVirtualNode);
|
||||
var
|
||||
SQL: WideString;
|
||||
SQL, db, table, QuotedTable: WideString;
|
||||
TableSize, RowsInTable: Int64;
|
||||
ds: TDataset;
|
||||
i: Integer;
|
||||
HasSelectedDatatype: Boolean;
|
||||
begin
|
||||
// Prepare SQL for one table node
|
||||
if (csCheckedNormal in [Node.CheckState, Node.Parent.CheckState]) and
|
||||
(Node.CheckType <> ctNone) then begin
|
||||
SQL := UpperCase(comboOperation.Text) + ' TABLE ' +
|
||||
Mainform.mask(TreeObjects.Text[Node.Parent, 0])+'.'+Mainform.mask(TreeObjects.Text[Node, 0]);
|
||||
if chkQuick.Enabled and chkQuick.Checked then SQL := SQL + ' QUICK';
|
||||
if chkFast.Enabled and chkFast.Checked then SQL := SQL + ' FAST';
|
||||
if chkMedium.Enabled and chkMedium.Checked then SQL := SQL + ' MEDIUM';
|
||||
if chkExtended.Enabled and chkExtended.Checked then SQL := SQL + ' EXTENDED';
|
||||
if chkChanged.Enabled and chkChanged.Checked then SQL := SQL + ' CHANGED';
|
||||
if chkUseFrm.Enabled and chkUseFrm.Checked then SQL := SQL + ' USE_FRM';
|
||||
AddResults(SQL);
|
||||
if (csCheckedNormal in [Node.CheckState, Node.Parent.CheckState]) and (Node.CheckType <> ctNone) then begin
|
||||
db := TreeObjects.Text[Node.Parent, 0];
|
||||
table := TreeObjects.Text[Node, 0];
|
||||
QuotedTable := Mainform.mask(db)+'.'+Mainform.mask(table);
|
||||
// Find table in cashed dataset and check its size - perhaps it has to be skipped
|
||||
TableSize := 0;
|
||||
RowsInTable := 0;
|
||||
ds := Mainform.FetchDbTableList(db);
|
||||
while not ds.Eof do begin
|
||||
if (ds.FieldByName(DBO_NAME).AsWideString = table)
|
||||
and (GetDBObjectType(ds.Fields) in [lntTable, lntCrashedTable]) then begin
|
||||
TableSize := GetTableSize(ds);
|
||||
RowsInTable := MakeInt(ds.FieldByName(DBO_ROWS).AsString);
|
||||
// Avoid division by zero in below SQL
|
||||
if RowsInTable = 0 then
|
||||
RowsInTable := 1;
|
||||
break;
|
||||
end;
|
||||
ds.Next;
|
||||
end;
|
||||
if (udSkipLargeTables.Position = 0) or ((TableSize div SIZE_MB) < udSkipLargeTables.Position) then try
|
||||
if Sender = btnExecuteMaintenance then begin
|
||||
SQL := UpperCase(comboOperation.Text) + ' TABLE ' + QuotedTable;
|
||||
if chkQuick.Enabled and chkQuick.Checked then SQL := SQL + ' QUICK';
|
||||
if chkFast.Enabled and chkFast.Checked then SQL := SQL + ' FAST';
|
||||
if chkMedium.Enabled and chkMedium.Checked then SQL := SQL + ' MEDIUM';
|
||||
if chkExtended.Enabled and chkExtended.Checked then SQL := SQL + ' EXTENDED';
|
||||
if chkChanged.Enabled and chkChanged.Checked then SQL := SQL + ' CHANGED';
|
||||
if chkUseFrm.Enabled and chkUseFrm.Checked then SQL := SQL + ' USE_FRM';
|
||||
end else if Sender = btnFindText then begin
|
||||
ds := Mainform.GetResults('SHOW COLUMNS FROM '+QuotedTable);
|
||||
SQL := '';
|
||||
while not ds.Eof do begin
|
||||
HasSelectedDatatype := comboDatatypes.ItemIndex = 0;
|
||||
if not HasSelectedDatatype then for i:=Low(Datatypes) to High(Datatypes) do begin
|
||||
HasSelectedDatatype := (LowerCase(getFirstWord(ds.FieldByName('Type').AsString)) = LowerCase(Datatypes[i].Name))
|
||||
and (Integer(Datatypes[i].Category)+1 = comboDatatypes.ItemIndex);
|
||||
if HasSelectedDatatype then
|
||||
break;
|
||||
end;
|
||||
if HasSelectedDatatype then
|
||||
SQL := SQL + Mainform.mask(ds.FieldByName('Field').AsWideString) + ' LIKE ' + esc('%'+memoFindText.Text+'%') + ' OR ';
|
||||
ds.Next;
|
||||
end;
|
||||
if SQL <> '' then begin
|
||||
Delete(SQL, Length(SQL)-3, 3);
|
||||
SQL := 'SELECT '''+db+''' AS `Database`, '''+table+''' AS `Table`, COUNT(*) AS `Found rows`, '
|
||||
+ 'CONCAT(ROUND(100 / '+IntToStr(RowsInTable)+' * COUNT(*), 1), ''%'') AS `Relevance` FROM '+QuotedTable+' WHERE '
|
||||
+ SQL;
|
||||
end;
|
||||
end;
|
||||
if SQL <> '' then
|
||||
AddResults(SQL)
|
||||
else
|
||||
AddNotes(db, table, STRSKIPPED+'table doesn''t have columns of selected type ('+comboDatatypes.Text+').', '');
|
||||
except
|
||||
// The above SQL can easily throw an exception, e.g. if a table is corrupted.
|
||||
// In such cases we create a dummy row, including the error message
|
||||
on E:Exception do
|
||||
AddNotes(db, table, 'error', E.Message);
|
||||
end else begin
|
||||
AddNotes(db, table, STRSKIPPED+FormatByteNumber(TableSize), '');
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -268,7 +350,7 @@ begin
|
||||
// Add missing columns
|
||||
for i:=ResultGrid.Header.Columns.Count to ds.FieldCount-1 do begin
|
||||
Col := ResultGrid.Header.Columns.Add;
|
||||
Col.Width := 100;
|
||||
Col.Width := 130;
|
||||
end;
|
||||
// Remove superfluous columns
|
||||
for i:=ResultGrid.Header.Columns.Count-1 downto ds.FieldCount do
|
||||
@ -278,7 +360,9 @@ begin
|
||||
Col := ResultGrid.Header.Columns[i];
|
||||
Col.Text := ds.Fields[i].FieldName;
|
||||
if ds.Fields[i].DataType in [ftSmallint, ftInteger, ftWord, ftLargeint, ftFloat] then
|
||||
Col.Alignment := taRightJustify;
|
||||
Col.Alignment := taRightJustify
|
||||
else
|
||||
Col.Alignment := taLeftJustify;
|
||||
end;
|
||||
ds.First;
|
||||
while not ds.Eof do begin
|
||||
@ -290,13 +374,37 @@ begin
|
||||
ds.Next;
|
||||
end;
|
||||
|
||||
Inc(FRealResultCounter);
|
||||
lblResults.Caption := IntToStr(FRealResultCounter)+' results:';
|
||||
lblResults.Repaint;
|
||||
UpdateResultGrid;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmTableTools.AddNotes(Col1, Col2, Col3, Col4: WideString);
|
||||
var
|
||||
Row: TWideStringlist;
|
||||
begin
|
||||
// Adds a row with non SQL results
|
||||
Row := TWideStringlist.Create;
|
||||
Row.Add(Col1);
|
||||
Row.Add(Col2);
|
||||
Row.Add(Col3);
|
||||
Row.Add(Col4);
|
||||
FResults.Add(Row);
|
||||
UpdateResultGrid;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmTableTools.UpdateResultGrid;
|
||||
begin
|
||||
// Refresh resultgrid
|
||||
ResultGrid.RootNodeCount := FResults.Count;
|
||||
ResultGrid.FocusedNode := ResultGrid.GetLast;
|
||||
ResultGrid.Selected[ResultGrid.FocusedNode] := True;
|
||||
ResultGrid.Repaint;
|
||||
end;
|
||||
|
||||
|
||||
procedure TfrmTableTools.ResultGridCompareNodes(Sender: TBaseVirtualTree; Node1, Node2: PVirtualNode;
|
||||
Column: TColumnIndex; var Result: Integer);
|
||||
begin
|
||||
@ -326,14 +434,16 @@ var
|
||||
VT: TVirtualStringTree;
|
||||
Msg: WideString;
|
||||
begin
|
||||
// Red text color for errors, purple for nodes
|
||||
VT := Sender as TVirtualStringTree;
|
||||
if VT.Header.Columns.Count >= 3 then begin
|
||||
Msg := LowerCase(VT.Text[Node, 2]);
|
||||
if Msg = 'note' then
|
||||
// Red text color for errors, purple for notes, grey for skipped tables
|
||||
if not (vsSelected in Node.States) then begin
|
||||
VT := Sender as TVirtualStringTree;
|
||||
Msg := VT.Text[Node, 2];
|
||||
if LowerCase(Msg) = 'note' then
|
||||
TargetCanvas.Font.Color := clPurple
|
||||
else if Msg = 'error' then
|
||||
TargetCanvas.Font.Color := clRed;
|
||||
else if LowerCase(Msg) = 'error' then
|
||||
TargetCanvas.Font.Color := clRed
|
||||
else if Pos(STRSKIPPED, Msg) > 0 then
|
||||
TargetCanvas.Font.Color := clGray;
|
||||
end;
|
||||
end;
|
||||
|
||||
@ -344,7 +454,10 @@ var
|
||||
begin
|
||||
if Column > NoColumn then begin
|
||||
Data := Sender.GetNodeData(Node);
|
||||
CellText := Data^[Column];
|
||||
if Data^.Count > Column then
|
||||
CellText := Data^[Column]
|
||||
else
|
||||
CellText := '';
|
||||
end;
|
||||
end;
|
||||
|
||||
|
Reference in New Issue
Block a user