diff --git a/packages/delphi11/heidisql.dpr b/packages/delphi11/heidisql.dpr
index 30672cdb..725b8d38 100644
--- a/packages/delphi11/heidisql.dpr
+++ b/packages/delphi11/heidisql.dpr
@@ -35,7 +35,8 @@ uses
table_editor in '..\..\source\table_editor.pas' {frmTableEditor},
mysql_api in '..\..\source\mysql_api.pas',
mysql_connection in '..\..\source\mysql_connection.pas',
- cUnicodeCodecs in '..\..\source\cUnicodeCodecs.pas';
+ cUnicodeCodecs in '..\..\source\cUnicodeCodecs.pas',
+ trigger_editor in '..\..\source\trigger_editor.pas' {frmTriggerEditor: TFrame};
{$R ..\..\res\icon.RES}
{$R ..\..\res\version.RES}
diff --git a/packages/delphi11/heidisql.dproj b/packages/delphi11/heidisql.dproj
index de502b12..7b73c879 100644
--- a/packages/delphi11/heidisql.dproj
+++ b/packages/delphi11/heidisql.dproj
@@ -180,6 +180,9 @@
+
+
+
diff --git a/res/icons/cog.png b/res/icons/cog.png
new file mode 100644
index 00000000..67de2c6c
Binary files /dev/null and b/res/icons/cog.png differ
diff --git a/source/const.inc b/source/const.inc
index 2ecae042..a8ffe178 100644
--- a/source/const.inc
+++ b/source/const.inc
@@ -247,6 +247,7 @@ const
ICONINDEX_CRASHED_TABLE = -1;
ICONINDEX_STOREDPROCEDURE = 119;
ICONINDEX_STOREDFUNCTION = 35;
+ ICONINDEX_TRIGGER = 137;
ICONINDEX_FUNCTION = 13;
ICONINDEX_KEYWORD = 25;
@@ -312,3 +313,5 @@ const
FKEY = 'FULLTEXT';
SKEY = 'SPATIAL';
+ SYNCOMPLETION_PATTERN: WideString = '\image{%d}\hspace{5}\color{clSilver}%s\column{}\color{clWindowText}%s';
+
diff --git a/source/helpers.pas b/source/helpers.pas
index c00299c5..2a7b7ad6 100644
--- a/source/helpers.pas
+++ b/source/helpers.pas
@@ -15,7 +15,7 @@ uses Classes, SysUtils, Graphics, GraphUtil, db, clipbrd, dialogs,
type
- TListNodeType = (lntNone, lntDb, lntTable, lntCrashedTable, lntView, lntFunction, lntProcedure, lntColumn);
+ TListNodeType = (lntNone, lntDb, lntTable, lntCrashedTable, lntView, lntFunction, lntProcedure, lntTrigger, lntColumn);
TListNodeTypes = Set of TListNodeType;
TListNode = record
Text: WideString;
@@ -2194,7 +2194,9 @@ begin
else if t = 'FUNCTION' then
Result := lntFunction
else if t = 'PROCEDURE' then
- Result := lntProcedure;
+ Result := lntProcedure
+ else if t = 'TRIGGER' then
+ Result := lntTrigger;
end else begin
if
TableStatus.IsNull(1) and // Engine column is NULL for views
diff --git a/source/main.dfm b/source/main.dfm
index 0ba7235b..d1d1acaf 100644
--- a/source/main.dfm
+++ b/source/main.dfm
@@ -2241,6 +2241,13 @@ object MainForm: TMainForm
ImageIndex = 19
OnExecute = actTableToolsExecute
end
+ object actCreateTrigger: TAction
+ Category = 'Database'
+ Caption = 'Trigger'
+ Hint = 'Create a trigger'
+ ImageIndex = 137
+ OnExecute = actCreateTriggerExecute
+ end
end
object SaveDialog2: TSaveDialog
DefaultExt = 'reg'
@@ -6039,6 +6046,29 @@ object MainForm: TMainForm
411C2FC06964B5EBFC0F200C40D1D6D566E00000000049454E44AE426082}
Name = 'PngImage136'
Background = clWindow
+ end
+ item
+ PngImage.Data = {
+ 89504E470D0A1A0A0000000D4948445200000010000000100804000000B5FA37
+ EA0000000467414D410000AFC837058AE90000001974455874536F6674776172
+ 650041646F626520496D616765526561647971C9653C000001C34944415478DA
+ 4D514D48545114FEEEC31C9A37FDBC11A79B4A61D1420884878B84C0160AAE5B
+ CF4A7117D1225AF8FCC1D171693B0986DC680BB111DCB431988DE84039D4A398
+ 4D1158D230538EDADCF14DF7BE773B3D453D97CB8573BEFB9DEF9C8F699CC5FB
+ 6195F421971EBC3CCBB16380DBE5EFFA3555BAD1AA91AF44B98AC9F687C55380
+ 9BF1875459D9AAD0C1353E97B42D0B32A116922321E0A3139BB1B0879F424539
+ 0BF045ABFA4DB3031FF069EC699A00EFC6FF4E71E6E1020C4804F436E8F858D3
+ DEE4DC74D862337D65D4A3D40176A8DC892602D6E1CE3E73A8457E5B2594C92D
+ 812A36B7C4440456AAA757C344AE2A852AB30DFF8EF11B7FE86711DF069CB740
+ A63FBECE8921866B980B58CEBF6DECA386087E6067E01101E6FB5BD6DB207011
+ 713C0FD8E2F6AF8465765B476886BB25272464CAEE95A468A55A13B21C8ACCA6
+ AF8F2A9266E03B15DAE81E11436E76DE09F7F07A5C4E75B37D6268867732A687
+ CB58D48DC917FFC77CE5F0995BC8E3AB30A27DB4A815CDEAF7CCBB58853B964D
+ 872D5299BD21518EDB970A835C2153F2ECA0504FC8853723A7663DE992BB576B
+ 91D2FD5681E58AE646ECB07DAD78CECDE3783C5C4936C096B2E7ECFE0748C2CE
+ 3B74ACC3980000000049454E44AE426082}
+ Name = 'PngImage137'
+ Background = clWindow
end>
PngOptions = [pngBlendOnDisabled, pngGrayscaleOnDisabled]
Left = 104
@@ -6090,6 +6120,9 @@ object MainForm: TMainForm
object menuCreateRoutine: TMenuItem
Action = actCreateRoutine
end
+ object menuCreateTrigger: TMenuItem
+ Action = actCreateTrigger
+ end
end
object N17: TMenuItem
Caption = '-'
diff --git a/source/main.pas b/source/main.pas
index 40f5821e..8eafecdf 100644
--- a/source/main.pas
+++ b/source/main.pas
@@ -20,7 +20,7 @@ uses
SynCompletionProposal, SynEditHighlighter, SynHighlighterSQL,
TntStdCtrls, Tabs, SynUnicode, EditVar, helpers,
createdatabase, table_editor, SynRegExpr,
- WideStrUtils, ExtActns, CommCtrl, routine_editor, options,
+ WideStrUtils, ExtActns, CommCtrl, routine_editor, trigger_editor, options,
Contnrs, PngSpeedButton, connections, SynEditKeyCmds,
mysql_connection, mysql_api, insertfiles, TntComCtrls;
@@ -444,6 +444,8 @@ type
menuQueryHelpersGenerateInsert: TMenuItem;
menuQueryHelpersGenerateUpdate: TMenuItem;
menuQueryHelpersGenerateDelete: TMenuItem;
+ actCreateTrigger: TAction;
+ menuCreateTrigger: TMenuItem;
procedure refreshMonitorConfig;
procedure loadWindowConfig;
procedure saveWindowConfig;
@@ -703,6 +705,7 @@ type
procedure TimerFilterVTTimer(Sender: TObject);
procedure PageControlMainContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean);
procedure menuQueryHelpersGenerateStatementClick(Sender: TObject);
+ procedure actCreateTriggerExecute(Sender: TObject);
private
ReachedEOT : Boolean;
FDelimiter: String;
@@ -751,6 +754,7 @@ type
SelectDBObjectForm: TfrmSelectDBObject;
SQLHelpForm: TfrmSQLhelp;
RoutineEditor: TfrmRoutineEditor;
+ TriggerEditor: TfrmTriggerEditor;
OptionsForm: Toptionsform;
SessionManager: TConnForm;
AllDatabases, Databases: TWideStringList;
@@ -1094,6 +1098,7 @@ begin
FreeAndNil(OptionsForm);
FreeAndNil(SessionManager);
FreeAndNil(TableEditor);
+ FreeAndNil(TriggerEditor);
FreeAndNil(CreateDatabaseForm);
debug('mem: clearing query and browse data.');
@@ -2166,7 +2171,7 @@ end;
procedure TMainForm.actDropObjectsExecute(Sender: TObject);
var
AllCount : Integer;
- Tables, Views, Functions, Procedures: TWideStringList;
+ Tables, Views, Functions, Procedures, Triggers: TWideStringList;
msg, activeDB : WideString;
InDBTree: Boolean;
Act: TAction;
@@ -2203,6 +2208,7 @@ begin
Views := TWideStringlist.Create;
Procedures := TWideStringlist.Create;
Functions := TWideStringlist.Create;
+ Triggers := TWideStringlist.Create;
Act := Sender as TAction;
InDBTree := (Act.ActionComponent is TMenuItem)
@@ -2229,6 +2235,7 @@ begin
lntView: Views.Add(SelectedTable.Text);
lntProcedure: Procedures.Add(SelectedTable.Text);
lntFunction: Functions.Add(SelectedTable.Text);
+ lntTrigger: Triggers.Add(SelectedTable.Text);
end;
end else begin
// Invoked from database tab
@@ -2237,12 +2244,13 @@ begin
Views := GetVTCaptions(ListTables, True, 0, [lntView]);
Procedures := GetVTCaptions(ListTables, True, 0, [lntProcedure]);
Functions := GetVTCaptions(ListTables, True, 0, [lntFunction]);
+ Triggers := GetVTCaptions(ListTables, True, 0, [lntTrigger]);
end;
// Fix actions temporarily enabled for popup menu.
ValidateControls(Sender);
- AllCount := Tables.Count + Views.Count + Procedures.Count + Functions.Count;
+ AllCount := Tables.Count + Views.Count + Procedures.Count + Functions.Count + Triggers.Count;
// Safety stop to avoid firing DROP TABLE without tablenames
if (AllCount = 0) then
@@ -2255,6 +2263,7 @@ begin
if Views.Count > 0 then msg := msg + CRLF + 'View(s): ' + ImplodeStr(', ', Views);
if Procedures.Count > 0 then msg := msg + CRLF + 'Procedure(s): ' + ImplodeStr(', ', Procedures);
if Functions.Count > 0 then msg := msg + CRLF + 'Function(s): ' + ImplodeStr(', ', Functions);
+ if Triggers.Count > 0 then msg := msg + CRLF + 'Trigger(s): ' + ImplodeStr(', ', Triggers);
if MessageDlg(msg, mtConfirmation, [mbok,mbcancel], 0) <> mrok then
Exit;
@@ -2264,6 +2273,7 @@ begin
DoDrop('VIEW', Views, True);
DoDrop('PROCEDURE', Procedures, False);
DoDrop('FUNCTION', Functions, False);
+ DoDrop('TRIGGER', Triggers, False);
// Refresh ListTables + dbtree so the dropped tables are gone:
actRefresh.Execute;
except
@@ -3580,6 +3590,30 @@ begin
' FROM '+mask(DBNAME_INFORMATION_SCHEMA)+'.ROUTINES ' +
'WHERE ROUTINE_SCHEMA = '+esc(db));
end;
+ if Connection.InformationSchemaObjects.IndexOf('TRIGGERS') > -1 then begin
+ // Stored routines
+ Unions.Add('SELECT TRIGGER_NAME AS '+mask(DBO_NAME)+
+ ', ''TRIGGER'' AS '+mask(DBO_TYPE)+
+ ', NULL AS '+mask(DBO_ENGINE)+
+ ', NULL AS '+mask(DBO_VERSION)+
+ ', NULL AS '+mask(DBO_ROWFORMAT)+
+ ', NULL AS '+mask(DBO_ROWS)+
+ ', NULL AS '+mask(DBO_AVGROWLEN)+
+ ', NULL AS '+mask(DBO_DATALEN)+
+ ', NULL AS '+mask(DBO_MAXDATALEN)+
+ ', NULL AS '+mask(DBO_INDEXLEN)+
+ ', NULL AS '+mask(DBO_DATAFREE)+
+ ', NULL AS '+mask(DBO_AUTOINC)+
+ ', CREATED AS '+mask(DBO_CREATED)+
+ ', NULL AS '+mask(DBO_UPDATED)+
+ ', NULL AS '+mask(DBO_CHECKED)+
+ ', DATABASE_COLLATION AS '+mask(DBO_COLLATION)+
+ ', NULL AS '+mask(DBO_CHECKSUM)+
+ ', NULL AS '+mask(DBO_CROPTIONS)+
+ ', NULL AS '+mask(DBO_COMMENT)+
+ ' FROM '+mask(DBNAME_INFORMATION_SCHEMA)+'.TRIGGERS ' +
+ 'WHERE TRIGGER_SCHEMA = '+esc(db));
+ end;
case Unions.Count of
0: ListObjectsSQL := 'SHOW TABLE STATUS FROM ' + mask(db);
1: ListObjectsSQL := Unions[0] + ' ORDER BY `Name`';
@@ -3722,6 +3756,7 @@ begin
lntView: img := ICONINDEX_VIEW;
lntProcedure: img := ICONINDEX_STOREDPROCEDURE;
lntFunction: img := ICONINDEX_STOREDFUNCTION;
+ lntTrigger: img := ICONINDEX_TRIGGER;
else img := -1;
end;
VTRowDataListTables[i].ImageIndex := img;
@@ -4061,8 +4096,6 @@ var
Proposal : TSynCompletionProposal;
Editor : TCustomSynEdit;
Queries : TWideStringList;
-const
- ItemPattern: WideString = '\image{%d}\hspace{5}\color{clSilver}%s\column{}\color{clWindowText}%s';
procedure addTable(Results: TMySQLQuery);
var ObjName, ObjType: WideString; Icon: Integer;
@@ -4077,10 +4110,11 @@ const
lntFunction: Icon := ICONINDEX_STOREDFUNCTION;
lntProcedure: Icon := ICONINDEX_STOREDPROCEDURE;
lntView: Icon := ICONINDEX_VIEW;
+ lntTrigger: Icon := ICONINDEX_TRIGGER;
else Icon := -1;
end;
Proposal.InsertList.Add( ObjName );
- Proposal.ItemList.Add( WideFormat(ItemPattern, [Icon, ObjType, ObjName]) );
+ Proposal.ItemList.Add( WideFormat(SYNCOMPLETION_PATTERN, [Icon, ObjType, ObjName]) );
end;
procedure addColumns( tablename: WideString );
@@ -4105,7 +4139,7 @@ const
end;
while not Columns.Eof do begin
Proposal.InsertList.Add(Columns.Col('Field'));
- Proposal.ItemList.Add(WideFormat(ItemPattern, [ICONINDEX_FIELD, GetFirstWord(Columns.Col('Type')), Columns.Col('Field')]) );
+ Proposal.ItemList.Add(WideFormat(SYNCOMPLETION_PATTERN, [ICONINDEX_FIELD, GetFirstWord(Columns.Col('Type')), Columns.Col('Field')]) );
Columns.Next;
end;
FreeAndNil(Columns);
@@ -4143,7 +4177,7 @@ begin
Results := Connection.GetResults('SHOW '+UpperCase(rx.Match[1])+' VARIABLES');
while not Results.Eof do begin
Proposal.InsertList.Add(Results.Col(0));
- Proposal.ItemList.Add(WideFormat(ItemPattern, [ICONINDEX_PRIMARYKEY, 'variable', Results.Col(0)+' \color{clSilver}= '+WideStringReplace(Results.Col(1), '\', '\\', [rfReplaceAll])] ) );
+ Proposal.ItemList.Add(WideFormat(SYNCOMPLETION_PATTERN, [ICONINDEX_PRIMARYKEY, 'variable', Results.Col(0)+' \color{clSilver}= '+WideStringReplace(Results.Col(1), '\', '\\', [rfReplaceAll])] ) );
Results.Next;
end;
except
@@ -4234,7 +4268,7 @@ begin
// Add databases
for i := 0 to Databases.Count - 1 do begin
Proposal.InsertList.Add(Databases[i]);
- Proposal.ItemList.Add(WideFormat(ItemPattern, [ICONINDEX_DB, 'database', Databases[i]]));
+ Proposal.ItemList.Add(WideFormat(SYNCOMPLETION_PATTERN, [ICONINDEX_DB, 'database', Databases[i]]));
end;
if ActiveDatabase <> '' then begin
@@ -4254,13 +4288,13 @@ begin
if MySqlFunctions[i].Version > Connection.ServerVersionInt then
continue;
Proposal.InsertList.Add( MySQLFunctions[i].Name + MySQLFunctions[i].Declaration );
- Proposal.ItemList.Add( WideFormat(ItemPattern, [ICONINDEX_FUNCTION, 'function', MySQLFunctions[i].Name + '\color{clSilver}' + MySQLFunctions[i].Declaration] ) );
+ Proposal.ItemList.Add( WideFormat(SYNCOMPLETION_PATTERN, [ICONINDEX_FUNCTION, 'function', MySQLFunctions[i].Name + '\color{clSilver}' + MySQLFunctions[i].Declaration] ) );
end;
// Add keywords
for i := 0 to MySQLKeywords.Count - 1 do begin
Proposal.InsertList.Add( MySQLKeywords[i] );
- Proposal.ItemList.Add( WideFormat(ItemPattern, [ICONINDEX_KEYWORD, 'keyword', MySQLKeywords[i]] ) );
+ Proposal.ItemList.Add( WideFormat(SYNCOMPLETION_PATTERN, [ICONINDEX_KEYWORD, 'keyword', MySQLKeywords[i]] ) );
end;
end;
@@ -6007,6 +6041,8 @@ begin
ImageIndex := ICONINDEX_STOREDPROCEDURE;
lntFunction:
ImageIndex := ICONINDEX_STOREDFUNCTION;
+ lntTrigger:
+ ImageIndex := ICONINDEX_TRIGGER;
end;
end;
end;
@@ -8049,6 +8085,15 @@ begin
end;
+procedure TMainForm.actCreateTriggerExecute(Sender: TObject);
+begin
+ tabEditor.TabVisible := True;
+ PagecontrolMain.ActivePage := tabEditor;
+ PlaceObjectEditor(lntTrigger);
+ TriggerEditor.Init;
+end;
+
+
procedure TMainForm.DataGridScroll(Sender: TBaseVirtualTree; DeltaX, DeltaY: Integer);
var
query: String;
@@ -8117,6 +8162,8 @@ begin
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, lntCrashedTable] then begin
if not Assigned(TableEditor) then
TableEditor := TfrmTableEditor.Create(tabEditor);
@@ -8129,6 +8176,10 @@ begin
if not Assigned(RoutineEditor) then
RoutineEditor := TfrmRoutineEditor.Create(tabEditor);
frm := RoutineEditor;
+ end else if Which = lntTrigger then begin
+ if not Assigned(TriggerEditor) then
+ TriggerEditor := TfrmTriggerEditor.Create(tabEditor);
+ frm := TriggerEditor;
end else
Exit;
frm.Parent := tabEditor;
@@ -8149,6 +8200,9 @@ begin
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;
@@ -8212,6 +8266,11 @@ begin
RoutineEditor.Init(SelectedTable.Text, RoutineType);
end;
+ lntTrigger: begin
+ PlaceObjectEditor(SelectedTable.NodeType);
+ TriggerEditor.Init(SelectedTable.Text);
+ end;
+
end;
end;
@@ -8824,6 +8883,8 @@ begin
Editors.Add(ViewEditor.SynMemoSelect);
if Assigned(RoutineEditor) then
Editors.Add(RoutineEditor.SynMemoBody);
+ if Assigned(TriggerEditor) then
+ Editors.Add(TriggerEditor.SynMemoStatement);
if Assigned(CreateDatabaseForm) then
Editors.Add(CreateDatabaseForm.SynMemoPreview);
if Assigned(OptionsForm) then
@@ -8843,10 +8904,16 @@ begin
Editor.Font.Size := FontSize;
Editor.Gutter.Font.Name := FontName;
Editor.Gutter.Font.Size := FontSize;
+ Editor.Gutter.AutoSize := BaseEditor.Gutter.AutoSize;
+ Editor.Gutter.DigitCount := BaseEditor.Gutter.DigitCount;
+ Editor.Gutter.LeftOffset := BaseEditor.Gutter.LeftOffset;
+ Editor.Gutter.RightOffset := BaseEditor.Gutter.RightOffset;
+ Editor.Gutter.ShowLineNumbers := BaseEditor.Gutter.ShowLineNumbers;
Editor.ActiveLineColor := ActiveLineColor;
Editor.Options := BaseEditor.Options;
Editor.TabWidth := TabWidth;
Editor.MaxScrollWidth := BaseEditor.MaxScrollWidth;
+ Editor.WantTabs := BaseEditor.WantTabs;
// Shortcuts
if Editor = BaseEditor then for j:=0 to Editor.Keystrokes.Count-1 do begin
KeyStroke := Editor.Keystrokes[j];
diff --git a/source/trigger_editor.dfm b/source/trigger_editor.dfm
new file mode 100644
index 00000000..4dbb759a
--- /dev/null
+++ b/source/trigger_editor.dfm
@@ -0,0 +1,160 @@
+object frmTriggerEditor: TfrmTriggerEditor
+ Left = 0
+ Top = 0
+ Width = 477
+ Height = 332
+ TabOrder = 0
+ DesignSize = (
+ 477
+ 332)
+ object lblName: TLabel
+ Left = 3
+ Top = 6
+ Width = 31
+ Height = 13
+ Caption = 'Name:'
+ FocusControl = editName
+ end
+ object lblTable: TLabel
+ Left = 3
+ Top = 33
+ Width = 45
+ Height = 13
+ Caption = 'On table:'
+ end
+ object lblBody: TLabel
+ Left = 3
+ Top = 87
+ Width = 327
+ Height = 13
+ Caption = 'Trigger statement: (e.g. "SET NEW.columnA = TRIM(OLD.columnA")'
+ end
+ object lblEvent: TLabel
+ Left = 3
+ Top = 59
+ Width = 32
+ Height = 13
+ Caption = 'Event:'
+ end
+ object editName: TTntEdit
+ Left = 96
+ Top = 3
+ Width = 378
+ Height = 21
+ Anchors = [akLeft, akTop, akRight]
+ TabOrder = 0
+ Text = 'editName'
+ OnChange = Modification
+ end
+ object SynMemoStatement: TSynMemo
+ Left = 3
+ Top = 106
+ Width = 471
+ Height = 192
+ SingleLineMode = False
+ Anchors = [akLeft, akTop, akRight, akBottom]
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -13
+ Font.Name = 'Courier New'
+ Font.Style = []
+ TabOrder = 2
+ Gutter.Font.Charset = DEFAULT_CHARSET
+ Gutter.Font.Color = clWindowText
+ Gutter.Font.Height = -11
+ Gutter.Font.Name = 'Courier New'
+ Gutter.Font.Style = []
+ Lines.UnicodeStrings = 'SynMemoStatement'
+ OnChange = Modification
+ end
+ object btnHelp: TButton
+ Left = 3
+ Top = 304
+ Width = 75
+ Height = 25
+ Anchors = [akLeft, akBottom]
+ Caption = 'Help'
+ TabOrder = 3
+ OnClick = btnHelpClick
+ end
+ object btnDiscard: TButton
+ Left = 84
+ Top = 304
+ Width = 75
+ Height = 25
+ Anchors = [akLeft, akBottom]
+ Caption = 'Discard'
+ TabOrder = 4
+ OnClick = btnDiscardClick
+ end
+ object btnSave: TButton
+ Left = 165
+ Top = 304
+ Width = 75
+ Height = 25
+ Anchors = [akLeft, akBottom]
+ Caption = 'Save'
+ Default = True
+ TabOrder = 5
+ OnClick = btnSaveClick
+ end
+ object comboTable: TTntComboBox
+ Left = 96
+ Top = 30
+ Width = 378
+ Height = 21
+ Style = csDropDownList
+ Anchors = [akLeft, akTop, akRight]
+ ItemHeight = 13
+ TabOrder = 1
+ OnChange = Modification
+ end
+ object comboTiming: TComboBox
+ Left = 96
+ Top = 56
+ Width = 145
+ Height = 21
+ Style = csDropDownList
+ ItemHeight = 13
+ TabOrder = 6
+ OnChange = Modification
+ end
+ object comboEvent: TComboBox
+ Left = 247
+ Top = 56
+ Width = 145
+ Height = 21
+ Style = csDropDownList
+ ItemHeight = 13
+ TabOrder = 7
+ OnChange = Modification
+ end
+ object SynCompletionProposalStatement: TSynCompletionProposal
+ Options = [scoLimitToMatchedText, scoUseInsertList, scoUsePrettyText, scoEndCharCompletion, scoCompleteWithTab, scoCompleteWithEnter]
+ EndOfTokenChr = '()[]. '
+ TriggerChars = '.'
+ Font.Charset = DEFAULT_CHARSET
+ Font.Color = clWindowText
+ Font.Height = -11
+ Font.Name = 'MS Sans Serif'
+ Font.Style = []
+ TitleFont.Charset = DEFAULT_CHARSET
+ TitleFont.Color = clBtnText
+ TitleFont.Height = -11
+ TitleFont.Name = 'MS Sans Serif'
+ TitleFont.Style = [fsBold]
+ Columns = <
+ item
+ BiggestWord = 'CONSTRUCTOR'
+ BiggestWordW = 'CONSTRUCTOR'
+ end>
+ Images = MainForm.PngImageListMain
+ OnExecute = SynCompletionProposalStatementExecute
+ ShortCut = 16416
+ Editor = SynMemoStatement
+ Left = 264
+ Top = 304
+ EndOfTokenChrW = '()[]. '
+ TriggerCharsW = '.'
+ end
+end
diff --git a/source/trigger_editor.pas b/source/trigger_editor.pas
new file mode 100644
index 00000000..315cec18
--- /dev/null
+++ b/source/trigger_editor.pas
@@ -0,0 +1,197 @@
+unit trigger_editor;
+
+interface
+
+uses
+ Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
+ Dialogs, StdCtrls, TntStdCtrls, SynEdit, SynMemo, ExtCtrls, mysql_connection, mysql_api,
+ SynCompletionProposal, VirtualTrees;
+
+type
+ TfrmTriggerEditor = class(TFrame)
+ lblName: TLabel;
+ editName: TTntEdit;
+ SynMemoStatement: TSynMemo;
+ btnHelp: TButton;
+ btnDiscard: TButton;
+ btnSave: TButton;
+ comboTable: TTntComboBox;
+ lblTable: TLabel;
+ lblBody: TLabel;
+ SynCompletionProposalStatement: TSynCompletionProposal;
+ lblEvent: TLabel;
+ comboTiming: TComboBox;
+ comboEvent: TComboBox;
+ procedure btnHelpClick(Sender: TObject);
+ procedure btnDiscardClick(Sender: TObject);
+ procedure Modification(Sender: TObject);
+ procedure btnSaveClick(Sender: TObject);
+ procedure SynCompletionProposalStatementExecute(Kind: SynCompletionType; Sender: TObject;
+ var CurrentInput: WideString; var x, y: Integer; var CanExecute: Boolean);
+ private
+ { Private declarations }
+ FEditTriggerName: WideString;
+ public
+ { Public declarations }
+ constructor Create(AOwner: TComponent); override;
+ procedure Init(EditTriggerName: WideString='');
+ end;
+
+implementation
+
+uses main, helpers;
+
+{$R *.dfm}
+
+
+{**
+ Create: Restore GUI setup
+}
+constructor TfrmTriggerEditor.Create(AOwner: TComponent);
+var
+ col: TProposalColumn;
+ i: Integer;
+begin
+ inherited Create(AOwner);
+ Align := alClient;
+ SynMemoStatement.Highlighter := Mainform.SynSQLSyn1;
+ InheritFont(Font);
+ editName.MaxLength := NAME_LEN;
+ comboTiming.Items.Text := 'BEFORE'+CRLF+'AFTER';
+ comboEvent.Items.Text := 'INSERT'+CRLF+'UPDATE'+CRLF+'DELETE';
+ for i:=0 to Mainform.SynCompletionProposal.Columns.Count-1 do begin
+ col := SynCompletionProposalStatement.Columns.Add;
+ col.BiggestWord := Mainform.SynCompletionProposal.Columns[i].BiggestWord;
+ end;
+ SynCompletionProposalStatement.NbLinesInWindow := Mainform.SynCompletionProposal.NbLinesInWindow;
+ SynCompletionProposalStatement.Width := Mainform.SynCompletionProposal.Width;
+ SynCompletionProposalStatement.Options := Mainform.SynCompletionProposal.Options;
+ SynCompletionProposalStatement.TimerInterval := Mainform.SynCompletionProposal.TimerInterval;
+ SynCompletionProposalStatement.ItemHeight := Mainform.SynCompletionProposal.ItemHeight;
+ SynCompletionProposalStatement.Margin := Mainform.SynCompletionProposal.Margin;
+ SynCompletionProposalStatement.Font := Font;
+end;
+
+
+procedure TfrmTriggerEditor.Init(EditTriggerName: WideString='');
+var
+ Definition, TableList: TMySQLQuery;
+begin
+ Mainform.SetupSynEditors;
+ FEditTriggerName := EditTriggerName;
+ editName.Text := '';
+ SynMemoStatement.Text := '';
+ comboEvent.ItemIndex := 0;
+ comboTiming.ItemIndex := 0;
+ TableList := Mainform.FetchActiveDbTableList;
+ comboTable.Items.Clear;
+ while not TableList.Eof do begin
+ if GetDBObjectType(TableList) in [lntTable, lntCrashedTable] then
+ comboTable.Items.Add(TableList.Col(DBO_NAME));
+ TableList.Next;
+ end;
+ if comboTable.Items.Count > 0 then
+ comboTable.ItemIndex := 0;
+ if FEditTriggerName <> '' then begin
+ // Edit mode
+ Mainform.SetEditorTabCaption(Self, FEditTriggerName);
+ editName.Text := FEditTriggerName;
+ Definition := Mainform.Connection.GetResults('SELECT '+
+ 'EVENT_MANIPULATION, EVENT_OBJECT_TABLE, ACTION_STATEMENT, ACTION_TIMING '+
+ 'FROM information_schema.TRIGGERS '+
+ 'WHERE TRIGGER_SCHEMA='+esc(Mainform.ActiveDatabase)+' AND TRIGGER_NAME='+esc(FEditTriggerName));
+ comboTable.ItemIndex := comboTable.Items.IndexOf(Definition.Col('EVENT_OBJECT_TABLE'));
+ comboTiming.ItemIndex := comboTiming.Items.IndexOf(UpperCase(Definition.Col('ACTION_TIMING')));
+ comboEvent.ItemIndex := comboEvent.Items.IndexOf(UpperCase(Definition.Col('EVENT_MANIPULATION')));
+ SynMemoStatement.Text := Definition.Col('ACTION_STATEMENT');
+ end else begin
+ Mainform.SetEditorTabCaption(Self, '');
+ editName.Text := 'Enter trigger name';
+ end;
+ btnSave.Enabled := False;
+ btnDiscard.Enabled := False;
+end;
+
+
+procedure TfrmTriggerEditor.Modification(Sender: TObject);
+begin
+ // Enable buttons if anything has changed
+ btnSave.Enabled := (editName.Text <> '') and (comboTable.ItemIndex > -1)
+ and (comboTiming.ItemIndex > -1) and (comboEvent.ItemIndex > -1)
+ and (SynMemoStatement.Text <> '');
+ btnDiscard.Enabled := True;
+end;
+
+
+procedure TfrmTriggerEditor.btnDiscardClick(Sender: TObject);
+begin
+ // Reinit editor, discarding changes
+ Init(FEditTriggerName);
+end;
+
+
+procedure TfrmTriggerEditor.btnSaveClick(Sender: TObject);
+var
+ sql: WideString;
+ FocusChangeEvent: procedure(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex) of object;
+begin
+ // Edit mode means we drop the trigger and recreate it, as there is no ALTER TRIGGER.
+ try
+ if FEditTriggerName <> '' then
+ Mainform.Connection.Query('DROP TRIGGER '+Mainform.mask(FEditTriggerName));
+ // CREATE
+ // [DEFINER = { user | CURRENT_USER }]
+ // TRIGGER trigger_name trigger_time trigger_event
+ // ON tbl_name FOR EACH ROW trigger_stmt
+ sql := 'CREATE TRIGGER '+Mainform.mask(editName.Text)+' '+
+ comboTiming.Items[comboTiming.ItemIndex]+' '+comboEvent.Items[comboEvent.ItemIndex]+
+ ' ON '+Mainform.mask(comboTable.Text)+
+ ' FOR EACH ROW '+SynMemoStatement.Text;
+ Mainform.Connection.Query(sql);
+ FocusChangeEvent := Mainform.DBtree.OnFocusChanged;
+ Mainform.DBtree.OnFocusChanged := nil;
+ Mainform.RefreshTreeDB(Mainform.ActiveDatabase);
+ Mainform.DBtree.OnFocusChanged := FocusChangeEvent;
+ Mainform.SelectDBObject(editName.Text, lntTrigger);
+ Init(editName.Text);
+ except on E:Exception do
+ MessageDlg(E.Message, mtError, [mbOK], 0);
+ end;
+end;
+
+
+procedure TfrmTriggerEditor.SynCompletionProposalStatementExecute(Kind: SynCompletionType; Sender: TObject;
+ var CurrentInput: WideString; var x, y: Integer; var CanExecute: Boolean);
+var
+ Proposal: TSynCompletionProposal;
+ Token: WideString;
+ Columns: TMySQLQuery;
+begin
+ // Propose column names from referencing table
+ Proposal := Sender as TSynCompletionProposal;
+ Token := UpperCase(Proposal.PreviousToken);
+ Proposal.InsertList.Clear;
+ Proposal.ItemList.Clear;
+ if (Token = 'NEW') or (Token = 'OLD') then begin
+ if comboTable.Text = '' then
+ CanExecute := False
+ else try
+ Columns := Mainform.Connection.GetResults('SHOW COLUMNS FROM '+Mainform.mask(comboTable.Text));
+ while not Columns.Eof do begin
+ Proposal.InsertList.Add(Columns.Col('Field'));
+ Proposal.ItemList.Add(WideFormat(SYNCOMPLETION_PATTERN, [ICONINDEX_FIELD, GetFirstWord(Columns.Col('Type')), Columns.Col('Field')]) );
+ Columns.Next;
+ end;
+ except
+ end;
+ end else
+ Mainform.SynCompletionProposalExecute(Kind, Sender, CurrentInput, x, y, CanExecute);
+end;
+
+
+procedure TfrmTriggerEditor.btnHelpClick(Sender: TObject);
+begin
+ Mainform.CallSQLHelpWithKeyword('TRIGGERS');
+end;
+
+end.