From 92bd62030978f1bb41080fbeab9c44d94624e09f Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Sun, 22 Nov 2009 23:42:39 +0000 Subject: [PATCH] Introduce caching of collation table and table engines list in connection layer. Remove that stuff from main unit and automatically clear cached stuff on disconnection. --- source/createdatabase.dfm | 1 - source/createdatabase.pas | 73 ++++++++++-------------- source/main.pas | 109 ------------------------------------ source/mysql_connection.pas | 104 +++++++++++++++++++++++++++++++++- source/table_editor.dfm | 2 +- source/table_editor.pas | 14 ++--- 6 files changed, 140 insertions(+), 163 deletions(-) diff --git a/source/createdatabase.dfm b/source/createdatabase.dfm index 6982658c..129cf9f8 100644 --- a/source/createdatabase.dfm +++ b/source/createdatabase.dfm @@ -15,7 +15,6 @@ object CreateDatabaseForm: TCreateDatabaseForm Position = poOwnerFormCenter OnClose = FormClose OnCreate = FormCreate - OnDestroy = FormDestroy OnShow = FormShow DesignSize = ( 317 diff --git a/source/createdatabase.pas b/source/createdatabase.pas index fdd9f6dd..275aaf96 100644 --- a/source/createdatabase.pas +++ b/source/createdatabase.pas @@ -18,7 +18,6 @@ type comboCollation: TComboBox; lblPreview: TLabel; SynMemoPreview: TSynMemo; - procedure FormDestroy(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure comboCharsetChange(Sender: TObject); procedure Modified(Sender: TObject); @@ -29,7 +28,7 @@ type function GetCreateStatement: WideString; private { Private declarations } - dsCollations : TMySQLQuery; + CollationTable: TMySQLQuery; defaultCharset : String; currentCollation : String; public @@ -53,45 +52,11 @@ var charset: String; begin InheritFont(Font); - - try - dsCollations := Mainform.Connection.GetResults('SHOW COLLATION'); - // Detect servers default charset - defaultCharset := Mainform.Connection.GetVar( 'SHOW VARIABLES LIKE '+esc('character_set_server'), 1 ); - except - // Ignore it when the above statements don't work on pre 4.1 servers. - // If the list(s) are nil, disable the combobox(es), so we create the db without charset. - end; - - // Create a list with charsets from collations dataset - comboCharset.Enabled := dsCollations <> nil; - lblCharset.Enabled := comboCharset.Enabled; - if comboCharset.Enabled then - begin - comboCharset.Items.BeginUpdate; - dsCollations.First; - while not dsCollations.Eof do begin - charset := dsCollations.Col('Charset'); - if comboCharset.Items.IndexOf(charset) = -1 then - comboCharset.Items.Add(charset); - dsCollations.Next; - end; - comboCharset.Items.EndUpdate; - end; - - comboCollation.Enabled := dsCollations <> nil; - lblCollation.Enabled := comboCollation.Enabled; - // Setup SynMemoPreview SynMemoPreview.Highlighter := Mainform.SynSQLSyn1; end; -procedure TCreateDatabaseForm.FormDestroy(Sender: TObject); -begin - FreeAndNil(dsCollations); -end; - {** Form gets displayed: Set default values. } @@ -100,8 +65,28 @@ var selectCharset, currentCharset, sql_create : WideString; + Charset: String; colpos: Integer; begin + CollationTable := Mainform.Connection.CollationTable; + // Detect servers default charset + defaultCharset := Mainform.Connection.GetVar( 'SHOW VARIABLES LIKE '+esc('character_set_server'), 1 ); + comboCharset.Enabled := Assigned(CollationTable); + lblCharset.Enabled := comboCharset.Enabled; + comboCollation.Enabled := comboCharset.Enabled; + lblCollation.Enabled := comboCharset.Enabled; + if comboCharset.Enabled then begin + // Create a list with charsets from collations dataset + comboCharset.Items.BeginUpdate; + while not CollationTable.Eof do begin + Charset := CollationTable.Col('Charset'); + if comboCharset.Items.IndexOf(Charset) = -1 then + comboCharset.Items.Add(Charset); + CollationTable.Next; + end; + comboCharset.Items.EndUpdate; + end; + if modifyDB = '' then begin Caption := 'Create database ...'; @@ -157,21 +142,21 @@ var defaultCollation : String; begin // Abort if collations were not fetched successfully - if dsCollations = nil then + if not Assigned(CollationTable) then Exit; // Fill pulldown with fitting collations comboCollation.Items.BeginUpdate; comboCollation.Items.Clear; - dsCollations.First; - while not dsCollations.Eof do begin - if dsCollations.Col('Charset') = comboCharset.Text then + CollationTable.First; + while not CollationTable.Eof do begin + if CollationTable.Col('Charset') = comboCharset.Text then begin - comboCollation.Items.Add( dsCollations.Col('Collation')); - if dsCollations.Col('Default') = 'Yes' then - defaultCollation := dsCollations.Col('Collation'); + comboCollation.Items.Add(CollationTable.Col('Collation')); + if CollationTable.Col('Default') = 'Yes' then + defaultCollation := CollationTable.Col('Collation'); end; - dsCollations.Next; + CollationTable.Next; end; // Preselect default or current collation diff --git a/source/main.pas b/source/main.pas index 99fa0a47..fff8fe2a 100644 --- a/source/main.pas +++ b/source/main.pas @@ -708,9 +708,6 @@ type EditVariableForm : TfrmEditVariable; FileNameSessionLog : String; FileHandleSessionLog : Textfile; - dsShowEngines, - dsHaveEngines, - dsCollations, FSelectedTableColumns, FSelectedTableKeys : TMySQLQuery; FilterPanelManuallyOpened : Boolean; @@ -824,7 +821,6 @@ type procedure ActivateFileLogging; procedure DeactivateFileLogging; procedure TrimSQLLog; - procedure TableEnginesCombo(var Combobox: TCombobox); function GetTreeNodeType(Tree: TBaseVirtualTree; Node: PVirtualNode): TListNodeType; function GetFocusedTreeNodeType: TListNodeType; procedure RefreshTree(DoResetTableCache: Boolean; SelectDatabase: WideString = ''); @@ -850,7 +846,6 @@ type function GetRegKeyTable: String; procedure SaveListSetup( List: TVirtualStringTree ); procedure RestoreListSetup( List: TVirtualStringTree ); - function GetCollations(Items: TWideStrings = nil): TMySQLQuery; procedure SetEditorTabCaption(Editor: TFrame; ObjName: WideString); procedure ResetSelectedTableStuff; procedure SetWindowCaption; @@ -1662,18 +1657,11 @@ begin ClearAllTableLists; FreeAndNil(AllDatabases); FreeAndNil(InformationSchemaTables); - FreeAndNil(dsShowEngines); - FreeAndNil(dsHaveEngines); - FreeAndNil(dsCollations); FreeAndNil(FDataGridSelect); ResetSelectedTableStuff; SynMemoFilter.Clear; SetLength(FDataGridSort, 0); - // Free forms which use session based datasets, fx dsShowEngines - FreeAndNil(TableEditor); - FreeAndNil(CreateDatabaseForm); - // Closing connection if Assigned(Connection) then FreeAndNil(Connection); @@ -5783,81 +5771,6 @@ begin end; -{** - Fetch table engines from server - Currently used in tbl_properties and createtable -} -procedure TMainForm.TableEnginesCombo(var Combobox: TCombobox); -var - engineName, defaultEngine, engineSupport : String; - HaveEngineList : TStrings; -begin - Combobox.Items.BeginUpdate; - Combobox.Items.Clear; - - // Cache datasets - if dsShowEngines = nil then begin - FreeAndNil(dsShowEngines); - try - dsShowEngines := Connection.GetResults('SHOW ENGINES'); - except - // Ignore errors on old servers - end; - end; - if dsHaveEngines = nil then begin - FreeAndNil(dsHaveEngines); - dsHaveEngines := Connection.GetResults('SHOW VARIABLES LIKE ''have%'''); - end; - - if Assigned(dsShowEngines) then begin - dsShowEngines.First; - while not dsShowEngines.Eof do begin - engineName := dsShowEngines.Col('Engine'); - engineSupport := LowerCase(dsShowEngines.Col('Support')); - // Add to dropdown if supported - if engineSupport <> 'no' then - Combobox.Items.Add(engineName); - // Check if this is the default engine - if engineSupport = 'default' then - defaultEngine := engineName; - dsShowEngines.Next; - end; - end - else begin - // Manually fetch available engine types by analysing have_* options - // This is for servers below 4.1 or when the SHOW ENGINES statement has - // failed for some other reason - - // Add default engines which will not show in a have_* variable: - Combobox.Items.CommaText := 'MyISAM,MRG_MyISAM,HEAP'; - defaultEngine := 'MyISAM'; - // Possible other engines: - HaveEngineList := TStringList.Create; - HaveEngineList.CommaText := 'ARCHIVE,BDB,BLACKHOLE,CSV,EXAMPLE,FEDERATED,INNODB,ISAM'; - dsHaveEngines.First; - while not dsHaveEngines.Eof do begin - engineName := copy(dsHaveEngines.Col(0), 6, Length(dsHaveEngines.Col(0)) ); - // Strip additional "_engine" suffix, fx from "have_blackhole_engine" - if Pos('_', engineName) > 0 then - engineName := copy(engineName, 0, Pos('_', engineName)-1); - engineName := UpperCase(engineName); - // Add engine to dropdown if it's a) in HaveEngineList and b) activated - if (HaveEngineList.IndexOf(engineName) > -1) - and (LowerCase(dsHaveEngines.Col(1)) = 'yes') then - Combobox.Items.Add(engineName); - dsHaveEngines.Next; - end; - end; - - Combobox.Sorted := True; - - // Select default - Combobox.ItemIndex := Combobox.Items.IndexOf(defaultEngine); - - Combobox.Items.EndUpdate; -end; - - {** A row in the process list was selected. Fill SynMemoProcessView with the SQL of that row. @@ -8215,28 +8128,6 @@ begin end; -function TMainform.GetCollations(Items: TWideStrings = nil): TMySQLQuery; -begin - // Return cached collation list, used in several places, e.g. table editor - if dsCollations = nil then try - dsCollations := Connection.GetResults('SHOW COLLATION'); - except - // Ignore errors on old servers - end; - if Assigned(dsCollations) then begin - dsCollations.First; - if Assigned(Items) then begin - while not dsCollations.Eof do begin - Items.Add(dsCollations.Col('Collation')); - dsCollations.Next; - end; - dsCollations.First; - end; - end; - Result := dsCollations; -end; - - procedure TMainForm.PlaceObjectEditor(Which: TListNodeType); var frm: TFrame; diff --git a/source/mysql_connection.pas b/source/mysql_connection.pas index 3cc1b5fc..1d04f049 100644 --- a/source/mysql_connection.pas +++ b/source/mysql_connection.pas @@ -83,6 +83,10 @@ type FServerVersionUntouched: String; FLastQueryStart, FLastQueryEnd: Cardinal; FIsUnicode: Boolean; + FTableEngines: TStringList; + FTableEngineDefault: String; + FCollationTable: TMySQLQuery; + FCollationsUnavailable: Boolean; function GetActive: Boolean; procedure SetActive(Value: Boolean); procedure SetDatabase(Value: WideString); @@ -93,8 +97,12 @@ type function GetServerVersionStr: String; function GetServerVersionInt: Integer; function GetLastQueryDuration: Cardinal; + function GetTableEngines: TStringList; + function GetCollationTable: TMySQLQuery; + function GetCollationList: TStringList; procedure Log(Category: TMySQLLogCategory; Msg: WideString); procedure DetectCapabilities; + procedure ClearCache; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; @@ -119,6 +127,10 @@ type property RowsAffected: Int64 read FRowsAffected; property LastQueryDuration: Cardinal read GetLastQueryDuration; property IsUnicode: Boolean read FIsUnicode; + property TableEngines: TStringList read GetTableEngines; + property TableEngineDefault: String read FTableEngineDefault; + property CollationTable: TMySQLQuery read GetCollationTable; + property CollationList: TStringList read GetCollationList; published property Active: Boolean read GetActive write SetActive default False; property Hostname: String read FHostname write FHostname; @@ -196,6 +208,7 @@ end; destructor TMySQLConnection.Destroy; begin if Active then Active := False; + ClearCache; inherited Destroy; end; @@ -290,8 +303,10 @@ end; function TMySQLConnection.GetActive: Boolean; begin - if FActive and (mysql_ping(FHandle) <> 0) then + if FActive and (mysql_ping(FHandle) <> 0) then begin Active := False; + ClearCache; + end; Result := FActive; end; @@ -616,6 +631,93 @@ begin end; +function TMySQLConnection.GetTableEngines: TStringList; +var + ShowEngines, HaveEngines: TMySQLQuery; + engineName, engineSupport: String; + PossibleEngines: TStringList; +begin + if not Assigned(FTableEngines) then begin + FTableEngines := TStringList.Create; + try + ShowEngines := GetResults('SHOW ENGINES'); + while not ShowEngines.Eof do begin + engineName := ShowEngines.Col('Engine'); + engineSupport := LowerCase(ShowEngines.Col('Support')); + // Add to dropdown if supported + if engineSupport <> 'no' then + FTableEngines.Add(engineName); + // Check if this is the default engine + if engineSupport = 'default' then + FTableEngineDefault := engineName; + ShowEngines.Next; + end; + except + // Ignore errors on old servers and try a fallback: + // Manually fetch available engine types by analysing have_* options + // This is for servers below 4.1 or when the SHOW ENGINES statement has + // failed for some other reason + HaveEngines := GetResults('SHOW VARIABLES LIKE ''have%'''); + // Add default engines which will not show in a have_* variable: + FTableEngines.CommaText := 'MyISAM,MRG_MyISAM,HEAP'; + FTableEngineDefault := 'MyISAM'; + // Possible other engines: + PossibleEngines := TStringList.Create; + PossibleEngines.CommaText := 'ARCHIVE,BDB,BLACKHOLE,CSV,EXAMPLE,FEDERATED,INNODB,ISAM'; + while not HaveEngines.Eof do begin + engineName := copy(HaveEngines.Col(0), 6, Length(HaveEngines.Col(0))); + // Strip additional "_engine" suffix, fx from "have_blackhole_engine" + if Pos('_', engineName) > 0 then + engineName := copy(engineName, 0, Pos('_', engineName)-1); + engineName := UpperCase(engineName); + // Add engine to list if it's a) in HaveEngineList and b) activated + if (PossibleEngines.IndexOf(engineName) > -1) + and (LowerCase(HaveEngines.Col(1)) = 'yes') then + FTableEngines.Add(engineName); + HaveEngines.Next; + end; + end; + end; + Result := FTableEngines; +end; + + +function TMySQLConnection.GetCollationTable: TMySQLQuery; +begin + if (not Assigned(FCollationTable)) and (not FCollationsUnavailable) then try + FCollationTable := GetResults('SHOW COLLATION'); + except + // Ignore errors on old servers + FCollationsUnavailable := True; + end; + if Assigned(FCollationTable) then + FCollationTable.First; + Result := FCollationTable; +end; + + +function TMySQLConnection.GetCollationList: TStringList; +var + c: TMySQLQuery; +begin + c := CollationTable; + Result := TStringList.Create; + if not FCollationsUnavailable then while not c.Eof do begin + Result.Add(c.Col('Collation')); + c.Next; + end; +end; + + +procedure TMySQLConnection.ClearCache; +begin + // Free cached lists and results. Called when the connection was closed and/or destroyed + FreeAndNil(FCollationTable); + FCollationsUnavailable := False; + FreeAndNil(FTableEngines); + FTableEngineDefault := ''; +end; + { TMySQLQuery } diff --git a/source/table_editor.dfm b/source/table_editor.dfm index c7955555..cdfe0846 100644 --- a/source/table_editor.dfm +++ b/source/table_editor.dfm @@ -343,7 +343,7 @@ object frmTableEditor: TfrmTableEditor TabOrder = 0 OnChange = editNumEditChange end - object comboCollation: TTntComboBox + object comboCollation: TComboBox Left = 354 Top = 3 Width = 119 diff --git a/source/table_editor.pas b/source/table_editor.pas index 33e5dfc8..f00d24aa 100644 --- a/source/table_editor.pas +++ b/source/table_editor.pas @@ -36,7 +36,7 @@ type memoUnionTables: TTntMemo; comboInsertMethod: TComboBox; lblCollation: TLabel; - comboCollation: TTNTComboBox; + comboCollation: TComboBox; lblEngine: TLabel; comboEngine: TComboBox; treeIndexes: TVirtualStringTree; @@ -302,9 +302,9 @@ begin // Start with "basic" tab activated when just called if FAlterTableName <> AlterTableName then PageControlMain.ActivePage := tabBasic; - Mainform.TableEnginesCombo(comboEngine); - comboCollation.Items.Clear; - Mainform.GetCollations(comboCollation.Items); + comboEngine.Items := Mainform.Connection.TableEngines; + comboEngine.ItemIndex := comboEngine.Items.IndexOf(Mainform.Connection.TableEngineDefault); + comboCollation.Items := Mainform.Connection.CollationList; FAlterTableName := AlterTableName; listColumns.BeginUpdate; FColumns.Clear; @@ -688,8 +688,8 @@ begin if comboInsertMethod.Enabled and (comboInsertMethod.Tag = ModifiedFlag) and (comboInsertMethod.Text <> '') then Specs.Add('INSERT_METHOD='+comboInsertMethod.Text); if chkCharsetConvert.Checked then begin - Results := Mainform.GetCollations; - while not Results.Eof do begin + Results := Mainform.Connection.CollationTable; + if Assigned(Results) then while not Results.Eof do begin if Results.Col('Collation') = comboCollation.Text then begin Specs.Add('CONVERT TO CHARSET '+Results.Col('Charset')); break; @@ -1409,7 +1409,7 @@ begin 8: begin // Collation pulldown EnumEditor := TEnumEditorLink.Create(VT); EnumEditor.ValueList := TWideStringList.Create; - Mainform.GetCollations(EnumEditor.ValueList); + EnumEditor.ValueList.Text := Mainform.Connection.CollationList.Text; EnumEditor.ValueList.Insert(0, ''); EditLink := EnumEditor; end;