From 5f9129bef2933bb4e9ad0b6f77ce569734430bd6 Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Thu, 8 Apr 2010 23:16:40 +0000 Subject: [PATCH] Implement event editor for MySQL 5.1+ servers. Also, simplify some code around database objects and their editors. Fixes issue #1527 --- packages/delphi2010/heidisql.dpr | 3 +- packages/delphi2010/heidisql.dproj | 4 + source/const.inc | 1 + source/event_editor.dfm | 355 ++++++++++++++++++++++++++ source/event_editor.pas | 386 +++++++++++++++++++++++++++++ source/helpers.pas | 26 +- source/main.dfm | 11 + source/main.pas | 220 ++++++---------- source/mysql_connection.pas | 94 ++++++- source/printlist.pas | 10 +- source/routine_editor.pas | 35 ++- source/table_editor.pas | 35 ++- source/tabletools.pas | 6 +- source/trigger_editor.pas | 23 +- source/view.pas | 29 ++- 15 files changed, 992 insertions(+), 246 deletions(-) create mode 100644 source/event_editor.dfm create mode 100644 source/event_editor.pas diff --git a/packages/delphi2010/heidisql.dpr b/packages/delphi2010/heidisql.dpr index 63a17665..fae97440 100644 --- a/packages/delphi2010/heidisql.dpr +++ b/packages/delphi2010/heidisql.dpr @@ -36,7 +36,8 @@ uses mysql_api in '..\..\source\mysql_api.pas', mysql_connection in '..\..\source\mysql_connection.pas', trigger_editor in '..\..\source\trigger_editor.pas' {frmTriggerEditor: TFrame}, - searchreplace in '..\..\source\searchreplace.pas' {frmSearchReplace}; + searchreplace in '..\..\source\searchreplace.pas' {frmSearchReplace}, + event_editor in '..\..\source\event_editor.pas' {frmEventEditor: TFrame}; {$R ..\..\res\icon.RES} {$R ..\..\res\version.RES} diff --git a/packages/delphi2010/heidisql.dproj b/packages/delphi2010/heidisql.dproj index a768f87b..34152b57 100644 --- a/packages/delphi2010/heidisql.dproj +++ b/packages/delphi2010/heidisql.dproj @@ -198,6 +198,10 @@
frmSearchReplace
+ +
frmEventEditor
+ TFrame +
updater.res
diff --git a/source/const.inc b/source/const.inc index 0087a987..cfb4a910 100644 --- a/source/const.inc +++ b/source/const.inc @@ -279,6 +279,7 @@ const ICONINDEX_STOREDFUNCTION = 35; ICONINDEX_TRIGGER = 137; ICONINDEX_FUNCTION = 13; + ICONINDEX_EVENT = 80; ICONINDEX_KEYWORD = 25; // Size of byte units diff --git a/source/event_editor.dfm b/source/event_editor.dfm new file mode 100644 index 00000000..53218a8b --- /dev/null +++ b/source/event_editor.dfm @@ -0,0 +1,355 @@ +object frmEventEditor: TfrmEventEditor + Left = 0 + Top = 0 + Width = 672 + Height = 438 + TabOrder = 0 + DesignSize = ( + 672 + 438) + object lblBody: TLabel + AlignWithMargins = True + Left = 3 + Top = 175 + Width = 666 + Height = 13 + Align = alTop + Caption = 'Execution body:' + FocusControl = SynMemoBody + end + object SynMemoBody: TSynMemo + AlignWithMargins = True + Left = 3 + Top = 194 + Width = 666 + Height = 214 + Margins.Bottom = 30 + SingleLineMode = False + Align = alClient + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Courier New' + Font.Style = [] + TabOrder = 1 + Gutter.AutoSize = True + Gutter.DigitCount = 2 + Gutter.Font.Charset = DEFAULT_CHARSET + Gutter.Font.Color = clWindowText + Gutter.Font.Height = -11 + Gutter.Font.Name = 'Courier New' + Gutter.Font.Style = [] + Gutter.LeftOffset = 2 + Gutter.ShowLineNumbers = True + Highlighter = MainForm.SynSQLSyn1 + Lines.Strings = ( + 'SynMemoBody') + Options = [eoAutoIndent, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] + OnChange = Modification + end + object btnHelp: TButton + Left = 3 + Top = 410 + Width = 75 + Height = 25 + Anchors = [akLeft, akBottom] + Caption = 'Help' + TabOrder = 2 + OnClick = btnHelpClick + end + object btnDiscard: TButton + Left = 84 + Top = 410 + Width = 75 + Height = 25 + Anchors = [akLeft, akBottom] + Caption = 'Discard' + TabOrder = 3 + OnClick = btnDiscardClick + end + object btnSave: TButton + Left = 165 + Top = 410 + Width = 75 + Height = 25 + Anchors = [akLeft, akBottom] + Caption = 'Save' + Default = True + TabOrder = 4 + OnClick = btnSaveClick + end + object PageControlMain: TPageControl + AlignWithMargins = True + Left = 3 + Top = 3 + Width = 666 + Height = 166 + ActivePage = tabSettings + Align = alTop + Images = MainForm.ImageListMain + TabOrder = 0 + OnChange = PageControlMainChange + object tabSettings: TTabSheet + Caption = 'Settings' + ImageIndex = 39 + DesignSize = ( + 658 + 137) + object lblName: TLabel + Left = 3 + Top = 6 + Width = 31 + Height = 13 + Caption = 'Name:' + FocusControl = editName + end + object lblComment: TLabel + Left = 3 + Top = 33 + Width = 49 + Height = 13 + Caption = 'Comment:' + end + object editName: TEdit + Left = 88 + Top = 3 + Width = 567 + Height = 21 + Anchors = [akLeft, akTop, akRight] + TabOrder = 0 + Text = 'editName' + TextHint = 'Enter event name ...' + OnChange = Modification + end + object chkDropAfterExpiration: TCheckBox + Left = 88 + Top = 57 + Width = 567 + Height = 17 + Anchors = [akLeft, akTop, akRight] + Caption = 'Drop event after expiration' + TabOrder = 2 + OnClick = Modification + end + object editComment: TEdit + Left = 88 + Top = 30 + Width = 567 + Height = 21 + Anchors = [akLeft, akTop, akRight] + TabOrder = 1 + Text = 'editComment' + OnChange = Modification + end + object grpState: TRadioGroup + Left = 88 + Top = 80 + Width = 349 + Height = 52 + Caption = 'State' + Columns = 3 + TabOrder = 3 + OnClick = Modification + end + end + object tabScheduling: TTabSheet + Caption = 'Timing' + ImageIndex = 80 + object radioOnce: TRadioButton + Left = 3 + Top = 15 + Width = 74 + Height = 17 + Caption = 'Once, at:' + Checked = True + TabOrder = 0 + TabStop = True + OnClick = radioScheduleClick + end + object radioEvery: TRadioButton + Left = 3 + Top = 50 + Width = 54 + Height = 17 + Caption = 'Every' + TabOrder = 3 + OnClick = radioScheduleClick + end + object dateOnce: TDateTimePicker + Left = 96 + Top = 11 + Width = 133 + Height = 21 + Date = 40273.547337048610000000 + Time = 40273.547337048610000000 + TabOrder = 1 + OnChange = Modification + end + object timeOnce: TDateTimePicker + Left = 235 + Top = 11 + Width = 133 + Height = 21 + Date = 40273.548026377310000000 + Time = 40273.548026377310000000 + Kind = dtkTime + TabOrder = 2 + OnChange = Modification + end + object editEveryQuantity: TEdit + Left = 96 + Top = 48 + Width = 53 + Height = 21 + TabOrder = 4 + Text = '1' + OnChange = Modification + end + object udEveryQuantity: TUpDown + Left = 149 + Top = 48 + Width = 16 + Height = 21 + Associate = editEveryQuantity + Min = 1 + Max = 400000 + Position = 1 + TabOrder = 5 + end + object comboEveryInterval: TComboBox + Left = 172 + Top = 48 + Width = 133 + Height = 21 + Style = csDropDownList + TabOrder = 6 + OnChange = comboEveryIntervalChange + end + object chkStarts: TCheckBox + Left = 96 + Top = 78 + Width = 70 + Height = 17 + Caption = 'Starts at:' + TabOrder = 7 + OnClick = chkStartsEndsClick + end + object chkEnds: TCheckBox + Left = 96 + Top = 105 + Width = 70 + Height = 17 + Caption = 'Ends at:' + TabOrder = 10 + OnClick = chkStartsEndsClick + end + object dateStarts: TDateTimePicker + Left = 171 + Top = 75 + Width = 133 + Height = 21 + Date = 40273.548478379630000000 + Time = 40273.548478379630000000 + TabOrder = 8 + OnChange = Modification + end + object timeStarts: TDateTimePicker + Left = 310 + Top = 75 + Width = 133 + Height = 21 + Date = 40273.549206851850000000 + Time = 40273.549206851850000000 + Kind = dtkTime + TabOrder = 9 + OnChange = Modification + end + object timeEnds: TDateTimePicker + Left = 310 + Top = 102 + Width = 133 + Height = 21 + Date = 40273.549548981480000000 + Time = 40273.549548981480000000 + Kind = dtkTime + TabOrder = 12 + OnChange = Modification + end + object dateEnds: TDateTimePicker + Left = 171 + Top = 102 + Width = 133 + Height = 21 + Date = 40273.549452245370000000 + Time = 40273.549452245370000000 + TabOrder = 11 + OnChange = Modification + end + end + object tabCREATEcode: TTabSheet + Caption = 'CREATE code' + ImageIndex = 119 + object SynMemoCREATEcode: TSynMemo + Left = 0 + Top = 0 + Width = 658 + Height = 137 + SingleLineMode = False + Align = alClient + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Courier New' + Font.Style = [] + TabOrder = 0 + Gutter.AutoSize = True + Gutter.DigitCount = 2 + Gutter.Font.Charset = DEFAULT_CHARSET + Gutter.Font.Color = clWindowText + Gutter.Font.Height = -11 + Gutter.Font.Name = 'Courier New' + Gutter.Font.Style = [] + Gutter.LeftOffset = 2 + Gutter.ShowLineNumbers = True + Highlighter = MainForm.SynSQLSyn1 + Lines.Strings = ( + 'SynMemoCREATEcode') + Options = [eoAutoIndent, eoAutoSizeMaxScrollWidth, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] + ReadOnly = True + end + end + object tabALTERcode: TTabSheet + Caption = 'ALTER code' + ImageIndex = 119 + TabVisible = False + object SynMemoALTERcode: TSynMemo + Left = 0 + Top = 0 + Width = 658 + Height = 137 + SingleLineMode = False + Align = alClient + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -13 + Font.Name = 'Courier New' + Font.Style = [] + TabOrder = 0 + Gutter.AutoSize = True + Gutter.DigitCount = 2 + Gutter.Font.Charset = DEFAULT_CHARSET + Gutter.Font.Color = clWindowText + Gutter.Font.Height = -11 + Gutter.Font.Name = 'Courier New' + Gutter.Font.Style = [] + Gutter.LeftOffset = 2 + Gutter.ShowLineNumbers = True + Highlighter = MainForm.SynSQLSyn1 + Lines.Strings = ( + 'SynMemoALTERcode') + Options = [eoAutoIndent, eoAutoSizeMaxScrollWidth, eoDragDropEditing, eoEnhanceEndKey, eoGroupUndo, eoHideShowScrollbars, eoKeepCaretX, eoShowScrollHint, eoSmartTabDelete, eoSmartTabs, eoTabsToSpaces] + ReadOnly = True + end + end + end +end diff --git a/source/event_editor.pas b/source/event_editor.pas new file mode 100644 index 00000000..dcd12878 --- /dev/null +++ b/source/event_editor.pas @@ -0,0 +1,386 @@ +unit event_editor; + +interface + +uses + Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, + Dialogs, StdCtrls, SynEdit, SynMemo, SynRegExpr, ComCtrls, ExtCtrls, WideStrUtils, + helpers, mysql_connection; + +type + TFrame = TDBObjectEditor; + TfrmEventEditor = class(TFrame) + SynMemoBody: TSynMemo; + btnHelp: TButton; + btnDiscard: TButton; + btnSave: TButton; + lblBody: TLabel; + PageControlMain: TPageControl; + tabSettings: TTabSheet; + tabScheduling: TTabSheet; + tabCREATEcode: TTabSheet; + tabALTERcode: TTabSheet; + lblName: TLabel; + editName: TEdit; + lblComment: TLabel; + chkDropAfterExpiration: TCheckBox; + editComment: TEdit; + grpState: TRadioGroup; + radioOnce: TRadioButton; + radioEvery: TRadioButton; + dateOnce: TDateTimePicker; + timeOnce: TDateTimePicker; + editEveryQuantity: TEdit; + udEveryQuantity: TUpDown; + comboEveryInterval: TComboBox; + chkStarts: TCheckBox; + chkEnds: TCheckBox; + dateStarts: TDateTimePicker; + timeStarts: TDateTimePicker; + timeEnds: TDateTimePicker; + dateEnds: TDateTimePicker; + SynMemoCREATEcode: TSynMemo; + SynMemoALTERcode: TSynMemo; + procedure Modification(Sender: TObject); + procedure radioScheduleClick(Sender: TObject); + procedure btnSaveClick(Sender: TObject); + procedure btnHelpClick(Sender: TObject); + procedure btnDiscardClick(Sender: TObject); + procedure PageControlMainChange(Sender: TObject); + procedure chkStartsEndsClick(Sender: TObject); + procedure comboEveryIntervalChange(Sender: TObject); + private + { Private declarations } + AlterCodeValid, CreateCodeValid: Boolean; + function ComposeCreateStatement: String; + function ComposeAlterStatement: String; + function ComposeBaseStatement: String; + procedure UpdateSQLcode; + public + { Public declarations } + constructor Create(AOwner: TComponent); override; + destructor Destroy; override; + procedure Init(Obj: TDBObject); override; + function ApplyModifications: TModalResult; override; + end; + +implementation + +uses main; + +{$R *.dfm} + + +constructor TfrmEventEditor.Create(AOwner: TComponent); +begin + inherited; + Mainform.SynCompletionProposal.AddEditor(SynMemoBody); + comboEveryInterval.Items := Explode('|', 'YEAR|QUARTER|MONTH|DAY|HOUR|MINUTE|WEEK|SECOND|YEAR_MONTH|'+ + 'DAY_HOUR|DAY_MINUTE|DAY_SECOND|HOUR_MINUTE|HOUR_SECOND|MINUTE_SECOND'); + grpState.Items := Explode('|', 'Enable|Disable|Disable on slave'); +end; + + +destructor TfrmEventEditor.Destroy; +begin + // Store GUI setup? Nothing yet. + inherited; +end; + + +procedure TfrmEventEditor.Init(Obj: TDBObject); +var + CreateCode, DateExpr: String; + rx: TRegExpr; + d: TDateTime; + i: Integer; +begin + inherited; + editName.Clear; + editComment.Clear; + chkDropAfterExpiration.Checked := True; + radioEvery.Checked := True; + grpState.ItemIndex := 0; + SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; + dateOnce.Date := Now; + timeOnce.Time := Now; + dateStarts.Date := Now; + timeStarts.Time := Now; + dateEnds.Date := Now; + timeEnds.Time := Now; + udEveryQuantity.Position := 1; + comboEveryInterval.ItemIndex := comboEveryInterval.Items.IndexOf('DAY'); + tabALTERcode.TabVisible := False; + if DBObject.Name <> '' then begin + // Edit mode + tabALTERcode.TabVisible := True; + editName.Text := DBObject.Name; + // CREATE EVENT `eventb` + // ON SCHEDULE EVERY 1 DAY STARTS '2010-04-08 08:05:04' ENDS '2010-04-30 01:01:28' + // ON COMPLETION NOT PRESERVE + // ENABLE + // DO BEGIN END + CreateCode := Mainform.Connection.GetVar('SHOW CREATE EVENT '+Mainform.mask(DBObject.Name), 'Create Event'); + DateExpr := '[''"]([^''"]+)[''"]'; + rx := TRegExpr.Create; + rx.ModifierI := True; + rx.Expression := '\bON\s+SCHEDULE\s+(EVERY|AT)\s+((\d+|''[^'']+'')\s+(\S+)(\s+STARTS\s+'+DateExpr+')?(\s+ENDS\s+'+DateExpr+')?|'+DateExpr+')'; + if rx.Exec(CreateCode) then begin + if UpperCase(rx.Match[1]) = 'AT' then begin + radioOnce.Checked := True; + d := Mainform.Connection.ParseDateTime(rx.Match[9]); + dateOnce.DateTime := d; + timeOnce.DateTime := d; + end else begin + radioEvery.Checked := True; + comboEveryInterval.ItemIndex := comboEveryInterval.Items.IndexOf(rx.Match[4]); + comboEveryIntervalChange(Self); + if udEveryQuantity.Enabled then + udEveryQuantity.Position := MakeInt(rx.Match[3]) + else + editEveryQuantity.Text := WideDequotedStr(rx.Match[3], ''''); + chkStarts.Checked := rx.MatchLen[5] > 0; + if chkStarts.Checked then begin + d := Mainform.Connection.ParseDateTime(rx.Match[6]); + dateStarts.DateTime := d; + timeStarts.DateTime := d; + end; + chkEnds.Checked := rx.MatchLen[7] > 0; + if chkEnds.Checked then begin + d := Mainform.Connection.ParseDateTime(rx.Match[8]); + dateEnds.DateTime := d; + timeEnds.DateTime := d; + end; + end; + Delete(CreateCode, 1, rx.MatchPos[0]+rx.MatchLen[0]); + end; + + rx.Expression := '^ON\s+COMPLETION(\s+NOT)?\s+PRESERVE\b'; + if rx.Exec(CreateCode) then begin + chkDropAfterExpiration.Checked := rx.MatchLen[1] > 0; + Delete(CreateCode, 1, rx.MatchPos[0]+rx.MatchLen[0]); + end; + + for i:=grpState.Items.Count-1 downto 0 do begin + if Pos(UpperCase(grpState.Items[i]), UpperCase(CreateCode)) = 1 then begin + grpState.ItemIndex := i; + Delete(CreateCode, 1, Length(grpState.Items[i])); + break; + end; + end; + + rx.Expression := '\bCOMMENT\s+''((.+)[^''])'''; + if rx.Exec(CreateCode) then begin + editComment.Text := StringReplace(rx.Match[1], '''''', '''', [rfReplaceAll]); + Delete(CreateCode, rx.MatchPos[0], rx.MatchLen[0]); + end; + + rx.Expression := '\bDO\s+(.*)'; + if rx.Exec(CreateCode) then + SynMemoBody.Text := rx.Match[1]; + + rx.Free; + + end; + radioScheduleClick(Self); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + Mainform.ShowStatusMsg; + Screen.Cursor := crDefault; +end; + + +procedure TfrmEventEditor.Modification(Sender: TObject); +begin + Modified := True; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + CreateCodeValid := False; + AlterCodeValid := False; + UpdateSQLcode; +end; + + +procedure TfrmEventEditor.btnSaveClick(Sender: TObject); +begin + ApplyModifications; +end; + + +function TfrmEventEditor.ApplyModifications: TModalResult; +var + sql: String; +begin + // Create or alter table + Result := mrOk; + if DBObject.Name = '' then + sql := ComposeCreateStatement + else + sql := ComposeAlterStatement; + try + Mainform.Connection.Query(sql); + DBObject.Name := editName.Text; + tabALTERcode.TabVisible := DBObject.Name <> ''; + Mainform.UpdateEditorTab; + Mainform.RefreshTreeDB(Mainform.ActiveDatabase, DBObject.Name, DBObject.NodeType); + Modified := False; + btnSave.Enabled := Modified; + btnDiscard.Enabled := Modified; + AlterCodeValid := False; + CreateCodeValid := False; + UpdateSQLcode; + except + on E:Exception do begin + MessageDlg(E.Message, mtError, [mbOk], 0); + Result := mrAbort; + end; + end; +end; + + +function TfrmEventEditor.ComposeCreateStatement: String; +begin + Result := 'CREATE EVENT ' + Mainform.mask(editName.Text) + ' ' + ComposeBaseStatement; +end; + + +function TfrmEventEditor.ComposeAlterStatement: String; +begin + Result := 'ALTER EVENT ' + Mainform.mask(DBObject.Name) + ' ' + ComposeBaseStatement; +end; + + +function TfrmEventEditor.ComposeBaseStatement: String; +var + d: TDateTime; + Quantity: String; +begin + // Return CREATE EVENT statement + Result := 'ON SCHEDULE' + CRLF + #9#9; + if radioOnce.Checked then begin + d := dateOnce.DateTime; + ReplaceTime(d, timeOnce.DateTime); + Result := Result + 'AT ' + esc(DateTimeToStr(d)) + CRLF; + end else begin + if udEveryQuantity.Enabled then + Quantity := IntToStr(udEveryQuantity.Position) + else + Quantity := esc(editEveryQuantity.Text); + Result := Result + 'EVERY ' + Quantity + ' ' + comboEveryInterval.Text; + if chkStarts.Checked then begin + d := dateStarts.DateTime; + ReplaceTime(d, timeStarts.DateTime); + Result := Result + ' STARTS ' + esc(DateTimeToStr(d)); + end; + if chkEnds.Checked then begin + d := dateEnds.DateTime; + ReplaceTime(d, timeEnds.DateTime); + Result := Result + ' ENDS ' + esc(DateTimeToStr(d)); + end; + Result := Result + CRLF; + end; + + if chkDropAfterExpiration.Checked then + Result := Result + #9 + 'ON COMPLETION NOT PRESERVE' + else + Result := Result + #9 + 'ON COMPLETION PRESERVE'; + if (DBObject.Name <> '') and (DBObject.Name <> editName.Text) then + Result := Result + CRLF + #9 + 'RENAME TO ' + MainForm.mask(editName.Text); + Result := Result + CRLF + #9 + UpperCase(grpState.Items[grpState.ItemIndex]); + Result := Result + CRLF + #9 + 'COMMENT ' + esc(editComment.Text); + Result := Result + CRLF + #9 + 'DO ' + SynMemoBody.Text; +end; + + +procedure TfrmEventEditor.PageControlMainChange(Sender: TObject); +begin + UpdateSQLcode; +end; + + +procedure TfrmEventEditor.UpdateSQLcode; +var + OldTopLine: Integer; +begin + if (PageControlMain.ActivePage = tabALTERCode) and (not AlterCodeValid) then begin + SynMemoALTERcode.BeginUpdate; + OldTopLine := SynMemoALTERcode.TopLine; + SynMemoALTERcode.Text := ComposeAlterStatement; + SynMemoALTERcode.TopLine := OldTopLine; + SynMemoALTERcode.EndUpdate; + AlterCodeValid := True; + end else if (PageControlMain.ActivePage = tabCREATECode) and (not CreateCodeValid) then begin + SynMemoCREATEcode.BeginUpdate; + OldTopLine := SynMemoCREATEcode.TopLine; + SynMemoCREATEcode.Text := ComposeCreateStatement; + SynMemoCREATEcode.TopLine := OldTopLine; + SynMemoCREATEcode.EndUpdate; + CreateCodeValid := True; + end; +end; + + +procedure TfrmEventEditor.radioScheduleClick(Sender: TObject); +var + IsOnce: Boolean; +begin + IsOnce := radioOnce.Checked; + dateOnce.Enabled := IsOnce; + timeOnce.Enabled := IsOnce; + editEveryQuantity.Enabled := not IsOnce; + udEveryQuantity.Enabled := not IsOnce; + comboEveryInterval.Enabled := not IsOnce; + comboEveryIntervalChange(Sender); + chkStarts.Enabled := not IsOnce; + chkEnds.Enabled := not IsOnce; + chkStartsEndsClick(Sender); + Modification(Sender); +end; + + +procedure TfrmEventEditor.chkStartsEndsClick(Sender: TObject); +begin + // Enable/disable start+end controls + dateStarts.Enabled := chkStarts.Checked and chkStarts.Enabled; + timeStarts.Enabled := chkStarts.Checked and chkStarts.Enabled; + dateEnds.Enabled := chkEnds.Checked and chkEnds.Enabled; + timeEnds.Enabled := chkEnds.Checked and chkEnds.Enabled; + Modification(Sender); +end; + + +procedure TfrmEventEditor.comboEveryIntervalChange(Sender: TObject); +begin + // To enter DAY_HOUR values editor has to accept "1-2" + if Pos('_', comboEveryInterval.Text) > 0 then begin + udEveryQuantity.Associate := nil; + udEveryQuantity.Enabled := False; + end else begin + udEveryQuantity.Associate := editEveryQuantity; + udEveryQuantity.Enabled := True; + end; + Modification(Sender); +end; + +procedure TfrmEventEditor.btnDiscardClick(Sender: TObject); +begin + // Reinit editor, discarding changes + Modified := False; + Init(DBObject); +end; + + +procedure TfrmEventEditor.btnHelpClick(Sender: TObject); +var + keyword: String; +begin + if DBObject.Name = '' then + keyword := 'CREATE EVENT' + else + keyword := 'ALTER EVENT'; + Mainform.CallSQLHelpWithKeyword(keyword); +end; + + +end. diff --git a/source/helpers.pas b/source/helpers.pas index 64cb0a30..59830890 100644 --- a/source/helpers.pas +++ b/source/helpers.pas @@ -142,15 +142,16 @@ type FModified: Boolean; procedure SetModified(Value: Boolean); protected - FEditObjectName: String; public + DBObject: TDBObject; constructor Create(AOwner: TComponent); override; destructor Destroy; override; - procedure Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); virtual; + procedure Init(Obj: TDBObject); virtual; function DeInit: TModalResult; property Modified: Boolean read FModified write SetModified; function ApplyModifications: TModalResult; virtual; abstract; end; + TDBObjectEditorClass = class of TDBObjectEditor; TWndProc = function (hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; PGripInfo = ^TGripInfo; @@ -271,7 +272,7 @@ var implementation -uses main, uVistaFuncs, table_editor, view, routine_editor, trigger_editor; +uses main, uVistaFuncs, table_editor, view, routine_editor, trigger_editor, event_editor; @@ -3250,7 +3251,7 @@ begin Value := esAddedDeleted; FStatus := Value; if Value <> esUntouched then - Mainform.TableEditor.Modification(Self); + TfrmTableEditor(Mainform.ActiveObjectEditor).Modification(Self); end; @@ -3318,11 +3319,12 @@ begin FModified := Value; end; -procedure TDBObjectEditor.Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); +procedure TDBObjectEditor.Init(Obj: TDBObject); begin Mainform.ShowStatusMsg('Initializing editor ...'); - FEditObjectName := ObjectName; - Mainform.SetEditorTabCaption(Self, FEditObjectName); + ScaleControls(Screen.PixelsPerInch, FORMS_DPI); + DBObject := Obj; + Mainform.UpdateEditorTab; Screen.Cursor := crHourglass; MainForm.SetupSynEditors; end; @@ -3334,13 +3336,9 @@ begin // Ask for saving modifications Result := mrOk; if Modified then begin - if Self is TfrmTableEditor then ObjType := 'table' - else if Self is TfrmView then ObjType := 'view' - else if Self is TfrmRoutineEditor then ObjType := 'routine' - else if Self is TfrmTriggerEditor then ObjType := 'trigger' - else ObjType := ''; - if FEditObjectName <> '' then - Msg := 'Save modified '+ObjType+' "'+FEditObjectName+'"?' + ObjType := LowerCase(DBObject.ObjType); + if DBObject.Name <> '' then + Msg := 'Save modified '+ObjType+' "'+DBObject.Name+'"?' else Msg := 'Save new '+ObjType+'?'; Result := MessageDlg(Msg, mtConfirmation, [mbYes, mbNo, mbCancel], 0); diff --git a/source/main.dfm b/source/main.dfm index 0b6c4c0f..22614769 100644 --- a/source/main.dfm +++ b/source/main.dfm @@ -2467,6 +2467,14 @@ object MainForm: TMainForm ImageIndex = 35 OnExecute = actRunRoutinesExecute end + object actCreateEvent: TAction + Category = 'Database' + Caption = 'Event' + Enabled = False + Hint = 'Create new event in selected database' + ImageIndex = 80 + OnExecute = actCreateDBObjectExecute + end end object SaveDialog2: TSaveDialog DefaultExt = 'reg' @@ -7563,6 +7571,9 @@ object MainForm: TMainForm object menuCreateTrigger: TMenuItem Action = actCreateTrigger end + object Event1: TMenuItem + Action = actCreateEvent + end end object N17: TMenuItem Caption = '-' diff --git a/source/main.pas b/source/main.pas index 7982a512..05b456c8 100644 --- a/source/main.pas +++ b/source/main.pas @@ -16,7 +16,7 @@ uses ShlObj, SynEditMiscClasses, SynEditSearch, SynEditRegexSearch, SynCompletionProposal, SynEditHighlighter, SynHighlighterSQL, Tabs, SynUnicode, SynRegExpr, WideStrUtils, ExtActns, CommCtrl, Contnrs, Generics.Collections, SynEditExport, SynExportHTML, - routine_editor, trigger_editor, options, EditVar, helpers, createdatabase, table_editor, + routine_editor, trigger_editor, event_editor, options, EditVar, helpers, createdatabase, table_editor, TableTools, View, Usermanager, SelectDBObject, connections, sqlhelp, mysql_connection, mysql_api, insertfiles, searchreplace, loaddata, copytable; @@ -472,6 +472,8 @@ type menuFetchDBitems: TMenuItem; actRunRoutines: TAction; Runroutines1: TMenuItem; + actCreateEvent: TAction; + Event1: TMenuItem; procedure actCreateDBObjectExecute(Sender: TObject); procedure menuConnectionsPopup(Sender: TObject); procedure actExitApplicationExecute(Sender: TObject); @@ -781,7 +783,6 @@ type FilterTextDatabase, FilterTextData: String; PreviousFocusedNode: PVirtualNode; - FActiveObjectEditor: TDBObjectEditor; FCmdlineFilenames: TStringlist; FCmdlineConnectionParams: TConnectionParameters; FCmdlineSessionName: String; @@ -796,7 +797,7 @@ type procedure SetVisibleListColumns( List: TVirtualStringTree; Columns: TStringList ); procedure ToggleFilterPanel(ForceVisible: Boolean = False); procedure AutoCalcColWidth(Tree: TVirtualStringTree; Column: TColumnIndex); - function PlaceObjectEditor(Which: TListNodeType): TDBObjectEditor; + procedure PlaceObjectEditor(Obj: TDBObject); procedure SetTabCaption(PageIndex: Integer; Text: String); function ConfirmTabClose(PageIndex: Integer): Boolean; procedure SaveQueryMemo(Tab: TQueryTab; Filename: String; OnlySelection: Boolean); @@ -818,19 +819,16 @@ type DBObjectsMaxSize: Int64; DBObjectsMaxRows: Int64; ProcessListMaxTime: Int64; + ActiveObjectEditor: TDBObjectEditor; // Cached forms TableToolsDialog: TfrmTableTools; - ViewEditor: TfrmView; UserManagerForm: TUserManagerForm; SelectDBObjectForm: TfrmSelectDBObject; SQLHelpForm: TfrmSQLhelp; - RoutineEditor: TfrmRoutineEditor; - TriggerEditor: TfrmTriggerEditor; OptionsForm: Toptionsform; SessionManager: TConnForm; CreateDatabaseForm: TCreateDatabaseForm; - TableEditor: TfrmTableEditor; InsertFiles: TfrmInsertFiles; EditVariableForm: TfrmEditVariable; SearchReplaceDialog: TfrmSearchReplace; @@ -941,7 +939,7 @@ type function GetRegKeyTable: String; procedure SaveListSetup( List: TVirtualStringTree ); procedure RestoreListSetup( List: TVirtualStringTree ); - procedure SetEditorTabCaption(Editor: TDBObjectEditor; ObjName: String); + procedure UpdateEditorTab; procedure SetWindowCaption; procedure OnMessageHandler(var Msg: TMsg; var Handled: Boolean); procedure DefaultHandler(var Message); override; @@ -1025,8 +1023,8 @@ begin Exit; end; // Unsaved modified table, trigger, view or routine? - if Assigned(FActiveObjectEditor) then - CanClose := not (FActiveObjectEditor.DeInit in [mrAbort, mrCancel]); + if Assigned(ActiveObjectEditor) then + CanClose := not (ActiveObjectEditor.DeInit in [mrAbort, mrCancel]); end; procedure TMainForm.FormDestroy(Sender: TObject); @@ -1035,16 +1033,13 @@ var i: Integer; begin // Destroy editors and dialogs. Must be done before connection gets closed, as some destructors do SQL stuff. - FreeAndNil(RoutineEditor); + FreeAndNil(ActiveObjectEditor); FreeAndNil(TableToolsDialog); FreeAndNil(UserManagerForm); - FreeAndNil(ViewEditor); FreeAndNil(SelectDBObjectForm); FreeAndNil(SQLHelpForm); FreeAndNil(OptionsForm); FreeAndNil(SessionManager); - FreeAndNil(TableEditor); - FreeAndNil(TriggerEditor); FreeAndNil(CreateDatabaseForm); FreeAndNil(SearchReplaceDialog); @@ -2487,21 +2482,20 @@ end; procedure TMainForm.actCreateDBObjectExecute(Sender: TObject); var - Editor: TDBObjectEditor; - ObjType: TListNodeType; + Obj: TDBObject; a: TAction; begin // Create a new table, view, etc. tabEditor.TabVisible := True; PagecontrolMain.ActivePage := tabEditor; a := Sender as TAction; - ObjType := lntNone; - if a = actCreateTable then ObjType := lntTable - else if a = actCreateView then ObjType := lntView - else if a = actCreateRoutine then ObjType := lntProcedure - else if a = actCreateTrigger then ObjType := lntTrigger; - Editor := PlaceObjectEditor(ObjType); - Editor.Init; + Obj := TDBObject.Create; + if a = actCreateTable then Obj.NodeType := lntTable + else if a = actCreateView then Obj.NodeType := lntView + else if a = actCreateRoutine then Obj.NodeType := lntProcedure + else if a = actCreateTrigger then Obj.NodeType := lntTrigger + else if a = actCreateEvent then Obj.NodeType := lntEvent; + PlaceObjectEditor(Obj); end; @@ -3817,14 +3811,7 @@ begin if Column <> (Sender as TVirtualStringTree).Header.MainColumn then Exit; Obj := Sender.GetNodeData(Node); - case Obj.NodeType of - lntTable: ImageIndex := ICONINDEX_TABLE; - lntView: ImageIndex := ICONINDEX_VIEW; - lntProcedure: ImageIndex := ICONINDEX_STOREDPROCEDURE; - lntFunction: ImageIndex := ICONINDEX_STOREDFUNCTION; - lntTrigger: ImageIndex := ICONINDEX_TRIGGER; - else ImageIndex := -1; - end; + ImageIndex := Obj.ImageIndex; end; @@ -4201,18 +4188,9 @@ var Queries : TStringList; procedure addTable(Obj: TDBObject); - var Icon: Integer; begin - case Obj.NodeType of - lntTable: Icon := ICONINDEX_TABLE; - lntFunction: Icon := ICONINDEX_STOREDFUNCTION; - lntProcedure: Icon := ICONINDEX_STOREDPROCEDURE; - lntView: Icon := ICONINDEX_VIEW; - lntTrigger: Icon := ICONINDEX_TRIGGER; - else Icon := -1; - end; Proposal.InsertList.Add(Obj.Name); - Proposal.ItemList.Add( Format(SYNCOMPLETION_PATTERN, [Icon, LowerCase(Obj.ObjType), Obj.Name]) ); + Proposal.ItemList.Add( Format(SYNCOMPLETION_PATTERN, [Obj.ImageIndex, LowerCase(Obj.ObjType), Obj.Name]) ); end; procedure addColumns( tablename: String ); @@ -4795,6 +4773,7 @@ begin actCreateView.Enabled := L in [1,2]; actCreateRoutine.Enabled := L in [1,2]; actCreateTrigger.Enabled := L in [1,2]; + actCreateEvent.Enabled := L in [1,2]; actDropObjects.Enabled := L in [1,2]; actCopyTable.Enabled := HasFocus and (NodeType in [lntTable, lntView]); actEmptyTables.Enabled := HasFocus and (NodeType in [lntTable, lntView]); @@ -4811,6 +4790,8 @@ begin actCreateTable.Enabled := True; actCreateView.Enabled := True; actCreateRoutine.Enabled := True; + actCreateTrigger.Enabled := True; + actCreateEvent.Enabled := True; actDropObjects.Enabled := ListTables.SelectedCount > 0; actEmptyTables.Enabled := False; actRunRoutines.Enabled := True; @@ -4829,6 +4810,7 @@ begin actCreateView.Enabled := actCreateView.Enabled and (Connection.ServerVersionInt >= 50001); actCreateRoutine.Enabled := actCreateRoutine.Enabled and (Connection.ServerVersionInt >= 50003); actCreateTrigger.Enabled := actCreateTrigger.Enabled and (Connection.ServerVersionInt >= 50002); + actCreateEvent.Enabled := actCreateEvent.Enabled and (Connection.ServerVersionInt >= 50100); end; @@ -5271,9 +5253,9 @@ begin ActiveQueryHelpers.Items.Add(Col.Name); end; end; - lntFunction, lntProcedure: if Assigned(RoutineEditor) then begin - for i:=0 to RoutineEditor.Parameters.Count-1 do - ActiveQueryHelpers.Items.Add(RoutineEditor.Parameters[i].Name); + lntFunction, lntProcedure: if Assigned(ActiveObjectEditor) then begin + for i:=0 to TfrmRoutineEditor(ActiveObjectEditor).Parameters.Count-1 do + ActiveQueryHelpers.Items.Add(TfrmRoutineEditor(ActiveObjectEditor).Parameters[i].Name); end; end; end; @@ -6318,22 +6300,7 @@ begin // of DBObjects. Probably a timing issue. Work around that by doing a safety check here. if Node.Index >= Cardinal(DBObjects.Count) then Exit; - case DBObjects[Node.Index].NodeType of - lntTable: - if Kind = ikSelected then - ImageIndex := ICONINDEX_TABLE_HIGHLIGHT - else ImageIndex := ICONINDEX_TABLE; - lntView: - if Kind = ikSelected then - ImageIndex := ICONINDEX_VIEW_HIGHLIGHT - else ImageIndex := ICONINDEX_VIEW; - lntProcedure: - ImageIndex := ICONINDEX_STOREDPROCEDURE; - lntFunction: - ImageIndex := ICONINDEX_STOREDFUNCTION; - lntTrigger: - ImageIndex := ICONINDEX_TRIGGER; - end; + ImageIndex := DBObjects[Node.Index].ImageIndex; end; end; end; @@ -6494,7 +6461,7 @@ begin end; end; newDbObject := SelectedTable.Name; - tabEditor.TabVisible := SelectedTable.NodeType in [lntTable, lntView, lntProcedure, lntFunction, lntTrigger]; + tabEditor.TabVisible := SelectedTable.NodeType in [lntTable, lntView, lntProcedure, lntFunction, lntTrigger, lntEvent]; tabData.TabVisible := SelectedTable.NodeType in [lntTable, lntView]; ParseSelectedTableStructure; if tabEditor.TabVisible then begin @@ -6536,8 +6503,8 @@ procedure TMainForm.DBtreeFocusChanging(Sender: TBaseVirtualTree; OldNode, begin debug('DBtreeFocusChanging'); // Check if some editor has unsaved changes - if Assigned(FActiveObjectEditor) and Assigned(NewNode) then begin - Allowed := not (FActiveObjectEditor.DeInit in [mrAbort, mrCancel]); + if Assigned(ActiveObjectEditor) and Assigned(NewNode) then begin + Allowed := not (ActiveObjectEditor.DeInit in [mrAbort, mrCancel]); DBTree.Selected[DBTree.FocusedNode] := not Allowed; end else Allowed := True; @@ -8432,67 +8399,39 @@ begin end; -function TMainForm.PlaceObjectEditor(Which: TListNodeType): TDBObjectEditor; +procedure TMainForm.PlaceObjectEditor(Obj: TDBObject); +var + EditorClass: TDBObjectEditorClass; begin // Place the relevant editor frame onto the editor tab, hide all others - Result := nil; - FActiveObjectEditor := nil; - if (not (Which in [lntTable])) and Assigned(TableEditor) then - FreeAndNil(TableEditor); - if (Which <> lntView) and Assigned(ViewEditor) then - FreeAndNil(ViewEditor); - if (not (Which in [lntProcedure, lntFunction])) and Assigned(RoutineEditor) then - FreeAndNil(RoutineEditor); - if (Which <> lntTrigger) and Assigned(TriggerEditor) then - FreeAndNil(TriggerEditor); - if Which in [lntTable] then begin - if not Assigned(TableEditor) then - TableEditor := TfrmTableEditor.Create(tabEditor); - Result := TableEditor; - end else if Which = lntView then begin - if not Assigned(ViewEditor) then - ViewEditor := TfrmView.Create(tabEditor); - Result := ViewEditor; - end else if Which in [lntProcedure, lntFunction] then begin - if not Assigned(RoutineEditor) then - RoutineEditor := TfrmRoutineEditor.Create(tabEditor); - Result := RoutineEditor; - end else if Which = lntTrigger then begin - if not Assigned(TriggerEditor) then - TriggerEditor := TfrmTriggerEditor.Create(tabEditor); - Result := TriggerEditor; - end else - Exit; - Result.Parent := tabEditor; - FActiveObjectEditor := Result; + if Assigned(ActiveObjectEditor) and (Obj.NodeType <> ActiveObjectEditor.DBObject.NodeType) then + FreeAndNil(ActiveObjectEditor); + case Obj.NodeType of + lntTable: EditorClass := TfrmTableEditor; + lntView: EditorClass := TfrmView; + lntProcedure, lntFunction: EditorClass := TfrmRoutineEditor; + lntTrigger: EditorClass := TfrmTriggerEditor; + lntEvent: EditorClass := TfrmEventEditor; + else Exit; + end; + if not Assigned(ActiveObjectEditor) then begin + ActiveObjectEditor := EditorClass.Create(tabEditor); + ActiveObjectEditor.Parent := tabEditor; + end; + ActiveObjectEditor.Init(Obj); end; -procedure TMainForm.SetEditorTabCaption(Editor: TDBObjectEditor; ObjName: String); +procedure TMainForm.UpdateEditorTab; var - ObjType, Cap: String; - IconIndex: Integer; + Cap: String; begin - if Editor = TableEditor then begin - ObjType := 'Table'; - IconIndex := ICONINDEX_TABLE; - end else if Editor = ViewEditor then begin - ObjType := 'View'; - IconIndex := ICONINDEX_VIEW; - end else if Editor = RoutineEditor then begin - ObjType := 'Routine'; - IconIndex := ICONINDEX_STOREDPROCEDURE; - end else if Editor = TriggerEditor then begin - ObjType := 'Trigger'; - IconIndex := ICONINDEX_Trigger; - end else - Exit; - tabEditor.ImageIndex := IconIndex; - Cap := ObjType+': '; - if ObjName = '' then + tabEditor.ImageIndex := ActiveObjectEditor.DBObject.ImageIndex; + Cap := ActiveObjectEditor.DBObject.ObjType+': '; + if ActiveObjectEditor.DBObject.Name = '' then Cap := Cap + '[Untitled]' else - Cap := sstr(Cap + ObjName, 30); + Cap := sstr(Cap + ActiveObjectEditor.DBObject.Name, 30); SetTabCaption(tabEditor.PageIndex, Cap); end; @@ -8510,8 +8449,8 @@ begin SelectDBObject(Obj.Name, Obj.NodeType); end; - case GetFocusedTreeNodeType of - lntDb: begin + case DBtree.GetNodeLevel(DBtree.FocusedNode) of + 1: begin if CreateDatabaseForm = nil then CreateDatabaseForm := TCreateDatabaseForm.Create(Self); CreateDatabaseForm.modifyDB := ActiveDatabase; @@ -8528,27 +8467,9 @@ begin end; end; - lntTable: begin - PlaceObjectEditor(SelectedTable.NodeType); - TableEditor.Init(SelectedTable.Name); - end; - - lntView: begin - PlaceObjectEditor(SelectedTable.NodeType); - ViewEditor.Init(SelectedTable.Name); - end; - - lntFunction, lntProcedure: begin - PlaceObjectEditor(SelectedTable.NodeType); - RoutineEditor.Init(SelectedTable.Name, SelectedTable.NodeType); - end; - - lntTrigger: begin - PlaceObjectEditor(SelectedTable.NodeType); - TriggerEditor.Init(SelectedTable.Name); - end; - + 2: PlaceObjectEditor(SelectedTable); end; + end; @@ -9166,6 +9087,17 @@ var ActiveLineColor: TColor; Attri: TSynHighlighterAttributes; Shortcut1, Shortcut2: TShortcut; + + procedure FindEditors(Comp: TComponent); + var i: Integer; + begin + for i:=0 to Comp.ComponentCount-1 do begin + if Comp.Components[i] is TSynMemo then + Editors.Add(Comp.Components[i]); + FindEditors(Comp.Components[i]); + end; + end; + begin // Restore font, highlighter and shortcuts for each instantiated TSynMemo Editors := TObjectList.Create; @@ -9175,18 +9107,8 @@ begin Editors.Add(SynMemoFilter); Editors.Add(SynMemoProcessView); Editors.Add(SynMemoSQLLog); - if Assigned(TableEditor) then begin - Editors.Add(TableEditor.SynMemoCREATEcode); - Editors.Add(TableEditor.SynMemoALTERcode); - end; - if Assigned(ViewEditor) then - Editors.Add(ViewEditor.SynMemoSelect); - if Assigned(RoutineEditor) then begin - Editors.Add(RoutineEditor.SynMemoBody); - Editors.Add(RoutineEditor.SynMemoCREATEcode); - end; - if Assigned(TriggerEditor) then - Editors.Add(TriggerEditor.SynMemoStatement); + if Assigned(ActiveObjectEditor) then + FindEditors(ActiveObjectEditor); if Assigned(CreateDatabaseForm) then Editors.Add(CreateDatabaseForm.SynMemoPreview); if Assigned(OptionsForm) then diff --git a/source/mysql_connection.pas b/source/mysql_connection.pas index 0a34d4bd..bd3c23ab 100644 --- a/source/mysql_connection.pas +++ b/source/mysql_connection.pas @@ -9,13 +9,20 @@ uses type { TDBObjectList and friends } - TListNodeType = (lntNone, lntDb, lntTable, lntView, lntFunction, lntProcedure, lntTrigger, lntColumn); + TListNodeType = (lntNone, lntDb, lntTable, lntView, lntFunction, lntProcedure, lntTrigger, lntEvent, lntColumn); TListNodeTypes = Set of TListNodeType; - TDBObject = class - Name, Database, Engine, Comment, RowFormat, CreateOptions, Collation, ObjType: String; + TDBObject = class(TObject) + Name, Database, Engine, Comment, RowFormat, CreateOptions, Collation: String; Created, Updated, LastChecked: TDateTime; Rows, Size, Version, AvgRowLen, MaxDataLen, IndexLen, DataLen, DataFree, AutoInc, CheckSum: Int64; NodeType: TListNodeType; + private + function GetObjType: String; + function GetImageIndex: Integer; + public + constructor Create; + property ObjType: String read GetObjType; + property ImageIndex: Integer read GetImageIndex; end; PDBObject = ^TDBObject; TDBObjectList = TObjectList; @@ -133,7 +140,6 @@ type function GetInformationSchemaObjects: TStringList; function GetConnectionUptime: Integer; function GetServerUptime: Integer; - function ParseDateTime(Str: String): TDateTime; procedure Log(Category: TMySQLLogCategory; Msg: String); procedure ClearCache; procedure SetObjectNamesInSelectedDB; @@ -154,6 +160,7 @@ type function GetDBObjects(db: String; Refresh: Boolean=False): TDBObjectList; function GetDBSize(db: String): Int64; function DbObjectsCached(db: String): Boolean; + function ParseDateTime(Str: String): TDateTime; procedure ClearDbObjects(db: String); procedure ClearAllDbObjects; property Parameters: TConnectionParameters read FParameters write FParameters; @@ -1071,12 +1078,9 @@ begin Obj.Size := StrToInt64Def(Results.Col('Data_length'), 0) + StrToInt64Def(Results.Col('Index_length'), 0); Inc(DBSize, Obj.Size); end; - Obj.ObjType := 'TABLE'; Obj.NodeType := lntTable; - if Results.IsNull(1) and Results.IsNull(2) then begin // Engine column is NULL for views + if Results.IsNull(1) and Results.IsNull(2) then // Engine column is NULL for views Obj.NodeType := lntView; - Obj.ObjType := 'VIEW'; - end; Obj.Created := ParseDateTime(Results.Col('Create_time')); Obj.Updated := ParseDateTime(Results.Col('Update_time')); if Results.ColExists('Type') then @@ -1117,7 +1121,6 @@ begin obj.Database := db; obj.Rows := -1; Obj.Size := -1; - Obj.ObjType := 'FUNCTION'; Obj.NodeType := lntFunction; Obj.Created := ParseDateTime(Results.Col('Created')); Obj.Updated := ParseDateTime(Results.Col('Modified')); @@ -1153,7 +1156,6 @@ begin obj.Database := db; obj.Rows := -1; Obj.Size := -1; - Obj.ObjType := 'PROCEDURE'; Obj.NodeType := lntProcedure; Obj.Created := ParseDateTime(Results.Col('Created')); Obj.Updated := ParseDateTime(Results.Col('Modified')); @@ -1189,7 +1191,6 @@ begin obj.Database := db; obj.Rows := -1; Obj.Size := -1; - Obj.ObjType := 'TRIGGER'; Obj.NodeType := lntTrigger; Obj.Created := ParseDateTime(Results.Col('Created')); Obj.Updated := 0; @@ -1212,6 +1213,41 @@ begin FreeAndNil(Results); end; + // Events + if ServerVersionInt >= 50100 then try + Results := GetResults('SHOW EVENTS FROM '+QuoteIdent(db)); + except + end; + if Assigned(Results) then begin + while not Results.Eof do begin + obj := TDBObject.Create; + Result.Add(obj); + obj.Name := Results.Col('Name'); + obj.Database := db; + obj.Rows := -1; + Obj.Size := -1; + Obj.NodeType := lntEvent; + Obj.Created := 0; + Obj.Updated := 0; + Obj.Engine := ''; + Obj.Comment := ''; + Obj.Version := -1; + Obj.AutoInc := -1; + Obj.RowFormat := ''; + Obj.AvgRowLen := -1; + Obj.MaxDataLen := -1; + Obj.IndexLen := -1; + Obj.DataLen := -1; + Obj.DataFree := -1; + Obj.LastChecked := 0; + Obj.Collation := ''; + Obj.CheckSum := -1; + Obj.CreateOptions := ''; + Results.Next; + end; + FreeAndNil(Results); + end; + // Sort list like it get sorted in MainForm.vstCompareNodes Result.Sort; @@ -1468,4 +1504,40 @@ begin end; +{ TDBObject } + +constructor TDBObject.Create; +begin + NodeType := lntNone; +end; + + +function TDBObject.GetObjType: String; +begin + case NodeType of + lntTable: Result := 'Table'; + lntView: Result := 'View'; + lntFunction: Result := 'Function'; + lntProcedure: Result := 'Procedure'; + lntTrigger: Result := 'Trigger'; + lntEvent: Result := 'Event'; + else Result := 'Unknown, should never appear'; + end; +end; + +function TDBObject.GetImageIndex: Integer; +begin + // Detect key icon index for specified db object (table, trigger, ...) + case NodeType of + lntTable: Result := ICONINDEX_TABLE; + lntFunction: Result := ICONINDEX_STOREDFUNCTION; + lntProcedure: Result := ICONINDEX_STOREDPROCEDURE; + lntView: Result := ICONINDEX_VIEW; + lntTrigger: Result := ICONINDEX_TRIGGER; + lntEvent: Result := ICONINDEX_EVENT; + else Result := -1; + end; +end; + + end. diff --git a/source/printlist.pas b/source/printlist.pas index 7aa75763..cfdba2ea 100644 --- a/source/printlist.pas +++ b/source/printlist.pas @@ -34,7 +34,7 @@ type implementation -uses main, helpers; +uses main, helpers, table_editor, mysql_connection; {$R *.DFM} @@ -78,8 +78,12 @@ begin else list := Mainform.ListCommandStats; end; 1: list := Mainform.ListTables; - 2: if Assigned(Mainform.TableEditor) and Mainform.TableEditor.Visible then - list := Mainform.TableEditor.listColumns; + 2: begin + if Assigned(Mainform.ActiveObjectEditor) + and (Mainform.ActiveObjectEditor.DBObject.NodeType = lntTable) + and Mainform.ActiveObjectEditor.Visible then + list := (Mainform.ActiveObjectEditor as TfrmTableEditor).listColumns; + end; else list := Mainform.ActiveGrid; end; if Assigned(list) then diff --git a/source/routine_editor.pas b/source/routine_editor.pas index 062d7a67..d4bedf3e 100644 --- a/source/routine_editor.pas +++ b/source/routine_editor.pas @@ -79,7 +79,7 @@ type Parameters: TRoutineParamList; constructor Create(AOwner: TComponent); override; destructor Destroy; override; - procedure Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); override; + procedure Init(Obj: TDBObject); override; function ApplyModifications: TModalResult; override; end; @@ -126,15 +126,15 @@ begin end; -procedure TfrmRoutineEditor.Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); +procedure TfrmRoutineEditor.Init(Obj: TDBObject); var Create, Returns, DataAccess, Security, Comment, Body: String; Deterministic: Boolean; begin inherited; - if ObjectType = lntProcedure then FAlterRoutineType := 'PROCEDURE' + if Obj.NodeType = lntProcedure then FAlterRoutineType := 'PROCEDURE' else FAlterRoutineType := 'FUNCTION'; - editName.Text := FEditObjectName; + editName.Text := DBObject.Name; comboType.ItemIndex := 0; comboReturns.Text := ''; chkDeterministic.Checked := False; @@ -144,7 +144,7 @@ begin comboSecurity.ItemIndex := 0; editComment.Clear; SynMemoBody.Text := 'BEGIN'+CRLF+CRLF+'END'; - if FEditObjectName <> '' then begin + if DBObject.Name <> '' then begin // Editing existing routine comboType.ItemIndex := ListIndexByRegExpr(comboType.Items, '^'+FAlterRoutineType+'\b'); Create := Mainform.Connection.GetVar('SHOW CREATE '+FAlterRoutineType+' '+Mainform.mask(editName.Text), 2); @@ -166,7 +166,7 @@ begin Modified := False; btnSave.Enabled := Modified; btnDiscard.Enabled := Modified; - Mainform.actRunRoutines.Enabled := FEditObjectName <> ''; + Mainform.actRunRoutines.Enabled := DBObject.Name <> ''; Mainform.ShowStatusMsg; Screen.Cursor := crDefault; end; @@ -407,7 +407,6 @@ var allRoutineNames: TStringList; ProcOrFunc: String; TargetExists: Boolean; - t: TListNodeType; begin // Save changes Result := mrOk; @@ -417,14 +416,14 @@ begin // Create a temp routine, check for syntax errors, then drop the old routine and create it. // See also: http://dev.mysql.com/doc/refman/5.0/en/alter-procedure.html try - if FEditObjectName <> '' then begin + if DBObject.Name <> '' then begin // Create temp name i := 0; allRoutineNames := Mainform.Connection.GetCol('SELECT ROUTINE_NAME FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.'+Mainform.mask('ROUTINES')+ ' WHERE ROUTINE_SCHEMA = '+esc(Mainform.ActiveDatabase)+ ' AND ROUTINE_TYPE = '+esc(ProcOrFunc) ); - TargetExists := ((editName.Text <> FEditObjectName) or (ProcOrFunc <> FAlterRoutineType)) and + TargetExists := ((editName.Text <> DBObject.Name) or (ProcOrFunc <> FAlterRoutineType)) and (allRoutineNames.IndexOf(editName.Text) > -1); if TargetExists then begin Result := MessageDlg('Routine "'+editName.Text+'" already exists. Overwrite it?', @@ -442,7 +441,7 @@ begin // Drop temporary routine, used for syntax checking Mainform.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(TempName)); // Drop edited routine - Mainform.Connection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+Mainform.mask(FEditObjectName)); + Mainform.Connection.Query('DROP '+FAlterRoutineType+' IF EXISTS '+Mainform.mask(DBObject.Name)); if TargetExists then begin // Drop target routine - overwriting has been confirmed, see above Mainform.Connection.Query('DROP '+ProcOrFunc+' IF EXISTS '+Mainform.mask(editName.Text)); @@ -450,12 +449,12 @@ begin end; Mainform.Connection.Query(ComposeCreateStatement(editName.Text)); // Set editing name if create/alter query was successful - FEditObjectName := editName.Text; + DBObject.Name := editName.Text; FAlterRoutineType := UpperCase(GetFirstWord(comboType.Text)); - Mainform.SetEditorTabCaption(Self, FEditObjectName); - if FAlterRoutineType = 'PROCEDURE' then t := lntProcedure - else t := lntFunction; - Mainform.RefreshTreeDB(Mainform.ActiveDatabase, FEditObjectName, t); + if FAlterRoutineType = 'PROCEDURE' then DBObject.NodeType := lntProcedure + else DBObject.NodeType := lntFunction; + Mainform.UpdateEditorTab; + Mainform.RefreshTreeDB(Mainform.ActiveDatabase, DBObject.Name, DBObject.NodeType); Modified := False; btnSave.Enabled := Modified; btnDiscard.Enabled := Modified; @@ -498,13 +497,9 @@ end; procedure TfrmRoutineEditor.btnDiscardClick(Sender: TObject); -var - t: TListNodeType; begin Modified := False; - if FAlterRoutineType = 'PROCEDURE' then t := lntProcedure - else t := lntFunction; - Init(FEditObjectName, t); + Init(DBObject); end; diff --git a/source/table_editor.pas b/source/table_editor.pas index 3b1ac6dd..22d52535 100644 --- a/source/table_editor.pas +++ b/source/table_editor.pas @@ -197,7 +197,7 @@ type { Public declarations } constructor Create(AOwner: TComponent); override; destructor Destroy; override; - procedure Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); override; + procedure Init(Obj: TDBObject); override; function ApplyModifications: TModalResult; override; end; @@ -217,7 +217,6 @@ const constructor TfrmTableEditor.Create(AOwner: TComponent); begin inherited; - ScaleControls(Screen.PixelsPerInch, FORMS_DPI); PageControlMain.Height := GetRegValue(REGNAME_TABLEEDITOR_TABSHEIGHT, PageControlMain.Height); FixVT(listColumns); FixVT(treeIndexes); @@ -253,7 +252,7 @@ begin end; -procedure TfrmTableEditor.Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); +procedure TfrmTableEditor.Init(Obj: TDBObject); var CreateTable, AttrName, AttrValue: String; rx: TRegExpr; @@ -267,7 +266,7 @@ begin FColumns.Clear; btnClearIndexesClick(Self); btnClearForeignKeysClick(Self); - tabALTERcode.TabVisible := FEditObjectName <> ''; + tabALTERcode.TabVisible := DBObject.Name <> ''; // Clear value editors memoComment.Text := ''; editAutoInc.Text := ''; @@ -279,14 +278,14 @@ begin memoUnionTables.Clear; comboInsertMethod.ItemIndex := -1; - if FEditObjectName = '' then begin + if DBObject.Name = '' then begin // Creating new table editName.Text := ''; comboCollation.ItemIndex := comboCollation.Items.IndexOf(Mainform.Connection.GetVar('SHOW VARIABLES LIKE ''collation_database''', 1)); PageControlMain.ActivePage := tabBasic; end else begin // Editing existing table - editName.Text := FEditObjectName; + editName.Text := DBObject.Name; CreateTable := Mainform.SelectedTableCreateStatement; rx := TRegExpr.Create; rx.ModifierI := True; @@ -350,7 +349,7 @@ procedure TfrmTableEditor.btnDiscardClick(Sender: TObject); begin // Reinit GUI, discarding changes Modified := False; - Init(FEditObjectName); + Init(DBObject); end; @@ -370,7 +369,7 @@ begin // Create or alter table Result := mrOk; Specs := TStringList.Create; - if FEditObjectName = '' then + if DBObject.Name = '' then sql := ComposeCreateStatement else begin sql := ComposeAlterStatement; @@ -386,9 +385,9 @@ begin end; try if Specs.Count > 0 then - Mainform.Connection.Query('ALTER TABLE '+Mainform.mask(FEditObjectName)+' '+ImplodeStr(', ', Specs)); + Mainform.Connection.Query('ALTER TABLE '+Mainform.mask(DBObject.Name)+' '+ImplodeStr(', ', Specs)); Mainform.Connection.Query(sql); - tabALTERcode.TabVisible := FEditObjectName <> ''; + tabALTERcode.TabVisible := DBObject.Name <> ''; if chkCharsetConvert.Checked then begin // Autoadjust column collations for i:=0 to FColumns.Count-1 do begin @@ -397,10 +396,10 @@ begin end; end; // Set table name for altering if Apply was clicked - FEditObjectName := editName.Text; - tabALTERcode.TabVisible := FEditObjectName <> ''; - Mainform.SetEditorTabCaption(Self, FEditObjectName); - Mainform.RefreshTreeDB(Mainform.ActiveDatabase, FEditObjectName, lntTable); + DBObject.Name := editName.Text; + tabALTERcode.TabVisible := DBObject.Name <> ''; + Mainform.UpdateEditorTab; + Mainform.RefreshTreeDB(Mainform.ActiveDatabase, DBObject.Name, DBObject.NodeType); Mainform.ParseSelectedTableStructure; ResetModificationFlags; AlterCodeValid := False; @@ -463,7 +462,7 @@ begin Mainform.ShowStatusMsg('Composing ALTER statement ...'); Screen.Cursor := crHourglass; Specs := TStringList.Create; - if editName.Text <> FEditObjectName then + if editName.Text <> DBObject.Name then Specs.Add('RENAME TO ' + Mainform.mask(editName.Text)); if memoComment.Tag = ModifiedFlag then Specs.Add('COMMENT=' + esc(memoComment.Text)); @@ -582,7 +581,7 @@ begin Specs.Add('ADD '+GetForeignKeySQL(i)); end; - Result := 'ALTER TABLE '+Mainform.mask(FEditObjectName) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs); + Result := 'ALTER TABLE '+Mainform.mask(DBObject.Name) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs); Result := Trim(Result); FreeAndNil(Specs); Mainform.ShowStatusMsg; @@ -1786,7 +1785,7 @@ end; procedure TfrmTableEditor.chkCharsetConvertClick(Sender: TObject); begin - chkCharsetConvert.Enabled := (FEditObjectName <> '') and (comboCollation.ItemIndex > -1); + chkCharsetConvert.Enabled := (DBObject.Name <> '') and (comboCollation.ItemIndex > -1); listColumns.Repaint; Modification(Sender); end; @@ -2114,7 +2113,7 @@ begin 2: begin Key.ReferenceTable := NewText; if not Key.KeyNameWasCustomized then - Key.KeyName := 'FK_'+FEditObjectName+'_'+Key.ReferenceTable; + Key.KeyName := 'FK_'+DBObject.Name+'_'+Key.ReferenceTable; end; 3: Key.ForeignColumns := Explode(',', NewText); 4: Key.OnUpdate := NewText; diff --git a/source/tabletools.pas b/source/tabletools.pas index 4ec76a57..e457b904 100644 --- a/source/tabletools.pas +++ b/source/tabletools.pas @@ -1031,7 +1031,7 @@ begin if chkExportTablesDrop.Checked or chkExportTablesCreate.Checked then begin Output(CRLF+CRLF+'# Dumping structure for '+LowerCase(DBObj.ObjType)+' '+DBObj.Database+'.'+DBObj.Name+CRLF, False, True, True, False, False); if chkExportTablesDrop.Checked then begin - Struc := 'DROP '+DBObj.ObjType+' IF EXISTS '; + Struc := 'DROP '+UpperCase(DBObj.ObjType)+' IF EXISTS '; if ToDb then Struc := Struc + m(FinalDbName)+'.'; Struc := Struc + m(DBObj.Name); @@ -1062,7 +1062,7 @@ begin lntTrigger: begin StrucResult := Mainform.Connection.GetResults('SHOW TRIGGERS WHERE `Trigger`='+esc(DBObj.Name)); - Struc := 'CREATE '+DBObj.ObjType+' '+m(DBObj.Name)+' '+StrucResult.Col('Timing')+' '+StrucResult.Col('Event')+ + Struc := 'CREATE '+UpperCase(DBObj.ObjType)+' '+m(DBObj.Name)+' '+StrucResult.Col('Timing')+' '+StrucResult.Col('Event')+ ' ON '+m(StrucResult.Col('Table'))+' FOR EACH ROW '+StrucResult.Col('Statement'); if ToDb then Insert(m(FinalDbName)+'.', Struc, Pos('TRIGGER', Struc) + 8 ); @@ -1076,7 +1076,7 @@ begin end; lntFunction, lntProcedure: begin - Struc := Mainform.Connection.GetVar('SHOW CREATE '+DBObj.ObjType+' '+m(DBObj.Database)+'.'+m(DBObj.Name), 2); + Struc := Mainform.Connection.GetVar('SHOW CREATE '+UpperCase(DBObj.ObjType)+' '+m(DBObj.Database)+'.'+m(DBObj.Name), 2); // Todo: Why exploding? MultiSQL := Explode(';', Struc); Struc := ImplodeStr(';'+CRLF, MultiSQL); diff --git a/source/trigger_editor.pas b/source/trigger_editor.pas index 2aef6c7e..f6e6022b 100644 --- a/source/trigger_editor.pas +++ b/source/trigger_editor.pas @@ -34,7 +34,7 @@ type public { Public declarations } constructor Create(AOwner: TComponent); override; - procedure Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); override; + procedure Init(Obj: TDBObject); override; function ApplyModifications: TModalResult; override; end; @@ -54,7 +54,6 @@ var i: Integer; begin inherited; - ScaleControls(Screen.PixelsPerInch, FORMS_DPI); SynMemoStatement.Highlighter := Mainform.SynSQLSyn1; editName.MaxLength := NAME_LEN; comboTiming.Items.Text := 'BEFORE'+CRLF+'AFTER'; @@ -73,7 +72,7 @@ begin end; -procedure TfrmTriggerEditor.Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); +procedure TfrmTriggerEditor.Init(Obj: TDBObject); var Definitions: TMySQLQuery; DBObjects: TDBObjectList; @@ -93,13 +92,13 @@ begin end; if comboTable.Items.Count > 0 then comboTable.ItemIndex := 0; - if FEditObjectName <> '' then begin + if DBObject.Name <> '' then begin // Edit mode - editName.Text := FEditObjectName; + editName.Text := DBObject.Name; Definitions := Mainform.Connection.GetResults('SHOW TRIGGERS FROM '+Mainform.mask(Mainform.ActiveDatabase)); Found := False; while not Definitions.Eof do begin - if Definitions.Col('Trigger') = FEditObjectName then begin + if Definitions.Col('Trigger') = DBObject.Name then begin comboTable.ItemIndex := comboTable.Items.IndexOf(Definitions.Col('Table')); comboTiming.ItemIndex := comboTiming.Items.IndexOf(UpperCase(Definitions.Col('Timing'))); comboEvent.ItemIndex := comboEvent.Items.IndexOf(UpperCase(Definitions.Col('Event'))); @@ -138,7 +137,7 @@ procedure TfrmTriggerEditor.btnDiscardClick(Sender: TObject); begin // Reinit editor, discarding changes Modified := False; - Init(FEditObjectName); + Init(DBObject); end; @@ -160,8 +159,8 @@ begin // So, we take the risk of loosing the trigger for cases in which the user has SQL errors in // his statement. The user must fix such errors and re-press "Save" while we have them in memory, // otherwise the trigger attributes are lost forever. - if FEditObjectName <> '' then try - Mainform.Connection.Query('DROP TRIGGER '+Mainform.mask(FEditObjectName)); + if DBObject.Name <> '' then try + Mainform.Connection.Query('DROP TRIGGER '+Mainform.mask(DBObject.Name)); except end; // CREATE @@ -173,9 +172,9 @@ begin ' ON '+Mainform.mask(comboTable.Text)+ ' FOR EACH ROW '+SynMemoStatement.Text; Mainform.Connection.Query(sql); - FEditObjectName := editName.Text; - Mainform.SetEditorTabCaption(Self, FEditObjectName); - Mainform.RefreshTreeDB(Mainform.ActiveDatabase, FEditObjectName, lntTrigger); + DBObject.Name := editName.Text; + Mainform.UpdateEditorTab; + Mainform.RefreshTreeDB(Mainform.ActiveDatabase, DBObject.Name, DBObject.NodeType); Modified := False; btnSave.Enabled := Modified; btnDiscard.Enabled := Modified; diff --git a/source/view.pas b/source/view.pas index eec0a966..a4d25897 100644 --- a/source/view.pas +++ b/source/view.pas @@ -29,7 +29,7 @@ type public { Public declarations } constructor Create(AOwner: TComponent); override; - procedure Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); override; + procedure Init(Obj: TDBObject); override; function ApplyModifications: TModalResult; override; end; @@ -47,7 +47,6 @@ uses main; constructor TfrmView.Create(AOwner: TComponent); begin inherited; - ScaleControls(Screen.PixelsPerInch, FORMS_DPI); SynMemoSelect.Highlighter := Mainform.SynSQLSyn1; Mainform.SynCompletionProposal.AddEditor(SynMemoSelect); editName.MaxLength := NAME_LEN; @@ -57,21 +56,21 @@ end; {** FormShow: Fill controls with content in edit mode } -procedure TfrmView.Init(ObjectName: String=''; ObjectType: TListNodeType=lntNone); +procedure TfrmView.Init(Obj: TDBObject); var Results: TMySQLQuery; db: String; rx: TRegExpr; begin inherited; - if FEditObjectName <> '' then begin + if Obj.Name <> '' then begin // Edit mode - editName.Text := FEditObjectName; + editName.Text := Obj.Name; db := Mainform.ActiveDatabase; Results := Mainform.Connection.GetResults('SELECT * FROM '+Mainform.mask(DBNAME_INFORMATION_SCHEMA)+'.VIEWS ' + - 'WHERE TABLE_SCHEMA = '+esc(db)+' AND TABLE_NAME = '+esc(FEditObjectName)); + 'WHERE TABLE_SCHEMA = '+esc(db)+' AND TABLE_NAME = '+esc(Obj.Name)); if Results.RecordCount = 0 then - raise Exception.Create('Can''t find view definition for "'+FEditObjectName+'" in '+DBNAME_INFORMATION_SCHEMA); + raise Exception.Create('Can''t find view definition for "'+Obj.Name+'" in '+DBNAME_INFORMATION_SCHEMA); // Algorithm is not changeable as we cannot look up its current state! rgAlgorithm.Enabled := False; rgAlgorithm.ItemIndex := 0; @@ -127,7 +126,7 @@ procedure TfrmView.btnHelpClick(Sender: TObject); var keyword: String; begin - if FEditObjectName = '' then + if DBObject.Name = '' then keyword := 'CREATE VIEW' else keyword := 'ALTER VIEW'; @@ -139,7 +138,7 @@ procedure TfrmView.btnDiscardClick(Sender: TObject); begin // Reinit editor, discarding changes Modified := False; - Init(FEditObjectName); + Init(DBObject); end; @@ -158,12 +157,12 @@ var begin // Save changes Result := mrOk; - if FEditObjectName = '' then begin + if DBObject.Name = '' then begin sql := 'CREATE '; viewname := editName.Text; end else begin sql := 'ALTER '; - viewname := FEditObjectName; + viewname := DBObject.Name; end; viewname := Mainform.mask(viewname); if rgAlgorithm.Enabled and (rgAlgorithm.ItemIndex > -1) then @@ -175,13 +174,13 @@ begin try Mainform.Connection.Query(sql); // Probably rename view - if (FEditObjectName <> '') and (FEditObjectName <> editName.Text) then begin + if (DBObject.Name <> '') and (DBObject.Name <> editName.Text) then begin renamed := Mainform.mask(editName.Text); Mainform.Connection.Query('RENAME TABLE '+viewname + ' TO '+renamed); end; - FEditObjectName := editName.Text; - Mainform.SetEditorTabCaption(Self, FEditObjectName); - Mainform.RefreshTreeDB(Mainform.ActiveDatabase, FEditObjectName, lntView); + DBObject.Name := editName.Text; + Mainform.UpdateEditorTab; + Mainform.RefreshTreeDB(Mainform.ActiveDatabase, DBObject.Name, DBObject.NodeType); Mainform.ParseSelectedTableStructure; Modified := False; btnSave.Enabled := Modified;