SQL export: Add popup menu action for copying mysqldump command line

This commit is contained in:
Ansgar Becker
2021-06-25 08:56:18 +02:00
parent ee69a049fd
commit ed28bcbf6f
11 changed files with 158 additions and 55 deletions

View File

@ -7,7 +7,7 @@ msgid ""
msgstr ""
"Project-Id-Version: HeidiSQL\n"
"POT-Creation-Date: 2012-11-05 21:40\n"
"PO-Revision-Date: 2021-06-06 17:21+0200\n"
"PO-Revision-Date: 2021-06-25 08:53+0200\n"
"Last-Translator: Ansgar Becker <anse@heidisql.com>\n"
"Language-Team: English (http://www.transifex.com/projects/p/heidisql/language/en/)\n"
"MIME-Version: 1.0\n"
@ -6690,3 +6690,6 @@ msgstr "Close all query tabs"
msgid "Close query tabs to the right"
msgstr "Close query tabs to the right"
msgid "Copy mysqldump command"
msgstr "Copy mysqldump command"

View File

@ -47,7 +47,8 @@ uses
Vcl.Styles,
Vcl.Graphics,
theme_preview in '..\..\source\theme_preview.pas' {frmThemePreview},
csv_detector in '..\..\source\csv_detector.pas' {frmCsvDetector};
csv_detector in '..\..\source\csv_detector.pas' {frmCsvDetector},
generic_types in '..\..\source\generic_types.pas';
{.$R *.RES}
{$R ..\..\res\icon.RES}

View File

@ -7,7 +7,7 @@
<TargetedPlatforms>3</TargetedPlatforms>
<AppType>Application</AppType>
<FrameworkType>VCL</FrameworkType>
<ProjectVersion>19.1</ProjectVersion>
<ProjectVersion>19.2</ProjectVersion>
<Platform Condition="'$(Platform)'==''">Win64</Platform>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
@ -238,6 +238,7 @@
<Form>frmCsvDetector</Form>
<FormType>dfm</FormType>
</DCCReference>
<DCCReference Include="..\..\source\generic_types.pas"/>
<BuildConfiguration Include="Debug">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>

View File

@ -8,7 +8,7 @@ interface
uses
Windows, Classes, Graphics, Forms, Controls, StdCtrls, ExtCtrls, SysUtils, ComCtrls, pngimage, gnugettext,
Dialogs, SynRegExpr, Vcl.Menus, ClipBrd, extra_controls;
Dialogs, SynRegExpr, Vcl.Menus, ClipBrd, extra_controls, generic_types;
type
TAboutBox = class(TExtForm)

View File

@ -383,6 +383,7 @@ type
function SynCompletionProposalPrettyText(ImageIndex: Integer; LeftText, CenterText, RightText: String; LeftColor: TColor=-1; CenterColor: TColor=-1; RightColor: TColor=-1): String;
function PopupComponent(Sender: TObject): TComponent;
function IsWine: Boolean;
function DirSep: Char;
var
AppSettings: TAppSettings;
@ -2932,6 +2933,14 @@ begin
end;
function DirSep: Char;
begin
if IsWine then
Result := '/'
else
Result := '\';
end;
{ Threading stuff }

View File

@ -5,7 +5,7 @@ interface
uses
Classes, SysUtils, windows, dbstructures, SynRegExpr, Generics.Collections, Generics.Defaults,
DateUtils, Types, Math, Dialogs, ADODB, DB, DBCommon, ComObj, Graphics, ExtCtrls, StrUtils,
gnugettext, AnsiStrings, Controls, Forms, System.IOUtils;
gnugettext, AnsiStrings, Controls, Forms, System.IOUtils, generic_types;
type
@ -323,7 +323,7 @@ type
function DefaultPort: Integer;
function DefaultUsername: String;
function DefaultIgnoreDatabasePattern: String;
function GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: Boolean): String;
function GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: TThreeStateBoolean): String;
published
property IsFolder: Boolean read FIsFolder write FIsFolder;
property NetType: TNetType read FNetType write FNetType;
@ -1723,7 +1723,7 @@ begin
end;
function TConnectionParameters.GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: Boolean): String;
function TConnectionParameters.GetExternalCliArguments(Connection: TDBConnection; ReplacePassword: TThreeStateBoolean): String;
var
Args: TStringList;
begin
@ -1756,14 +1756,15 @@ begin
Args.Add('--user="'+Username+'"');
if Password <> '' then begin
if ReplacePassword then
Args.Add('--password="***"')
else
Args.Add('--password="'+StringReplace(Password, '"', '\"', [rfReplaceAll])+'"');
case ReplacePassword of
nbTrue: Args.Add('--password="***"');
nbFalse: Args.Add('--password="'+StringReplace(Password, '"', '\"', [rfReplaceAll])+'"');
nbUnset: Args.Add('--password'); // will prompt
end;
end;
if Compressed then
Args.Add('--compress');
if Connection.Database <> '' then
if Assigned(Connection) and (Connection.Database <> '') then
Args.Add('--database="' + Connection.Database + '"');
Result := ' ' + Implode(' ', Args);

11
source/generic_types.pas Normal file
View File

@ -0,0 +1,11 @@
unit generic_types;
interface
type
TThreeStateBoolean = (nbUnset, nbFalse, nbTrue);
implementation
end.

View File

@ -20,7 +20,7 @@ uses
JumpList, System.Actions, System.UITypes, pngimage,
System.ImageList, Vcl.Styles.UxTheme, Vcl.Styles.Utils.Menus, Vcl.Styles.Utils.Forms,
Vcl.VirtualImageList, Vcl.BaseImageCollection, Vcl.ImageCollection, System.IniFiles, extra_controls,
SynEditCodeFolding, texteditor, System.Character;
SynEditCodeFolding, texteditor, System.Character, generic_types;
type
@ -156,8 +156,6 @@ type
function Compare(const Left, Right: TQueryHistoryItem): Integer; override;
end;
TThreeStateBoolean = (nbUnset, nbFalse, nbTrue);
ITaskbarList = interface(IUnknown)
[SID_ITaskbarList]
function HrInit: HRESULT; stdcall;
@ -3855,10 +3853,10 @@ begin
cmd := '$TERM';
end;
log := path + cmd + p + Conn.Parameters.GetExternalCliArguments(Conn, True);
log := path + cmd + p + Conn.Parameters.GetExternalCliArguments(Conn, nbTrue);
LogSQL(f_('Launching command line: %s', [log]), lcInfo);
p := p + Conn.Parameters.GetExternalCliArguments(Conn, False);
p := p + Conn.Parameters.GetExternalCliArguments(Conn, nbFalse);
ShellExec(cmd, path, p);
end;
end;

View File

@ -697,5 +697,9 @@ object frmTableTools: TfrmTableTools
AutoCheck = True
Caption = 'Remove DEFINER clauses'
end
object menuCopyMysqldumpCommand: TMenuItem
Caption = 'Copy mysqldump command'
OnClick = menuCopyMysqldumpCommandClick
end
end
end

View File

@ -12,7 +12,7 @@ uses
Windows, SysUtils, Classes, Controls, Forms, StdCtrls, ComCtrls, Buttons, Dialogs, StdActns,
VirtualTrees, ExtCtrls, Graphics, SynRegExpr, Math, Generics.Collections, extra_controls,
dbconnection, apphelpers, Menus, gnugettext, DateUtils, System.Zip, System.UITypes, StrUtils, Messages,
SynEdit, SynMemo;
SynEdit, SynMemo, ClipBrd, generic_types;
type
TToolMode = (tmMaintenance, tmFind, tmSQLExport, tmBulkTableEdit);
@ -88,9 +88,11 @@ type
tabSQL: TTabSheet;
memoFindText: TMemo;
SynMemoFindText: TSynMemo;
menuCopyMysqldumpCommand: TMenuItem;
procedure FormCreate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure btnHelpMaintenanceClick(Sender: TObject);
function GetCheckedObjects(DBNode: PVirtualNode): TDBObjectList;
procedure TreeObjectsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType; var CellText: String);
procedure TreeObjectsInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
@ -133,6 +135,7 @@ type
procedure CheckAllClick(Sender: TObject);
procedure TreeObjectsExpanded(Sender: TBaseVirtualTree; Node: PVirtualNode);
procedure btnExportOptionsClick(Sender: TObject);
procedure menuCopyMysqldumpCommandClick(Sender: TObject);
const
StatusMsg = '%s %s ...';
private
@ -240,6 +243,7 @@ begin
OUTPUT_DIR := _('Directory - one file per object in database subdirectories');
OUTPUT_DB := _('Database');
OUTPUT_SERVER := _('Server')+': ';
// Todo: sanitize misleading names
DATA_NO := _('No data');
DATA_REPLACE := _('Delete + insert (truncate existing data)');
DATA_INSERT := _('Insert');
@ -379,6 +383,75 @@ begin
end;
procedure TfrmTableTools.menuCopyMysqldumpCommandClick(Sender: TObject);
var
BinPath, ConnectionArguments, FullCommand: String;
Arguments, DatabaseNames: TStringList;
Conn: TDBConnection;
SessionNode, DBNode: PVirtualNode;
DBObj: PDBObject;
begin
// Copy command line for use with mysqldump
Screen.Cursor := crHourGlass;
Conn := MainForm.ActiveConnection;
BinPath := AppSettings.ReadString(asMySQLBinaries);
if (not BinPath.IsEmpty) and (BinPath[Length(BinPath)] <> DirSep) then
BinPath := BinPath + DirSep;
BinPath := BinPath + IfThen(IsWine, 'mysqldump', 'mysqldump.exe');
ConnectionArguments := Conn.Parameters.GetExternalCliArguments(nil, nbUnset);
Arguments := TStringList.Create;
if chkExportDatabasesDrop.Checked then
Arguments.Add('--add-drop-database');
if not chkExportDatabasesCreate.Checked then
Arguments.Add('--no-create-db');
if chkExportTablesDrop.Checked then
Arguments.Add('--add-drop-table');
if not chkExportTablesCreate.Checked then
Arguments.Add('--no-create-info');
// Data output. No support for delete+insert - will just use inserts.
if comboExportData.Text = DATA_NO then
Arguments.Add('--no-data')
else if comboExportData.Text = DATA_UPDATE then
Arguments.Add('--replace')
else if comboExportData.Text = DATA_INSERTNEW then
Arguments.Add('--insert-ignore');
// Output file. No support for server, database and clipboard
if comboExportOutputType.Text = OUTPUT_FILE then
Arguments.Add('--result-file="'+comboExportOutputTarget.Text+'"')
else if comboExportOutputType.Text = OUTPUT_DIR then
Arguments.Add('--tab="'+comboExportOutputTarget.Text+'"');
// Use checked database names
DatabaseNames := TStringList.Create;
SessionNode := TreeObjects.GetFirstChild(nil);
while Assigned(SessionNode) do begin
DBNode := TreeObjects.GetFirstChild(SessionNode);
while Assigned(DBNode) do begin
if not (DBNode.CheckState in [csUncheckedNormal, csUncheckedPressed]) then begin
DBObj := TreeObjects.GetNodeData(DBNode);
DatabaseNames.Add(DBObj.Database);
// Todo: loop through tables?
// CheckedObjects := GetCheckedObjects(DBNode);
end;
DBNode := TreeObjects.GetNextSibling(DBNode);
end;
SessionNode := TreeObjects.GetNextSibling(SessionNode);
end;
Arguments.Add('--databases ' + Implode(' ', DatabaseNames));
DatabaseNames.Free;
FullCommand := BinPath + ConnectionArguments + ' ' + Implode(' ', Arguments);
Arguments.Free;
Clipboard.AsText := FullCommand;
Screen.Cursor := crDefault;
end;
procedure TfrmTableTools.FormClose(Sender: TObject; var Action: TCloseAction);
begin
// Auto close temorary connection
@ -638,6 +711,43 @@ begin
end;
function TfrmTableTools.GetCheckedObjects(DBNode: PVirtualNode): TDBObjectList;
var
Child, GrandChild: PVirtualNode;
ChildObj, GrandChildObj: PDBObject;
begin
// Return list with checked objects from database node
// The caller doesn't need to care whether type grouping in tree is activated
Result := TDBObjectList.Create(False);
Child := TreeObjects.GetFirstChild(DBNode);
while Assigned(Child) do begin
if Child.CheckState in CheckedStates then begin
ChildObj := TreeObjects.GetNodeData(Child);
case ChildObj.NodeType of
lntGroup: begin
GrandChild := TreeObjects.GetFirstChild(Child);
while Assigned(GrandChild) do begin
if GrandChild.CheckState in CheckedStates then begin
GrandChildObj := TreeObjects.GetNodeData(GrandChild);
Result.Add(GrandChildObj^);
end;
GrandChild := TreeObjects.GetNextSibling(GrandChild);
end;
end
else begin
Result.Add(ChildObj^);
end;
end;
end;
Child := TreeObjects.GetNextSibling(Child);
end;
end;
procedure TfrmTableTools.Execute(Sender: TObject);
var
SessionNode, DBNode: PVirtualNode;
@ -678,40 +788,6 @@ var
end;
end;
procedure SetCheckedObjects(DBNode: PVirtualNode);
var
Child, GrandChild: PVirtualNode;
ChildObj, GrandChildObj: PDBObject;
begin
CheckedObjects.Clear;
Child := TreeObjects.GetFirstChild(DBNode);
while Assigned(Child) do begin
if Child.CheckState in CheckedStates then begin
ChildObj := TreeObjects.GetNodeData(Child);
case ChildObj.NodeType of
lntGroup: begin
GrandChild := TreeObjects.GetFirstChild(Child);
while Assigned(GrandChild) do begin
if GrandChild.CheckState in CheckedStates then begin
GrandChildObj := TreeObjects.GetNodeData(GrandChild);
CheckedObjects.Add(GrandChildObj^);
end;
GrandChild := TreeObjects.GetNextSibling(GrandChild);
end;
end
else begin
CheckedObjects.Add(ChildObj^);
end;
end;
end;
Child := TreeObjects.GetNextSibling(Child);
end;
end;
begin
Screen.Cursor := crHourGlass;
// Disable critical controls so ProcessMessages is unable to do things while export is in progress
@ -731,7 +807,6 @@ begin
ResultGrid.Clear;
FResults.Clear;
FFindSeeResultSQL.Clear;
CheckedObjects := TDBObjectList.Create(False);
Triggers := TDBObjectList.Create(False); // False, so we can .Free that object afterwards without loosing the contained objects
Views := TDBObjectList.Create(False);
FHeaderCreated := False;
@ -750,7 +825,7 @@ begin
Triggers.Clear;
Views.Clear;
FSecondExportPass := False;
SetCheckedObjects(DBNode);
CheckedObjects := GetCheckedObjects(DBNode);
for DBObj in CheckedObjects do begin
// Triggers have to be exported at the very end
if (FToolMode = tmSQLExport) and (DBObj.NodeType = lntTrigger) then

View File

@ -5,7 +5,7 @@ interface
uses
Windows, Messages, SysUtils, Classes, Forms, StdCtrls, IniFiles, Controls, Graphics,
apphelpers, gnugettext, ExtCtrls, extra_controls, System.StrUtils, Vcl.Dialogs,
Vcl.Menus, Vcl.Clipbrd;
Vcl.Menus, Vcl.Clipbrd, generic_types;
type
TfrmUpdateCheck = class(TExtForm)