mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-14 01:56:36 +08:00

* Make export table locks local to current connection work. * Bugfix: In non-file mode, export commands go directly to server without being parsed; thus they must not have semicolons at end of sentence. A regression here causes issue #1747558 and issue #1795486, which this commit fixes again. (Briefly considered adding a cleanSql() which just runs result := parseSql(sql)[0], which would do the same in fewer lines of code, albeit with the small overhead of having the semicolon both added and afterwards removed again..)
1461 lines
50 KiB
ObjectPascal
1461 lines
50 KiB
ObjectPascal
unit exportsql;
|
|
|
|
|
|
// -------------------------------------
|
|
// Export Tables
|
|
// -------------------------------------
|
|
|
|
|
|
interface
|
|
|
|
uses
|
|
Threading,
|
|
Windows,
|
|
Messages,
|
|
SysUtils,
|
|
Classes,
|
|
Graphics,
|
|
Controls,
|
|
Forms,
|
|
Dialogs,
|
|
StdCtrls,
|
|
ExtCtrls,
|
|
CheckLst,
|
|
Buttons,
|
|
comctrls,
|
|
Registry,
|
|
ToolWin,
|
|
DB,
|
|
SynEdit,
|
|
SynMemo,
|
|
ZDataSet;
|
|
|
|
type
|
|
TExportSQLForm = class(TForm)
|
|
btnExport: TButton;
|
|
btnCancel: TButton;
|
|
dialogSave: TSaveDialog;
|
|
barProgress: TProgressBar;
|
|
lblProgress: TLabel;
|
|
pageControl1: TPageControl;
|
|
TabSheet1: TTabSheet;
|
|
TabSheet2: TTabSheet;
|
|
lblSelectDbTables: TLabel;
|
|
checkListTables: TCheckListBox;
|
|
comboSelectDatabase: TComboBox;
|
|
toolbarSelectTools: TToolBar;
|
|
ToolButton1: TToolButton;
|
|
ToolButton2: TToolButton;
|
|
groupOutput: TGroupBox;
|
|
btnFileBrowse: TBitBtn;
|
|
editFileName: TEdit;
|
|
radioOtherDatabase: TRadioButton;
|
|
radioFile: TRadioButton;
|
|
comboOtherDatabase: TComboBox;
|
|
radioOtherHost: TRadioButton;
|
|
comboOtherHost: TComboBox;
|
|
comboOtherHostDatabase: TComboBox;
|
|
groupExampleSql: TGroupBox;
|
|
SynMemoExampleSQL: TSynMemo;
|
|
groupOptions: TGroupBox;
|
|
lblTargetCompat: TLabel;
|
|
cbxStructure: TCheckBox;
|
|
cbxDatabase: TCheckBox;
|
|
comboDatabase: TComboBox;
|
|
cbxTables: TCheckBox;
|
|
comboTables: TComboBox;
|
|
cbxData: TCheckBox;
|
|
comboData: TComboBox;
|
|
comboTargetCompat: TComboBox;
|
|
procedure comboTargetCompatChange(Sender: TObject);
|
|
procedure comboOtherHostSelect(Sender: TObject);
|
|
procedure comboDataChange(Sender: TObject);
|
|
procedure comboTablesChange(Sender: TObject);
|
|
procedure comboDatabaseChange(Sender: TObject);
|
|
procedure cbxTablesClick(Sender: TObject);
|
|
procedure cbxDatabaseClick(Sender: TObject);
|
|
procedure btnCancelClick(Sender: TObject);
|
|
procedure FormShow(Sender: TObject);
|
|
procedure comboSelectDatabaseChange(Sender: TObject);
|
|
procedure CheckListToggle(Sender: TObject);
|
|
procedure btnFileBrowseClick(Sender: TObject);
|
|
procedure btnExportClick(Sender: TObject);
|
|
procedure radioOtherDatabaseClick(Sender: TObject);
|
|
procedure radioFileClick(Sender: TObject);
|
|
procedure fillcombo_anotherdb(Sender: TObject);
|
|
procedure generateExampleSQL;
|
|
procedure validateRadioControls(Sender: TObject);
|
|
procedure validateControls(Sender: TObject);
|
|
procedure cbxStructureClick(Sender: TObject);
|
|
procedure radioOtherHostClick(Sender: TObject);
|
|
procedure cbxDataClick(Sender: TObject);
|
|
procedure checkListTablesKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
procedure SaveSettings;
|
|
private
|
|
{ Private declarations }
|
|
public
|
|
{ Public declarations }
|
|
end;
|
|
|
|
function ExportTablesWindow (AOwner : TComponent; Flags : String = '') : Boolean;
|
|
|
|
{$I const.inc}
|
|
|
|
implementation
|
|
|
|
uses
|
|
Main,
|
|
Childwin,
|
|
Helpers,
|
|
Synchronization,
|
|
Communication;
|
|
|
|
{$R *.DFM}
|
|
|
|
const
|
|
// Order of items in combo box: comboDatabase
|
|
DB_DROP_CREATE = 0;
|
|
DB_CREATE = 1;
|
|
DB_CREATE_IGNORE = 2;
|
|
// Order of items in combo box: comboTables
|
|
TAB_DROP_CREATE = 0;
|
|
TAB_CREATE = 1;
|
|
TAB_CREATE_IGNORE = 2;
|
|
// Order of items in combo box: comboData
|
|
DATA_TRUNCATE_INSERT = 0;
|
|
DATA_INSERT = 1;
|
|
DATA_INSERT_IGNORE = 2;
|
|
DATA_REPLACE_INTO = 3;
|
|
// Order of radiobutton group "Output"
|
|
OUTPUT_FILE = 1;
|
|
OUTPUT_DB = 2;
|
|
OUTPUT_HOST = 3;
|
|
|
|
// Default output compatibility
|
|
SQL_VERSION_DEFAULT = SQL_VERSION_ANSI;
|
|
|
|
var
|
|
appHandles: array of THandle;
|
|
cancelDialog: TForm = nil;
|
|
remote_version: integer;
|
|
remote_max_allowed_packet : Int64;
|
|
target_versions : TStringList;
|
|
|
|
function ExportTablesWindow (AOwner : TComponent; Flags : String = '') : Boolean;
|
|
var
|
|
f : TExportSQLForm;
|
|
begin
|
|
f := TExportSQLForm.Create(AOwner);
|
|
// todo: pass params if needed
|
|
Result := (f.ShowModal = mrOK);
|
|
FreeAndNil (f);
|
|
end;
|
|
|
|
procedure TExportSQLForm.btnCancelClick(Sender: TObject);
|
|
begin
|
|
close;
|
|
end;
|
|
|
|
procedure TExportSQLForm.FormShow(Sender: TObject);
|
|
var
|
|
tn : TTreeNode;
|
|
i, OutputTo : Integer;
|
|
dbtree_db : String;
|
|
list: TWindowDataArray;
|
|
begin
|
|
barProgress.Position := 0;
|
|
lblProgress.Caption := '';
|
|
PageControl1.ActivePageIndex := 0;
|
|
SynMemoExampleSQL.Highlighter := Mainform.ChildWin.SynSQLSyn1;
|
|
SynMemoExampleSQL.Font := Mainform.ChildWin.SynMemoQuery.Font;
|
|
|
|
// read dbs and Tables from treeview
|
|
comboSelectDatabase.Items.Clear;
|
|
Caption := Mainform.ChildWin.MysqlConn.Description + ' - Export Tables...';
|
|
for i:=0 to Mainform.ChildWin.DBTree.Items.Count-1 do
|
|
begin
|
|
tn := Mainform.ChildWin.DBTree.Items[i];
|
|
if tn.Level = 1 then
|
|
comboSelectDatabase.Items.Add(tn.Text);
|
|
end;
|
|
|
|
if Mainform.ChildWin.DBRightClickSelectedItem <> nil then
|
|
begin
|
|
case Mainform.ChildWin.DBRightClickSelectedItem.Level of
|
|
1 : dbtree_db := Mainform.ChildWin.DBRightClickSelectedItem.Text;
|
|
2 : dbtree_db := Mainform.ChildWin.DBRightClickSelectedItem.Parent.Text;
|
|
3 : dbtree_db := Mainform.ChildWin.DBRightClickSelectedItem.Parent.Parent.Text;
|
|
end;
|
|
end;
|
|
|
|
for i:=0 to comboSelectDatabase.Items.Count-1 do
|
|
begin
|
|
if ((dbtree_db = '') and (comboSelectDatabase.Items[i] = Mainform.ChildWin.ActiveDatabase))
|
|
or ((dbtree_db <> '') and (comboSelectDatabase.Items[i] = dbtree_db)) then
|
|
begin
|
|
comboSelectDatabase.ItemIndex := i;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
if comboSelectDatabase.ItemIndex = -1 then
|
|
comboSelectDatabase.ItemIndex := 0;
|
|
|
|
comboSelectDatabaseChange(self);
|
|
|
|
// Initialize and fill list with target versions
|
|
target_versions := TStringList.Create;
|
|
with target_versions do
|
|
begin
|
|
Add( IntToStr( SQL_VERSION_ANSI ) + '=Standard ANSI SQL' );
|
|
Add( '32300=MySQL 3.23' );
|
|
Add( '40000=MySQL 4.0' );
|
|
Add( '40100=MySQL 4.1' );
|
|
Add( '50000=MySQL 5.0' );
|
|
Add( '50100=MySQL 5.1' );
|
|
Add( IntToStr( Mainform.ChildWin.mysql_version ) + '=Same as source server (MySQL '+Mainform.ChildWin.GetVar('SELECT VERSION()') +')' );
|
|
end;
|
|
|
|
// Add all target versions to combobox and set default option
|
|
comboTargetCompat.Items.Clear;
|
|
for i := 0 to target_versions.Count - 1 do
|
|
begin
|
|
comboTargetCompat.Items.Add( target_versions.ValueFromIndex[i] );
|
|
if( target_versions.Names[i] = IntToStr( SQL_VERSION_DEFAULT ) ) then
|
|
begin
|
|
comboTargetCompat.ItemIndex := i;
|
|
end;
|
|
end;
|
|
|
|
// Read options
|
|
with TRegistry.Create do
|
|
if OpenKey(REGPATH, true) then begin
|
|
// WithUseDB, UseBackticks, CompleteInserts: deprecated (hardcoded true now)
|
|
if Valueexists('ExportStructure') then cbxStructure.Checked := ReadBool('ExportStructure');
|
|
if Valueexists('WithCreateDatabase') then cbxDatabase.Checked := ReadBool('WithCreateDatabase');
|
|
if Valueexists('WithCreateTable') then cbxTables.Checked := ReadBool('WithCreateTable');
|
|
if Valueexists('ExportData') then cbxData.Checked := ReadBool('ExportData');
|
|
if Valueexists('CreateDatabaseHow') then comboDatabase.ItemIndex := ReadInteger('CreateDatabaseHow');
|
|
if Valueexists('CreateTablesHow') then comboTables.ItemIndex := ReadInteger('CreateTablesHow')
|
|
else if Valueexists('WithDropTable') and ReadBool('WithDropTable') then comboTables.ItemIndex := TAB_DROP_CREATE;
|
|
if Valueexists('CreateDataHow') then comboData.ItemIndex := ReadInteger('CreateDataHow');
|
|
if Valueexists('Compatibility') then comboTargetCompat.ItemIndex := ReadInteger('Compatibility');
|
|
if Valueexists('exportfilename') then editFileName.Text := ReadString('exportfilename');
|
|
if Valueexists('ExportSQL_OutputTo') then
|
|
begin
|
|
OutputTo := ReadInteger('ExportSQL_OutputTo');
|
|
|
|
{***
|
|
@note ansgarbecker, 2007-02-24
|
|
If OutputTo is now OUTPUT_HOST and there are no other windows
|
|
to export to, reset OutputTo to OUTPUT_FILE to avoid the error-popup
|
|
"You need at least 2 windows...", which should not be fired in
|
|
FormShow rather than only when the user has really clicked that
|
|
radiobutton.
|
|
As a benefit, the OUTPUT_FILE won't be saved to registry here
|
|
so the OUTPUT_HOST is still enabled in registry and will be used
|
|
the next time if we have more than 1 window
|
|
@see bug #1666054
|
|
}
|
|
// Check if all the heidisql windows are still alive.
|
|
CheckForCrashedWindows;
|
|
// Fetch list of heidisql windows.
|
|
list := GetWindowList;
|
|
if Length(list) < 2 then
|
|
OutputTo := OUTPUT_FILE;
|
|
|
|
case OutputTo of
|
|
OUTPUT_FILE : radioFile.Checked := true;
|
|
OUTPUT_DB : radioOtherDatabase.Checked := true;
|
|
OUTPUT_HOST : radioOtherHost.Checked := true;
|
|
end;
|
|
end;
|
|
if ValueExists('ExportSQL_WindowWidth') then Width := ReadInteger('ExportSQL_WindowWidth');
|
|
if ValueExists('ExportSQL_WindowHeight') then Height := ReadInteger('ExportSQL_WindowHeight');
|
|
end;
|
|
|
|
if EditFileName.Text = '' then
|
|
EditFileName.Text := ExtractFilePath(paramstr(0)) + 'export.sql';
|
|
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
|
|
procedure TExportSQLForm.comboDatabaseChange(Sender: TObject);
|
|
begin
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
procedure TExportSQLForm.comboDataChange(Sender: TObject);
|
|
begin
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
procedure TExportSQLForm.comboOtherHostSelect(Sender: TObject);
|
|
var
|
|
data: TDataSet;
|
|
j: integer;
|
|
versions : TStringList;
|
|
begin
|
|
// Get both databases and version right when the radio
|
|
// is clicked, so we can switch to the 'file' radio
|
|
// immediately when something goes wrong.
|
|
try
|
|
data := RemoteExecQuery(
|
|
appHandles[comboOtherHost.ItemIndex],
|
|
'SHOW DATABASES',
|
|
'Fetching remote list of databases...'
|
|
);
|
|
comboOtherHostDatabase.Clear;
|
|
for j:=0 to data.RecordCount - 1 do begin
|
|
comboOtherHostDatabase.Items.Add(data.FieldByName('Database').AsString);
|
|
data.Next;
|
|
end;
|
|
data.Free;
|
|
|
|
data := RemoteExecQuery(
|
|
appHandles[comboOtherHost.ItemIndex],
|
|
'SELECT VERSION()',
|
|
'Probing for remote version...'
|
|
);
|
|
versions := explode('.', data.Fields[0].AsString);
|
|
remote_version := MakeInt(versions[0]) * 10000 + MakeInt(versions[1]) * 100 + MakeInt(versions[2]);
|
|
data.Free;
|
|
|
|
// Fetch the max_allowed_packet variable to be sure not to
|
|
// overload the server when using "Extended Insert"
|
|
data := RemoteExecQuery(
|
|
appHandles[comboOtherHost.ItemIndex],
|
|
'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'),
|
|
'Checking for maximum allowed SQL-packet size on server '+comboOtherHost.Text+'...'
|
|
);
|
|
remote_max_allowed_packet := MakeInt( data.FieldByName('Value').AsString );
|
|
data.Free;
|
|
except
|
|
on E: Exception do begin
|
|
ShowMessage(E.Message);
|
|
radioFile.Checked := true;
|
|
E.Free;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TExportSQLForm.comboSelectDatabaseChange(Sender: TObject);
|
|
var
|
|
i : Integer;
|
|
dbtree_table : String;
|
|
Selected : TStringList;
|
|
sql: string;
|
|
begin
|
|
// read tables from db
|
|
checkListTables.Items.Clear;
|
|
|
|
// Fetch tables from DB
|
|
sql := 'FROM ' + MainForm.mask(comboSelectDatabase.Text);
|
|
if Mainform.ChildWin.mysql_version > 50002 then sql := 'SHOW FULL TABLES ' + sql + ' WHERE table_type=''BASE TABLE'''
|
|
else sql := 'SHOW TABLES ' + sql;
|
|
checkListTables.Items := Mainform.ChildWin.GetCol( sql );
|
|
|
|
// Fetch selected tables in list
|
|
Selected := GetVTCaptions( Mainform.ChildWin.ListTables, True );
|
|
|
|
// select all/some:
|
|
for i:=0 to checkListTables.Items.Count-1 do
|
|
begin
|
|
if Mainform.ChildWin.DBRightClickSelectedItem <> nil then
|
|
begin
|
|
case Mainform.ChildWin.DBRightClickSelectedItem.Level of
|
|
2 : dbtree_table := Mainform.ChildWin.DBRightClickSelectedItem.Text;
|
|
3 : dbtree_table := Mainform.ChildWin.DBRightClickSelectedItem.Parent.Text;
|
|
end;
|
|
case Mainform.ChildWin.DBRightClickSelectedItem.Level of
|
|
1 : checkListTables.checked[i] := true;
|
|
2,3 : checkListTables.checked[i] := dbtree_table = checkListTables.Items[i];
|
|
end;
|
|
end
|
|
else if Mainform.ChildWin.ActiveDatabase = comboSelectDatabase.Text then
|
|
checkListTables.checked[i] := Selected.IndexOf( checkListTables.Items[i] ) > -1
|
|
else
|
|
checkListTables.checked[i] := true;
|
|
end;
|
|
Mainform.ChildWin.DBRightClickSelectedItem := nil;
|
|
|
|
// write items for "Another Databases":
|
|
fillcombo_anotherdb(self);
|
|
end;
|
|
|
|
|
|
procedure TExportSQLForm.comboTablesChange(Sender: TObject);
|
|
begin
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
procedure TExportSQLForm.comboTargetCompatChange(Sender: TObject);
|
|
begin
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
procedure TExportSQLForm.CheckListToggle(Sender: TObject);
|
|
begin
|
|
// check all or none
|
|
ToggleCheckListBox(checkListTables, ((Sender as TControl).Tag = 1));
|
|
end;
|
|
|
|
|
|
|
|
procedure TExportSQLForm.btnFileBrowseClick(Sender: TObject);
|
|
begin
|
|
dialogSave.Filename := comboSelectDatabase.Text;
|
|
if dialogSave.Execute then
|
|
if dialogSave.Filename <> '' then
|
|
EditFileName.Text := dialogSave.Filename;
|
|
end;
|
|
|
|
|
|
procedure TExportSQLForm.btnExportClick(Sender: TObject);
|
|
var
|
|
f : TFileStream;
|
|
i,j,k,m : Integer;
|
|
spos, epos : Integer;
|
|
exportdb,exporttables : boolean;
|
|
exportdata : boolean;
|
|
dropquery,createquery,insertquery,
|
|
columnnames : String;
|
|
keylist : Array of TMyKey;
|
|
keystr : String;
|
|
sourceDb, destDb : String;
|
|
which : Integer;
|
|
tofile,todb,tohost : boolean;
|
|
tcount,tablecounter : Integer;
|
|
win2export : THandle;
|
|
StrProgress : String;
|
|
value : String;
|
|
Escaped,fullvalue : PChar;
|
|
extended_insert : Boolean;
|
|
max_allowed_packet : Int64;
|
|
thesevalues : String;
|
|
valuescount, limit : Integer;
|
|
donext : Boolean;
|
|
PBuffer : PChar;
|
|
sql, current_characterset : String;
|
|
target_version, loopnumber: Integer;
|
|
ansi : Boolean;
|
|
RecordCount_all, RecordCount_one, RecordNo_all,
|
|
offset : Int64;
|
|
sql_select : String;
|
|
cwin : TMDIChild;
|
|
query : TDataSet;
|
|
OldActualDatabase : String;
|
|
|
|
function sourceMask(sql: String): String;
|
|
begin
|
|
// Same as cwin.mask(sql).
|
|
Result := maskSql(cwin.mysql_version, sql);
|
|
end;
|
|
|
|
function destMask(sql: String): String;
|
|
begin
|
|
Result := maskSql(target_version, sql);
|
|
end;
|
|
|
|
function makeConditionalStmt(sql: String; version: integer; tofile: boolean): String;
|
|
begin
|
|
// End statement with semicolon, unless destination is a live server.
|
|
// Afterwards, wrap in conditional comment.
|
|
Result := sql;
|
|
if tofile then Result := Result + ';';
|
|
Result := '/*!' + IntToStr(version) + ' ' + Result + '*/';
|
|
end;
|
|
|
|
begin
|
|
// export!
|
|
pageControl1.ActivePageIndex := 0;
|
|
Screen.Cursor := crHourGlass;
|
|
|
|
// Initialize default-variables
|
|
target_version := SQL_VERSION_DEFAULT;
|
|
max_allowed_packet := 1024*1024;
|
|
|
|
// export what?
|
|
exportdb := cbxDatabase.Enabled and cbxDatabase.Checked;
|
|
exporttables := cbxTables.Enabled and cbxTables.Checked;
|
|
exportdata := cbxData.Checked;
|
|
|
|
// to where?
|
|
tofile := radioFile.Checked;
|
|
todb := radioOtherDatabase.Checked;
|
|
tohost := radioOtherHost.Checked;
|
|
|
|
// for easy use of methods in childwin
|
|
cwin := Mainform.ChildWin;
|
|
|
|
{***
|
|
@note ansgarbecker
|
|
For "export to file" set max_allowed_packet to the default-value
|
|
in mysql-server to be safe on most servers.
|
|
For "export to another db" set max_allowed_packet to the value set on current host
|
|
For "export to other host" set max_allowed_packet to the value set on remote host
|
|
@see http://dev.mysql.com/doc/refman/5.0/en/packet-too-large.html
|
|
}
|
|
|
|
// Export to .sql-file on disk
|
|
if tofile then begin
|
|
// Extract name part of selected target version
|
|
target_version := StrToIntDef( target_versions.Names[ comboTargetCompat.ItemIndex ], SQL_VERSION_DEFAULT );
|
|
max_allowed_packet := MakeInt( cwin.GetVar( 'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'), 1 ) );
|
|
try
|
|
f := TFileStream.Create(EditFileName.Text, fmCreate);
|
|
except
|
|
messagedlg('File "'+EditFileName.Text+'" could not be opened!' + crlf + 'Maybe in use by another application?', mterror, [mbOK], 0);
|
|
f.free;
|
|
Screen.Cursor := crDefault;
|
|
abort;
|
|
end;
|
|
wfs(f, '# ' + APPNAME + ' Dump ');
|
|
wfs(f, '#');
|
|
sourceDb := comboSelectDatabase.Text;
|
|
destDb := comboSelectDatabase.Text;
|
|
end;
|
|
|
|
// Export to other database in the same window
|
|
if todb then begin
|
|
target_version := cwin.mysql_version;
|
|
max_allowed_packet := MakeInt( cwin.GetVar( 'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'), 1 ) );
|
|
sourceDb := comboSelectDatabase.Text;
|
|
destDb := comboOtherDatabase.Text;
|
|
end;
|
|
|
|
// Export to other window/host
|
|
if tohost then begin
|
|
target_version := remote_version;
|
|
max_allowed_packet := remote_max_allowed_packet;
|
|
win2export := appHandles[comboOtherHost.ItemIndex];
|
|
sourceDb := comboSelectDatabase.Text;
|
|
if cbxDatabase.Checked then
|
|
begin
|
|
// Use original DB-name from source-server
|
|
destDb := comboSelectDatabase.Text;
|
|
end
|
|
else
|
|
// Use existing DB-name on target-server
|
|
destDb := comboOtherHostDatabase.Items[comboOtherHostDatabase.ItemIndex];
|
|
end;
|
|
|
|
// MySQL has supported extended insert since 3.23.
|
|
extended_insert := not (target_version = SQL_VERSION_ANSI);
|
|
|
|
try
|
|
// Be sure to read everything from the correct database
|
|
cwin.TemporaryDatabase := comboSelectDatabase.Text;
|
|
|
|
{***
|
|
Ouput useful header information only when exporting to file
|
|
}
|
|
if tofile then
|
|
begin
|
|
wfs(f, '# --------------------------------------------------------');
|
|
wfs(f, '# Host: ' + cwin.MysqlConn.Connection.HostName );
|
|
wfs(f, '# Database: ' + sourceDb );
|
|
wfs(f, '# Server version: ' + cwin.GetVar( 'SELECT VERSION()' ) );
|
|
wfs(f, '# Server OS: ' + cwin.GetVar( 'SHOW VARIABLES LIKE ' + esc('version_compile_os'), 1 ) );
|
|
wfs(f, '# Target-Compatibility: ' + comboTargetCompat.Text );
|
|
if extended_insert then
|
|
begin
|
|
wfs(f, '# max_allowed_packet: ' + inttostr(max_allowed_packet) );
|
|
end;
|
|
wfs(f, '# ' + APPNAME + ' version: ' + appversion );
|
|
wfs(f, '# --------------------------------------------------------');
|
|
wfs(f);
|
|
end;
|
|
|
|
{***
|
|
Set characterset to current one
|
|
}
|
|
if cwin.mysql_version > 40100 then
|
|
current_characterset := cwin.GetVar( 'SHOW VARIABLES LIKE ' + esc('character_set_connection'), 1 )
|
|
else if cwin.mysql_version > 40000 then
|
|
// todo: test this, add charolation --> charset conversion table from 4.0 to 4.1+
|
|
current_characterset := cwin.GetVar( 'SHOW VARIABLES LIKE ' + esc('character_set'), 1 )
|
|
else
|
|
// todo: test this
|
|
current_characterset := 'binary';
|
|
|
|
{***
|
|
Some actions which are only needed if we're not in OtherDatabase-mode:
|
|
Set character set, create and use database.
|
|
}
|
|
if tofile or tohost then
|
|
begin
|
|
if current_characterset <> '' then
|
|
begin
|
|
sql := makeConditionalStmt('SET CHARACTER SET ' + current_characterset, 40100, tofile);
|
|
sql := fixSQL( sql, target_version );
|
|
if tofile then begin
|
|
wfs(f, sql)
|
|
end else if tohost then begin
|
|
RemoteExecNonQuery(win2export, sql );
|
|
end;
|
|
end;
|
|
|
|
// Switch to correct SQL_MODE so MySQL doesn't reject ANSI SQL
|
|
if target_version = SQL_VERSION_ANSI then
|
|
begin
|
|
sql := makeConditionalStmt('SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE=''ANSI''', 40101, tofile);
|
|
sql := fixSQL( sql, target_version );
|
|
if tofile then
|
|
wfs(f, sql)
|
|
else if tohost then
|
|
RemoteExecNonQuery(win2export, sql );
|
|
end;
|
|
|
|
{***
|
|
FOREIGN KEY import compatibility (head)
|
|
Based on mysqldump output file
|
|
}
|
|
sql := makeConditionalStmt('SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0', 40014, tofile);
|
|
sql := fixSQL( sql, target_version );
|
|
if tofile then
|
|
wfs(f, sql)
|
|
else if tohost then
|
|
RemoteExecNonQuery(win2export, sql );
|
|
|
|
if exportdb then
|
|
begin
|
|
{***
|
|
DROP statement for database
|
|
}
|
|
if tofile then
|
|
begin
|
|
wfs(f);
|
|
wfs(f);
|
|
wfs(f, '#');
|
|
wfs(f, '# Database structure for database ''' + sourceDb + '''');
|
|
wfs(f, '#');
|
|
wfs(f);
|
|
end;
|
|
if comboDatabase.ItemIndex = DB_DROP_CREATE then
|
|
begin
|
|
sql := 'DROP DATABASE IF EXISTS ' + destMask(destDb);
|
|
if tofile then
|
|
wfs(f, sql + ';')
|
|
else if tohost then
|
|
RemoteExecNonQuery(win2export, sql );
|
|
end;
|
|
|
|
{***
|
|
CREATE statement for database plus database-switching
|
|
}
|
|
if cwin.mysql_version < 50002 then
|
|
begin
|
|
sql := 'CREATE DATABASE ';
|
|
if comboDatabase.ItemIndex = DB_CREATE_IGNORE then
|
|
begin
|
|
sql := sql + '/*!32312 IF NOT EXISTS*/ ';
|
|
end;
|
|
sql := sql + destMask(destDb);
|
|
end
|
|
else
|
|
begin
|
|
sql := cwin.GetVar( 'SHOW CREATE DATABASE ' + sourceMask(sourceDb), 1 );
|
|
sql := fixNewlines(sql);
|
|
if target_version = SQL_VERSION_ANSI then
|
|
sql := StringReplace(sql, '`', '"', [rfReplaceAll]);
|
|
if comboDatabase.ItemIndex = DB_CREATE_IGNORE then
|
|
begin
|
|
Insert('/*!32312 IF NOT EXISTS*/ ', sql, Pos('DATABASE', sql) + 9);
|
|
end;
|
|
end;
|
|
sql := fixSQL( sql, target_version);
|
|
if tofile then
|
|
wfs(f, sql + ';')
|
|
else if tohost then
|
|
RemoteExecNonQuery(win2export, sql);
|
|
if exporttables then
|
|
begin
|
|
if tofile then
|
|
begin
|
|
sql := 'USE ' + destMask(destDb);
|
|
wfs(f);
|
|
wfs(f, sql + ';');
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// How many tables?
|
|
tcount := 0;
|
|
for i:=0 to checkListTables.Items.Count-1 do if checkListTables.checked[i] then inc(tcount);
|
|
barProgress.Max := 0;
|
|
if exporttables then
|
|
barProgress.Max := tcount;
|
|
if exportdata then
|
|
barProgress.Max := barProgress.Max + tcount;
|
|
|
|
checkListTables.ItemIndex := -1;
|
|
tablecounter := 0;
|
|
|
|
for i:=0 to checkListTables.Items.Count-1 do if checkListTables.checked[i] then
|
|
begin
|
|
inc(tablecounter);
|
|
if checkListTables.ItemIndex > -1 then
|
|
checkListTables.Checked[checkListTables.ItemIndex] := false;
|
|
checkListTables.ItemIndex := i;
|
|
StrProgress := 'Table ' + inttostr(tablecounter) + '/' + inttostr(tcount) + ': ' + checkListTables.Items[i];
|
|
lblProgress.caption := StrProgress;
|
|
|
|
if exporttables then
|
|
begin
|
|
dropquery := '';
|
|
if comboTables.ItemIndex = TAB_DROP_CREATE then begin
|
|
if tofile then
|
|
dropquery := 'DROP TABLE IF EXISTS ' + destMask(checkListTables.Items[i])
|
|
else
|
|
dropquery := 'DROP TABLE IF EXISTS ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]);
|
|
end;
|
|
|
|
createquery := '';
|
|
if tofile then begin
|
|
createquery := '#' + crlf;
|
|
createquery := createquery + '# Table structure for table ''' + checkListTables.Items[i] + '''' + crlf;
|
|
createquery := createquery + '#' + crlf + crlf;
|
|
end;
|
|
|
|
{***
|
|
Let the server generate the CREATE TABLE statement if the version allows that
|
|
}
|
|
if cwin.mysql_version >= 32320 then
|
|
begin
|
|
Query := cwin.GetResults('SHOW CREATE TABLE ' + sourceMask(checkListTables.Items[i]));
|
|
sql := Query.Fields[1].AsString;
|
|
sql := fixNewlines(sql);
|
|
if Pos('DEFAULT CHARSET', sql) > 0 then begin
|
|
Insert('/*!40100 ', sql, Pos('DEFAULT CHARSET', sql));
|
|
sql := sql + '*/';
|
|
end;
|
|
// Mask USING {BTREE,HASH,RTREE} from older servers.
|
|
spos := 1;
|
|
while true do begin
|
|
spos := Pos2('USING', sql, spos);
|
|
if spos = 0 then break;
|
|
epos := min(Pos2(',', sql, spos), Pos2(')', sql, spos));
|
|
Insert('*/', sql, epos);
|
|
Insert('/*!50100 ', sql, spos);
|
|
spos := epos + 11;
|
|
end;
|
|
if target_version = SQL_VERSION_ANSI then
|
|
begin
|
|
sql := StringReplace(sql, '`', '"', [rfReplaceAll]);
|
|
j := max(pos('TYPE=', sql), pos('ENGINE=', sql));
|
|
// Delphi's Pos() lacks a start-at parameter. Admittedly very ugly hack to achieve said effect.
|
|
k := 0;
|
|
while k <= j do k := k + 1 + Pos(' ', Copy(sql, k + 1, Length(sql)));
|
|
Delete(sql, j, k - j);
|
|
end
|
|
else if target_version < 40102 then
|
|
begin
|
|
{***
|
|
@note ansgarbecker
|
|
The ENGINE and TYPE options specify the storage engine for the table.
|
|
ENGINE was added in MySQL 4.0.18 (for 4.0) and 4.1.2 (for 4.1).
|
|
It is the preferred option name as of those versions, and TYPE has
|
|
become deprecated. TYPE is supported throughout the 4.x series, but
|
|
likely will be removed in the future.
|
|
So we use "TYPE" on target versions below 4.1.2 and "ENGINE" on all other versions.
|
|
@see http://dev.mysql.com/doc/refman/4.1/en/create-table.html
|
|
@see http://www.heidisql.com/forum/viewtopic.php?p=1226#1226
|
|
}
|
|
sql := stringreplace(sql, 'ENGINE=', 'TYPE=', [rfReplaceAll]);
|
|
end
|
|
else
|
|
begin
|
|
sql := stringreplace(sql, 'TYPE=', 'ENGINE=', [rfReplaceAll]);
|
|
end;
|
|
sql := fixSQL( sql, target_version );
|
|
end
|
|
{***
|
|
Generate CREATE TABLE statement by hand on old servers
|
|
}
|
|
else if cwin.mysql_version < 32320 then begin
|
|
Query := cwin.GetResults( 'SHOW COLUMNS FROM ' + sourceMask(checkListTables.Items[i]));
|
|
if tofile then
|
|
sql := 'CREATE TABLE ' + destMask(checkListTables.Items[i]) + ' (' + crlf
|
|
else
|
|
sql := sql + 'CREATE TABLE ' + destMask(destDb) + '.' + sourceMask(checkListTables.Items[i]) + ' (' + crlf;
|
|
for j := 1 to Query.Fieldcount do
|
|
begin
|
|
sql := sql + ' ' + destMask(Query.Fields[0].AsString) + ' ' + Query.Fields[1].AsString;
|
|
if Query.Fields[2].AsString <> 'YES' then
|
|
sql := sql + ' NOT NULL';
|
|
if Query.Fields[4].AsString <> '' then
|
|
sql := sql + ' DEFAULT ''' + Query.Fields[4].AsString + '''';
|
|
if Query.Fields[5].AsString <> '' then
|
|
sql := sql + ' ' + Query.Fields[5].AsString;
|
|
if j < Query.Fieldcount then
|
|
sql := sql + ',' + crlf;
|
|
end;
|
|
|
|
// Keys:
|
|
Query := cwin.GetResults( 'SHOW KEYS FROM ' + sourceMask(checkListTables.Items[i]));
|
|
setLength(keylist, 0);
|
|
keystr := '';
|
|
if Query.RecordCount > 0 then
|
|
keystr := ',';
|
|
|
|
for j := 1 to Query.RecordCount do
|
|
begin
|
|
which := -1;
|
|
|
|
for k:=0 to length(keylist)-1 do
|
|
begin
|
|
if keylist[k].Name = Query.Fields[2].AsString then // keyname exists!
|
|
which := k;
|
|
end;
|
|
if which = -1 then
|
|
begin
|
|
setlength(keylist, length(keylist)+1);
|
|
which := high(keylist);
|
|
keylist[which].Columns := TStringList.Create;
|
|
with keylist[which] do // set properties for new key
|
|
begin
|
|
Name := Query.Fields[2].AsString;
|
|
if Query.Fields[2].AsString = 'PRIMARY' then
|
|
_type := 'PRIMARY'
|
|
else if Query.FieldCount >= 10 then if Query.Fields[9].AsString = 'FULLTEXT' then
|
|
_type := 'FULLTEXT'
|
|
else if Query.Fields[1].AsString = '1' then
|
|
_type := ''
|
|
else if Query.Fields[1].AsString = '0' then
|
|
_type := 'UNIQUE';
|
|
end;
|
|
end;
|
|
keylist[which].Columns.add(destMask(Query.Fields[4].AsString)); // add column(s)
|
|
Query.Next;
|
|
end;
|
|
for k:=0 to high(keylist) do
|
|
begin
|
|
if k > 0 then
|
|
keystr := keystr + ',';
|
|
if keylist[k].Name = 'PRIMARY' then
|
|
keystr := keystr + crlf + ' PRIMARY KEY ('
|
|
else
|
|
keystr := keystr + crlf + ' ' + keylist[k]._type + ' KEY ' + destMask(keylist[k].Name) + ' (';
|
|
keystr := keystr + implodestr(',', keylist[k].Columns) + ')';
|
|
end;
|
|
sql := sql + keystr + crlf + ')';
|
|
end; // mysql_version < 32320
|
|
|
|
if not tofile then Insert(destMask(destDb) + '.', sql, Pos('TABLE', sql) + 6);
|
|
|
|
if comboTables.ItemIndex = TAB_CREATE_IGNORE then
|
|
begin
|
|
Insert('/*!32312 IF NOT EXISTS*/ ', sql, Pos('TABLE', sql) + 6);
|
|
end;
|
|
|
|
createquery := createquery + sql;
|
|
|
|
// Output CREATE TABLE to file
|
|
if tofile then begin
|
|
createquery := createquery + ';' + crlf;
|
|
if dropquery <> '' then dropquery := dropquery + ';' + crlf;
|
|
wfs(f);
|
|
wfs(f);
|
|
if dropquery <> '' then wfs(f, dropquery);
|
|
wfs(f, createquery);
|
|
end
|
|
|
|
// Run CREATE TABLE on another Database
|
|
else if todb then begin
|
|
if comboTables.ItemIndex = TAB_DROP_CREATE then
|
|
cwin.ExecUpdateQuery( dropquery );
|
|
cwin.ExecUpdateQuery( createquery );
|
|
end
|
|
|
|
// Run CREATE TABLE on another host
|
|
else if tohost then begin
|
|
if comboTables.ItemIndex = TAB_DROP_CREATE then
|
|
RemoteExecNonQuery(win2export, dropquery);
|
|
RemoteExecNonQuery(win2export, createquery);
|
|
end;
|
|
|
|
barProgress.StepIt;
|
|
end;
|
|
|
|
{***
|
|
Export data
|
|
}
|
|
if exportdata then
|
|
begin
|
|
// Set to mysql-readable char:
|
|
DecimalSeparator := '.';
|
|
columnnames := ' (';
|
|
Query := cwin.GetResults( 'SHOW FIELDS FROM ' + sourceMask(checkListTables.Items[i]));
|
|
for k:=1 to Query.RecordCount do
|
|
begin
|
|
if k>1 then
|
|
columnnames := columnnames + ', ';
|
|
columnnames := columnnames + destMask(Query.Fields[0].AsString);
|
|
Query.Next;
|
|
end;
|
|
columnnames := columnnames+')';
|
|
|
|
if tofile then
|
|
begin
|
|
wfs(f);
|
|
wfs(f);
|
|
wfs(f, '#');
|
|
wfs(f, '# Dumping data for table ''' + checkListTables.Items[i] + '''');
|
|
wfs(f, '#');
|
|
wfs(f);
|
|
end;
|
|
|
|
if comboData.ItemIndex = DATA_TRUNCATE_INSERT then
|
|
begin
|
|
if tofile then
|
|
begin
|
|
wfs(f, 'TRUNCATE TABLE ' + destMask(checkListTables.Items[i]) + ';');
|
|
end
|
|
else if todb then
|
|
begin
|
|
cwin.ExecUpdateQuery('TRUNCATE TABLE ' + sourceMask(destDb) + '.' + checkListTables.Items[i]);
|
|
end
|
|
else if tohost then
|
|
begin
|
|
RemoteExecNonQuery(win2export, 'TRUNCATE TABLE ' + destMask(destDb) + '.' + checkListTables.Items[i]);
|
|
end;
|
|
end;
|
|
|
|
{***
|
|
Detect average row size and limit the number of rows fetched at
|
|
once if more than ~ 5 MB of data
|
|
Be sure to do this step before the table is locked!
|
|
}
|
|
RecordCount_all := MakeInt( cwin.GetVar( 'SELECT COUNT(*) FROM ' + sourceMask(checkListTables.Items[i]) ) );
|
|
limit := cwin.GetCalculatedLimit( checkListTables.Items[i] );
|
|
|
|
if RecordCount_all = 0 then begin
|
|
if tofile then
|
|
begin
|
|
wfs(f, '# (No data found.)');
|
|
wfs(f);
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
if tofile then
|
|
begin
|
|
wfs(f, fixSQL( '/*!40000 ALTER TABLE '+ destMask(checkListTables.Items[i]) +' DISABLE KEYS;*/', target_version) );
|
|
wfs(f, 'LOCK TABLES '+ destMask(checkListTables.Items[i]) +' WRITE;' );
|
|
end
|
|
else if todb then
|
|
begin
|
|
if target_version > 40000 then
|
|
cwin.ExecUpdateQuery( 'ALTER TABLE ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i])+ ' DISABLE KEYS' );
|
|
cwin.ExecUpdateQuery( 'LOCK TABLES ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i])+ ' WRITE, ' + sourceMask(sourceDb) + '.' + sourceMask(checkListTables.Items[i])+ ' WRITE');
|
|
end
|
|
else if tohost then
|
|
begin
|
|
if target_version > 40000 then
|
|
RemoteExecNonQuery(win2export, 'ALTER TABLE ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' DISABLE KEYS');
|
|
RemoteExecNonQuery(win2export, 'LOCK TABLES ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' WRITE');
|
|
end;
|
|
end;
|
|
|
|
offset := 0;
|
|
loopnumber := 0;
|
|
RecordNo_all := 0;
|
|
|
|
// Loop as long as (offset+limit) have not reached (recordcount)
|
|
while true do
|
|
begin
|
|
inc( loopnumber );
|
|
debug('loopnumber: '+formatnumber(loopnumber));
|
|
|
|
// Check if end of data has been reached
|
|
if ( (offset) >= RecordCount_all) or ( (limit = -1) and (loopnumber > 1) ) then
|
|
begin
|
|
break;
|
|
end;
|
|
|
|
sql_select := 'SELECT * FROM ' + sourceMask(comboSelectDatabase.Text) + '.' + sourceMask(checkListTables.Items[i]);
|
|
if limit > -1 then
|
|
begin
|
|
sql_select := sql_select + ' LIMIT ' + IntToStr( offset ) + ', ' + IntToStr( limit );
|
|
offset := offset + limit;
|
|
end;
|
|
|
|
// Execute SELECT
|
|
Query := cwin.GetResults( sql_select );
|
|
|
|
insertquery := '';
|
|
valuescount := 0;
|
|
j := 0;
|
|
donext := true;
|
|
RecordCount_one := Query.RecordCount;
|
|
while not Query.Eof do
|
|
begin
|
|
inc(j);
|
|
inc(RecordNo_all);
|
|
lblProgress.caption := StrProgress + ' (Record ' + FormatNumber(RecordNo_all) + ')';
|
|
if j mod 100 = 0 then
|
|
lblProgress.Repaint;
|
|
if insertquery = '' then
|
|
begin
|
|
case comboData.ItemIndex of
|
|
DATA_TRUNCATE_INSERT: insertquery := 'INSERT INTO ';
|
|
DATA_INSERT: insertquery := 'INSERT INTO ';
|
|
DATA_INSERT_IGNORE: insertquery := 'INSERT IGNORE INTO ';
|
|
DATA_REPLACE_INTO: insertquery := 'REPLACE INTO ';
|
|
end;
|
|
if tofile then
|
|
insertquery := insertquery + destMask(checkListTables.Items[i])
|
|
else
|
|
insertquery := insertquery + destMask(destDb) + '.' + destMask(checkListTables.Items[i]);
|
|
insertquery := insertquery + columnnames;
|
|
insertquery := insertquery + ' VALUES' + crlf + #9;
|
|
end;
|
|
thesevalues := '(';
|
|
|
|
for k := 0 to Query.fieldcount-1 do
|
|
begin
|
|
if Query.Fields[k].IsNull then
|
|
value := 'NULL'
|
|
else
|
|
case Query.Fields[k].DataType of
|
|
ftInteger, ftSmallint, ftWord:
|
|
value := Query.Fields[k].AsString;
|
|
ftBoolean:
|
|
value := esc( Bool2Str( Query.Fields[k].AsBoolean ) );
|
|
else
|
|
value := escapeAuto( Query.Fields[k].AsString, current_characterset, target_version );
|
|
end;
|
|
thesevalues := thesevalues + value;
|
|
if k < Query.Fieldcount-1 then
|
|
thesevalues := thesevalues + ',';
|
|
end;
|
|
thesevalues := thesevalues + ')';
|
|
if extended_insert then
|
|
begin
|
|
if (valuescount > 1)
|
|
and (length(insertquery)+length(thesevalues)+2 >= max_allowed_packet)
|
|
then
|
|
begin
|
|
// Rewind one record and throw thesevalues away
|
|
donext := false;
|
|
dec(j);
|
|
delete( insertquery, length(insertquery)-3, 4 );
|
|
end
|
|
else if j = RecordCount_one then
|
|
begin
|
|
insertquery := insertquery + thesevalues;
|
|
end
|
|
else
|
|
begin
|
|
inc(valuescount);
|
|
insertquery := insertquery + thesevalues + ',' + crlf + #9;
|
|
Query.Next;
|
|
continue;
|
|
end;
|
|
end
|
|
else
|
|
begin
|
|
insertquery := insertquery + thesevalues;
|
|
end;
|
|
if tofile then begin
|
|
insertquery := insertquery + ';';
|
|
wfs(f, insertquery)
|
|
end else if todb then
|
|
cwin.ExecUpdateQuery(insertquery)
|
|
else if tohost then
|
|
RemoteExecNonQuery(win2export, insertquery);
|
|
if donext then
|
|
Query.Next;
|
|
donext := true;
|
|
insertquery := '';
|
|
end;
|
|
Query.Close;
|
|
end;
|
|
// Set back to local setting:
|
|
setLocales;
|
|
|
|
if RecordCount_all > 0 then begin
|
|
if tofile then
|
|
begin
|
|
wfs(f, 'UNLOCK TABLES;' );
|
|
wfs(f, fixSQL( '/*!40000 ALTER TABLE '+destMask(checkListTables.Items[i])+' ENABLE KEYS;*/', target_version) );
|
|
end
|
|
else if todb then
|
|
begin
|
|
cwin.ExecUpdateQuery( 'UNLOCK TABLES' );
|
|
if target_version > 40000 then
|
|
cwin.ExecUpdateQuery( 'ALTER TABLE ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i]) + ' ENABLE KEYS' );
|
|
end
|
|
else if tohost then
|
|
begin
|
|
RemoteExecNonQuery(win2export, 'UNLOCK TABLES');
|
|
if target_version > 40000 then
|
|
RemoteExecNonQuery(win2export, 'ALTER TABLE ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' ENABLE KEYS');
|
|
end;
|
|
end;
|
|
barProgress.StepIt;
|
|
end;
|
|
end;
|
|
|
|
// Restore old value for SQL_MODE
|
|
if (tofile or tohost) and (target_version = SQL_VERSION_ANSI) then
|
|
begin
|
|
sql := makeConditionalStmt('SET SQL_MODE=@OLD_SQL_MODE', 40101, tofile);
|
|
sql := fixSql(sql, target_version);
|
|
if tofile then
|
|
wfs(f, sql)
|
|
else if tohost then
|
|
RemoteExecNonQuery(win2export, sql );
|
|
end;
|
|
|
|
{***
|
|
FOREIGN KEY import compatibility (foot)
|
|
Based on mysqldump output file
|
|
}
|
|
sql := makeConditionalStmt('SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS', 40014, tofile);
|
|
sql := fixSQL( sql, target_version );
|
|
if tofile then
|
|
wfs(f, sql)
|
|
else if tohost then
|
|
RemoteExecNonQuery(win2export, sql );
|
|
|
|
FINALLY
|
|
cwin.TemporaryDatabase := '';
|
|
if tofile then
|
|
f.Free;
|
|
Screen.Cursor := crDefault;
|
|
END;
|
|
|
|
SaveSettings;
|
|
close;
|
|
end;
|
|
|
|
procedure TExportSQLForm.radioOtherDatabaseClick(Sender: TObject);
|
|
begin
|
|
if comboSelectDatabase.Items.Count <= 1 then begin
|
|
MessageDLG('There must be more than one database to enable this option.', mtError, [mbOK], 0);
|
|
radioFile.OnClick(self);
|
|
abort;
|
|
end;
|
|
validateRadioControls(Sender);
|
|
validateControls(Sender);
|
|
generateExampleSql;
|
|
end;
|
|
|
|
procedure TExportSQLForm.radioFileClick(Sender: TObject);
|
|
begin
|
|
validateRadioControls(Sender);
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
procedure TExportSQLForm.fillcombo_anotherdb(Sender: TObject);
|
|
begin
|
|
comboOtherDatabase.Items := comboSelectDatabase.Items;
|
|
comboOtherDatabase.Items.delete(comboSelectDatabase.ItemIndex);
|
|
if comboOtherDatabase.ItemIndex = -1 then
|
|
comboOtherDatabase.ItemIndex := 0;
|
|
end;
|
|
|
|
procedure TExportSQLForm.generateExampleSQL;
|
|
const
|
|
STR_DROP_DB = 'DROP DATABASE <db>;' + CRLF;
|
|
STR_CREATE_DB = 'CREATE DATABASE <db>;' + CRLF;
|
|
STR_CREATE_DB_IGNORE = 'CREATE DATABASE IF NOT EXISTS <db>;' + CRLF;
|
|
STR_DROP_TABLE = 'DROP TABLE <table>;' + CRLF;
|
|
STR_CREATE_TABLE = 'CREATE TABLE <table> <definition>;' + CRLF;
|
|
STR_CREATE_TABLE_IGNORE = 'CREATE TABLE IF NOT EXISTS <table> <definition>;' + CRLF;
|
|
STR_TRUNCATE_TABLE = 'TRUNCATE TABLE <table>;' + CRLF;
|
|
STR_INSERT = 'INSERT INTO <table> (<columns>) VALUES (<values>)';
|
|
STR_INSERT_IGNORE = 'INSERT IGNORE INTO <table> (<columns>) VALUES (<values>)';
|
|
STR_REPLACE_INTO = 'REPLACE INTO <table> (<columns>) VALUES (<values>)';
|
|
STR_END_INSERT_REG = ';' + CRLF + '(...)' + CRLF;
|
|
STR_END_INSERT_EXT = ', (<values>)...;' + CRLF;
|
|
var
|
|
s: string;
|
|
procedure add(str: string); overload;
|
|
begin
|
|
s := s + str;
|
|
end;
|
|
procedure add(str1: string; str2: string); overload;
|
|
begin
|
|
s := s + str1 + str2;
|
|
end;
|
|
begin
|
|
s := '';
|
|
if cbxStructure.Enabled and cbxStructure.Checked then begin
|
|
if cbxDatabase.Enabled and cbxDatabase.Checked then begin
|
|
case comboDatabase.ItemIndex of
|
|
DB_DROP_CREATE: add(STR_DROP_DB, STR_CREATE_DB);
|
|
DB_CREATE: add(STR_CREATE_DB);
|
|
DB_CREATE_IGNORE: add(STR_CREATE_DB_IGNORE);
|
|
end;
|
|
add( CRLF );
|
|
end;
|
|
if cbxTables.Enabled and cbxTables.Checked then begin
|
|
case comboTables.ItemIndex of
|
|
TAB_DROP_CREATE: add(STR_DROP_TABLE, STR_CREATE_TABLE);
|
|
TAB_CREATE: add(STR_CREATE_TABLE);
|
|
TAB_CREATE_IGNORE: add(STR_CREATE_TABLE_IGNORE);
|
|
end;
|
|
add( CRLF );
|
|
end;
|
|
end;
|
|
if cbxData.Enabled and cbxData.Checked then begin
|
|
case comboData.ItemIndex of
|
|
DATA_TRUNCATE_INSERT: add(STR_TRUNCATE_TABLE, STR_INSERT);
|
|
DATA_INSERT: add(STR_INSERT);
|
|
DATA_INSERT_IGNORE: add(STR_INSERT_IGNORE);
|
|
DATA_REPLACE_INTO: add(STR_REPLACE_INTO);
|
|
end;
|
|
if comboTargetCompat.ItemIndex > 0 then add(STR_END_INSERT_EXT)
|
|
else add(STR_END_INSERT_REG);
|
|
end;
|
|
s := TrimRight(s);
|
|
SynMemoExampleSql.Text := s;
|
|
end;
|
|
|
|
procedure TExportSQLForm.validateRadioControls(Sender: TObject);
|
|
begin
|
|
if radioFile.Checked then begin
|
|
EditFileName.Enabled := true;
|
|
EditFileName.Color := clWindow;
|
|
btnFileBrowse.Enabled := true;
|
|
EditFileName.SetFocus;
|
|
end else begin
|
|
EditFileName.Enabled := false;
|
|
EditFileName.Color := clBtnFace;
|
|
btnFileBrowse.Enabled := false;
|
|
end;
|
|
|
|
if radioOtherDatabase.Checked then begin
|
|
comboOtherDatabase.Enabled := true;
|
|
comboOtherDatabase.Color := clWindow;
|
|
if comboOtherDatabase.CanFocus then comboOtherDatabase.SetFocus;
|
|
end else begin
|
|
comboOtherDatabase.Enabled := false;
|
|
comboOtherDatabase.Color := clBtnFace;
|
|
end;
|
|
|
|
if radioOtherHost.Checked then begin
|
|
comboOtherHost.Enabled := true;
|
|
comboOtherHost.Color := clWindow;
|
|
comboOtherHostDatabase.Enabled := not (cbxStructure.Checked and cbxDatabase.Checked);
|
|
comboOtherHostDatabase.Color := clWindow;
|
|
if comboOtherHost.CanFocus then comboOtherHost.SetFocus;
|
|
end else begin
|
|
comboOtherHost.Enabled := false;
|
|
comboOtherHost.Color := clBtnFace;
|
|
comboOtherHostDatabase.Enabled := false;
|
|
comboOtherHostDatabase.Color := clBtnFace;
|
|
end;
|
|
|
|
// Disable target selection if exporting to known session.
|
|
comboTargetCompat.Enabled := radioFile.Checked;
|
|
end;
|
|
|
|
procedure TExportSQLForm.validateControls(Sender: TObject);
|
|
begin
|
|
cbxDatabase.Enabled := cbxStructure.Checked and ( radioFile.Checked or radioOtherHost.Checked );
|
|
comboDatabase.Enabled := cbxStructure.Checked and ( radioFile.Checked or radioOtherHost.Checked ) and cbxDatabase.Checked;
|
|
comboOtherHostDatabase.Enabled := not cbxDatabase.Checked;
|
|
|
|
cbxTables.Enabled := cbxStructure.Checked;
|
|
comboTables.Enabled := cbxStructure.Checked and cbxTables.Checked;
|
|
|
|
comboData.Enabled := cbxData.Checked;
|
|
|
|
// Prevent choosing export of db struct + data but no table struct.
|
|
if cbxData.Checked then begin
|
|
if Sender = cbxTables then cbxDatabase.Checked := cbxDatabase.Checked And cbxTables.Checked
|
|
else cbxTables.Checked := cbxTables.Checked or cbxDatabase.Checked;
|
|
end;
|
|
|
|
btnExport.Enabled := cbxData.Checked or
|
|
(cbxStructure.Checked and (cbxDatabase.Checked or cbxTables.Checked));
|
|
|
|
if cbxStructure.Checked and cbxDatabase.Checked and (comboDatabase.ItemIndex = DB_DROP_CREATE) then begin
|
|
// 'drop tables', 'truncate data', 'insert ignore' and 'replace into' is useless.
|
|
comboTables.ItemIndex := TAB_CREATE;
|
|
comboTables.Enabled := false;
|
|
comboData.ItemIndex := DATA_INSERT;
|
|
comboData.Enabled := false;
|
|
end;
|
|
|
|
if cbxStructure.Checked and cbxTables.Checked and (comboTables.ItemIndex = TAB_DROP_CREATE) then begin
|
|
// 'truncate data', 'insert ignore' and 'replace into' is useless.
|
|
comboData.ItemIndex := DATA_INSERT;
|
|
comboData.Enabled := false;
|
|
end;
|
|
end;
|
|
|
|
procedure TExportSQLForm.cbxStructureClick(Sender: TObject);
|
|
begin
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
procedure TExportSQLForm.cbxDataClick(Sender: TObject);
|
|
begin
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
procedure TExportSQLForm.cbxTablesClick(Sender: TObject);
|
|
begin
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
procedure TExportSQLForm.checkListTablesKeyDown(Sender: TObject; var Key: Word;
|
|
Shift: TShiftState);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
// if exist tables and is more than one, 'cause
|
|
// if exists only one, this action is not needed
|
|
// and CTRL Key is pressed
|
|
if ((checkListTables.Count > 1) and (ssCtrl in Shift)) then
|
|
begin
|
|
case (Key) of
|
|
VK_UP: // UP Key
|
|
begin
|
|
// find the selected, starting from the second table
|
|
for i := 1 to (checkListTables.Count - 1) do
|
|
begin
|
|
if (checkListTables.Selected[i]) then
|
|
begin
|
|
// move the selected to up
|
|
checkListTables.Items.Move(i, (i - 1));
|
|
// select it again
|
|
checkListTables.Selected[i] := True;
|
|
// stop the find
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
VK_DOWN: // DOWN Key
|
|
begin
|
|
// find the selected, starting from the first table, but
|
|
// ignore the last
|
|
for i := 0 to (checkListTables.Count - 2) do
|
|
begin
|
|
if (checkListTables.Selected[i]) then
|
|
begin
|
|
// move the selected to down
|
|
checkListTables.Items.Move(i, (i + 1));
|
|
// select it again
|
|
checkListTables.Selected[i] := True;
|
|
// stop the find
|
|
Break;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TExportSQLForm.cbxDatabaseClick(Sender: TObject);
|
|
begin
|
|
validateControls(Sender);
|
|
generateExampleSQL;
|
|
end;
|
|
|
|
|
|
procedure TExportSQLForm.radioOtherHostClick(Sender: TObject);
|
|
var
|
|
list: TWindowDataArray;
|
|
i, k: integer;
|
|
begin
|
|
// Check if all the heidisql windows are still alive.
|
|
CheckForCrashedWindows;
|
|
|
|
// Fetch list of heidisql windows.
|
|
list := GetWindowList;
|
|
|
|
// Fill list of hosts.
|
|
comboOtherHost.Items.Clear;
|
|
SetLength(appHandles, High(list));
|
|
k := 0;
|
|
for i := 0 to High(list) do with list[i] do begin
|
|
// Do not include current window.
|
|
if appHandle <> MainForm.Handle then begin
|
|
// Do not include non-connected windows.
|
|
if connected then begin
|
|
if namePostfix <> 0 then name := name + Format(' (%d)', [namePostFix]);
|
|
comboOtherHost.Items.Add(name);
|
|
appHandles[k] := appHandle;
|
|
k := k + 1;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
// Abort if no other windows.
|
|
if comboOtherHost.Items.Count = 0 then begin
|
|
MessageDLG('You need at least two open connection-windows to enable this option.', mtError, [mbOK], 0);
|
|
radioFile.Checked := true;
|
|
abort;
|
|
end;
|
|
|
|
// Select first host and first database.
|
|
comboOtherHost.ItemIndex := 0;
|
|
comboOtherHost.OnSelect(comboOtherHost);
|
|
comboOtherHostDatabase.ItemIndex := 0;
|
|
|
|
// De-select database structure to enable database dropdown box.
|
|
cbxDatabase.Checked := false;
|
|
|
|
validateRadioControls(Sender);
|
|
validateControls(Sender);
|
|
generateExampleSql;
|
|
end;
|
|
|
|
|
|
|
|
{***
|
|
Save settings in registry, should be called just before closing
|
|
the form, but not when Cancel was pressed.
|
|
}
|
|
procedure TExportSQLForm.SaveSettings;
|
|
var
|
|
OutputTo : Byte;
|
|
begin
|
|
with TRegistry.Create do
|
|
begin
|
|
OpenKey(REGPATH, true);
|
|
// WithUseDB, UseBackticks, CompleteInserts, WithDropTable: deprecated (currently not automagically removed)
|
|
WriteBool('ExportStructure', cbxStructure.Checked);
|
|
WriteBool('WithCreateDatabase', cbxDatabase.Checked);
|
|
WriteBool('WithCreateTable', cbxTables.Checked);
|
|
WriteBool('ExportData', cbxData.Checked);
|
|
WriteInteger('CreateDatabaseHow', comboDatabase.ItemIndex);
|
|
WriteInteger('CreateTablesHow', comboTables.ItemIndex);
|
|
WriteInteger('CreateDataHow', comboData.ItemIndex);
|
|
WriteInteger('Compatibility', comboTargetCompat.ItemIndex);
|
|
WriteString('exportfilename', EditFileName.Text);
|
|
OutputTo := OUTPUT_FILE;
|
|
if radioOtherDatabase.checked then
|
|
OutputTo := OUTPUT_DB
|
|
else if radioOtherHost.checked then
|
|
OutputTo := OUTPUT_HOST;
|
|
WriteInteger('ExportSQL_OutputTo', OutputTo );
|
|
WriteInteger('ExportSQL_WindowWidth', Width );
|
|
WriteInteger('ExportSQL_WindowHeight', Height );
|
|
CloseKey();
|
|
end;
|
|
end;
|
|
|
|
end.
|
|
|
|
|
|
|
|
|