mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
Implement handling of triggers as separate database objects, on the same level as tables, routines and views. Means we have a trigger editor frame, a new icon and various code extensions. Fixes issue #806.
This commit is contained in:
@ -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}
|
||||
|
@ -180,6 +180,9 @@
|
||||
<DCCReference Include="..\..\source\texteditor.pas">
|
||||
<Form>frmTextEditor</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\trigger_editor.pas">
|
||||
<Form>frmTriggerEditor</Form>
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\source\updatecheck.pas">
|
||||
<Form>frmUpdateCheck</Form>
|
||||
</DCCReference>
|
||||
|
BIN
res/icons/cog.png
Normal file
BIN
res/icons/cog.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 512 B |
@ -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';
|
||||
|
||||
|
@ -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
|
||||
|
@ -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 = '-'
|
||||
|
@ -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];
|
||||
|
160
source/trigger_editor.dfm
Normal file
160
source/trigger_editor.dfm
Normal file
@ -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
|
197
source/trigger_editor.pas
Normal file
197
source/trigger_editor.pas
Normal file
@ -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.
|
Reference in New Issue
Block a user