Files
HeidiSQL/source/exportsql.pas

1599 lines
55 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,
PngSpeedButton, StdActns, WideStrings, TntCheckLst, TntStdCtrls, Menus;
type
TExportSQLForm = class(TForm)
btnExport: TButton;
btnCancel: TButton;
dialogSave: TSaveDialog;
barProgress: TProgressBar;
lblProgress: TLabel;
pageControl1: TPageControl;
TabSheet1: TTabSheet;
TabSheet2: TTabSheet;
lblSelectDbTables: TLabel;
checkListTables: TTNTCheckListBox;
comboSelectDatabase: TTNTComboBox;
toolbarSelectTools: TToolBar;
ToolButton1: TToolButton;
ToolButton2: TToolButton;
groupOutput: TGroupBox;
btnFileBrowse: TPngSpeedButton;
editFileName: TEdit;
radioOtherDatabase: TRadioButton;
radioFile: TRadioButton;
comboOtherDatabase: TTNTComboBox;
radioOtherHost: TRadioButton;
comboOtherHost: TComboBox;
comboOtherHostDatabase: TTNTComboBox;
groupExampleSql: TGroupBox;
SynMemoExampleSQL: TSynMemo;
groupOptions: TGroupBox;
lblTargetCompat: TLabel;
cbxStructure: TCheckBox;
cbxDatabase: TCheckBox;
comboDatabase: TComboBox;
cbxTables: TCheckBox;
comboTables: TComboBox;
cbxData: TCheckBox;
comboData: TComboBox;
comboTargetCompat: TComboBox;
radioDirectory: TRadioButton;
editDirectory: TEdit;
btnDirectoryBrowse: TPngSpeedButton;
procedure FormCreate(Sender: TObject);
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 btnDirectoryBrowseClick(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 radioFileOrDirClick(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 }
SelectedTables: TWideStringList;
function InitFileStream(TableName: String; OldStream: TFileStream = nil): TFileStream;
public
{ Public declarations }
end;
{$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;
OUTPUT_DIR = 4;
// Default output compatibility
SQL_VERSION_DEFAULT = SQL_VERSION_ANSI;
// Pattern for use in creating destination files
TABLENAME_PATTERN = '<table>';
var
appHandles: array of THandle;
cancelDialog: TForm = nil;
remote_version: integer;
remote_max_allowed_packet : Int64;
target_versions : TStringList;
procedure TExportSQLForm.FormCreate(Sender: TObject);
var
menu: TMenu;
ds: TDataset;
begin
menu := nil;
if Owner is TMenuItem then
menu := (Owner as TMenuItem).GetParentMenu;
if menu = Mainform.ChildWin.popupTreeView then begin
SelectedTables := TWideStringlist.Create;
// If a table is selected, use that for preselection. If only a db was selected, use all tables inside it.
if Mainform.ChildWin.SelectedTable <> '' then
SelectedTables.Add(Mainform.ChildWin.SelectedTable)
else begin
ds := Mainform.ChildWin.FetchDbTableList(Mainform.ChildWin.ActiveDatabase);
while not ds.Eof do begin
SelectedTables.Add(ds.Fields[0].AsWideString);
ds.Next;
end;
end;
end else
SelectedTables := GetVTCaptions( Mainform.ChildWin.ListTables, True );
// Assign images from main imagelist to speedbuttons
btnFileBrowse.PngImage := Mainform.PngImageListMain.PngImages[10].PngImage;
btnDirectoryBrowse.PngImage := Mainform.PngImageListMain.PngImages[51].PngImage;
SetWindowSizeGrip( Self.Handle, True );
InheritFont(Font);
end;
procedure TExportSQLForm.FormShow(Sender: TObject);
var
i, OutputTo : Integer;
list: TWindowDataArray;
CWin: TMDIChild;
begin
CWin := Mainform.ChildWin;
barProgress.Position := 0;
lblProgress.Caption := '';
PageControl1.ActivePageIndex := 0;
SynMemoExampleSQL.Highlighter := CWin.SynSQLSyn1;
SynMemoExampleSQL.Font := CWin.SynMemoQuery.Font;
// read dbs and Tables from treeview
comboSelectDatabase.Items.Clear;
Caption := CWin.MysqlConn.SessionName + ' - Export Tables...';
comboSelectDatabase.Items.Assign(CWin.Databases);
comboSelectDatabase.ItemIndex := comboSelectDatabase.Items.IndexOf(CWin.ActiveDatabase);
// Select first database if at least one is available.
if (comboSelectDatabase.ItemIndex = -1) and (comboSelectDatabase.Items.Count>0) 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 ) + '=ANSI SQL' );
Add( IntToStr( CWin.mysql_version ) + '=Same as source (' + ConvertServerVersion(CWin.mysql_version) + ')');
Add( '50100=HeidiSQL w/ MySQL Server 5.1' );
Add( '50000=HeidiSQL w/ MySQL Server 5.0' );
Add( '40100=HeidiSQL w/ MySQL Server 4.1' );
Add( '40000=HeidiSQL w/ MySQL Server 4.0' );
Add( '32300=HeidiSQL w/ MySQL Server 3.23' );
Add( '50100_mysqldump=mysqldump+mysqlcli 5.1' );
Add( '50000_mysqldump=mysqldump+mysqlcli 5.0' );
Add( '40100_mysqldump=mysqldump+mysqlcli 4.1' );
Add( '40000_mysqldump=mysqldump+mysqlcli 4.0' );
Add( '32300_mysqldump=mysqldump+mysqlcli 3.23' );
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
// WithUseDB, UseBackticks, CompleteInserts: deprecated (hardcoded true now)
cbxStructure.Checked := Mainform.GetRegValue(REGNAME_EXP_STRUCTURE, cbxStructure.Checked);
cbxDatabase.Checked := Mainform.GetRegValue(REGNAME_EXP_CREATEDB, cbxDatabase.Checked);
cbxTables.Checked := Mainform.GetRegValue(REGNAME_EXP_CREATETABLE, cbxTables.Checked);
cbxData.Checked := Mainform.GetRegValue(REGNAME_EXP_DATA, cbxData.Checked);
comboDatabase.ItemIndex := Mainform.GetRegValue(REGNAME_EXP_DBHOW, comboDatabase.ItemIndex);
comboTables.ItemIndex := Mainform.GetRegValue(REGNAME_EXP_TABLESHOW, comboTables.ItemIndex);
comboData.ItemIndex := Mainform.GetRegValue(REGNAME_EXP_DATAHOW, comboData.ItemIndex);
comboTargetCompat.ItemIndex := Mainform.GetRegValue(REGNAME_EXP_COMPAT, comboTargetCompat.ItemIndex);
editFileName.Text := Mainform.GetRegValue(REGNAME_EXP_OUTFILE, '');
editDirectory.Text := Mainform.GetRegValue(REGNAME_EXP_OUTDIR, '');
OutputTo := Mainform.GetRegValue(REGNAME_EXP_TARGET, -1);
if OutputTo > -1 then
begin
{***
@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) and (OutputTo = OUTPUT_HOST) then
OutputTo := OUTPUT_FILE;
case OutputTo of
OUTPUT_FILE : radioFile.Checked := true;
OUTPUT_DIR : radioDirectory.Checked := true;
OUTPUT_DB : radioOtherDatabase.Checked := true;
OUTPUT_HOST : radioOtherHost.Checked := true;
end;
end;
Width := Mainform.GetRegValue(REGNAME_EXP_WINWIDTH, Width);
Height := Mainform.GetRegValue(REGNAME_EXP_WINHEIGHT, Height);
if EditFileName.Text = '' then
EditFileName.Text := ExtractFilePath(paramstr(0)) + 'export.sql';
// Tell the user how to use the table pattern
EditFileName.Hint := 'Usage for generating one file per table: c:\foo\bar_'+TABLENAME_PATTERN+'.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 : TWideStringList;
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').AsWideString);
data.Next;
end;
data.Free;
data := RemoteExecQuery(
appHandles[comboOtherHost.ItemIndex],
'SELECT VERSION()',
'Probing for remote version...'
);
versions := explode('.', data.Fields[0].AsWideString);
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;
// Select remote database with the same name as the source db if available
if comboOtherHostDatabase.Items.IndexOf( comboSelectDatabase.Text ) > -1 then
comboOtherHostDatabase.ItemIndex := comboOtherHostDatabase.Items.IndexOf( comboSelectDatabase.Text )
// Otherwise, select first database if available
else if comboOtherHostDatabase.Items.Count > 0 then
comboOtherHostDatabase.ItemIndex := 0;
end;
procedure TExportSQLForm.comboSelectDatabaseChange(Sender: TObject);
var
i : Integer;
sql: WideString;
CWin: TMDIChild;
CheckThisItem: Boolean;
begin
CWin := Mainform.Childwin;
// read tables from db
checkListTables.Items.Clear;
// Fetch tables from DB
sql := 'FROM ' + MainForm.mask(comboSelectDatabase.Text);
if CWin.mysql_version > 50002 then sql := 'SHOW FULL TABLES ' + sql + ' WHERE table_type=''BASE TABLE'''
else sql := 'SHOW TABLES ' + sql;
checkListTables.Items.Text := CWin.GetCol( sql ).Text;
// select all/some:
for i:=0 to checkListTables.Items.Count-1 do
begin
if CWin.ActiveDatabase = comboSelectDatabase.Text then
CheckThisItem := SelectedTables.IndexOf( checkListTables.Items[i] ) > -1
else
CheckThisItem := true;
checkListTables.checked[i] := CheckThisItem;
end;
// 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;
{**
Parse destination filename for variables like %table% and create the file
If an existing filestream is passed, check if it should be reused, depending on the "Part"
@return TFileStream|Nil
}
function TExportSQLForm.InitFileStream(TableName: String; OldStream: TFileStream = nil): TFileStream;
var
UnparsedFileName, ParsedFileName, FileName, FilePath : String;
begin
Result := nil;
// File or directory ?
if radioFile.Checked then
UnparsedFileName := EditFileName.Text
else if radioDirectory.Checked then begin
UnparsedFileName := EditDirectory.Text;
// Ensure directory ends with a slash.
// ExtractFilePath() expects a slash at the very end, otherwise the last segment
// will be identified as filename and therefore stripped from the return value
if UnparsedFileName[Length(UnparsedFileName)] <> '\' then
UnparsedFileName := UnparsedFileName + '\';
UnparsedFileName := ExtractFilePath(UnparsedFileName);
UnparsedFileName := UnparsedFileName + TABLENAME_PATTERN + '.sql';
end else begin
Screen.Cursor := crDefault;
Raise Exception.Create('Internal error: InitFileStream called in wrong context.');
end;
// Parse filename
FilePath := ExtractFilePath(UnparsedFileName);
FileName := ExtractFileName(UnparsedFileName);
FileName := StringReplace(FileName, TABLENAME_PATTERN, TableName, [rfIgnoreCase]);
ParsedFileName := FilePath + GoodFileName(FileName);
// Reuse the old stream if its filename has not changed
if (OldStream <> nil) and (OldStream.FileName = ParsedFileName) then
begin
Result := OldStream;
Exit;
end;
// Filename has changed, so close the old file.
if OldStream <> nil then
OldStream.Free;
// Warn about overwriting target file
if FileExists(ParsedFileName) then begin
if MessageDlg('Overwrite file "'+ParsedFileName+'" ?', mtConfirmation, [mbYes, mbCancel], 0 ) <> mrYes then
Exit;
end;
// Create the file
try
Result := openfs(ParsedFileName);
except
MessageDlg('File "'+ParsedFileName+'" could not be opened!' + CRLF + 'Maybe in use by another application?', mterror, [mbOK], 0);
Result.Free;
end;
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 : WideString;
keylist : Array of TMyKey;
keystr : WideString;
sourceDb, destDb : WideString;
which : Integer;
tofile,todb,tohost : boolean;
samehost : boolean;
sameuuid : TGuid;
tcount,tablecounter : Integer;
win2export : THandle;
StrProgress : String;
value : WideString;
Escaped,fullvalue : PChar;
extended_insert : Boolean;
max_allowed_packet : Int64;
thesevalues : WideString;
valuescount : Integer;
donext : Boolean;
PBuffer : PChar;
sql, current_characterset : WideString;
loopnumber : Integer;
target_version : Integer;
target_cliwa : Boolean;
ansi : Boolean;
RecordCount_all, RecordCount_one, RecordNo_all,
offset, limit : Int64;
sql_select : WideString;
cwin : TMDIChild;
query : TDataSet;
OldActualDatabase : WideString;
function sourceMask(sql: WideString): WideString;
begin
// Same as cwin.mask(sql).
Result := maskSql(cwin.mysql_version, sql);
end;
function destMask(sql: WideString): WideString;
begin
Result := maskSql(target_version, sql);
end;
function makeConditionalStmt(sql: WideString; version: integer; tofile: boolean): WideString;
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
// Check for valid directory
if radioDirectory.Checked then begin
if not DirectoryExists(EditDirectory.Text) then begin
MessageDlg('The selected directory "'+EditDirectory.Text+'" does not exist.', mtError, [mbOk], 0);
EditDirectory.SetFocus;
Exit;
end;
end;
// to where?
tofile := radioFile.Checked or radioDirectory.Checked;
todb := radioOtherDatabase.Checked;
tohost := radioOtherHost.Checked;
// export!
pageControl1.ActivePageIndex := 0;
Screen.Cursor := crHourGlass;
// Initialize default-variables
target_version := SQL_VERSION_DEFAULT;
target_cliwa := false;
win2export := 0;
max_allowed_packet := 1024*1024;
// export what?
exportdb := cbxDatabase.Enabled and cbxDatabase.Checked;
exporttables := cbxTables.Enabled and cbxTables.Checked;
exportdata := cbxData.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 := MakeInt(target_versions.Names[comboTargetCompat.ItemIndex]);
target_cliwa := Pos('mysqldump', target_versions.Names[comboTargetCompat.ItemIndex]) > 0;
max_allowed_packet := MakeInt( cwin.GetVar( 'SHOW VARIABLES LIKE ' + esc('max_allowed_packet'), 1 ) );
f := InitFileStream('header');
if f = nil then
begin
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 exportdb then begin
// Use original DB-name from source-server
destDb := comboSelectDatabase.Text;
end else begin
// Use existing DB-name on target-server
destDb := comboOtherHostDatabase.Items[comboOtherHostDatabase.ItemIndex];
end;
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, WideFormat('# %-30s%s', ['Host:', cwin.MysqlConn.Connection.HostName]));
wfs(f, WideFormat('# %-30s%s', ['Database:', sourceDb]));
wfs(f, WideFormat('# %-30s%s', ['Server version:', cwin.GetVar('SELECT VERSION()')]));
wfs(f, WideFormat('# %-30s%s', ['Server OS:', cwin.GetVar('SHOW VARIABLES LIKE ' + esc('version_compile_os'), 1)]));
wfs(f, WideFormat('# %-30s%s', ['Target compatibility:', comboTargetCompat.Text]));
if extended_insert then
begin
wfs(f, WideFormat('# %-30s%d', ['Target max_allowed_packet:', max_allowed_packet]));
end;
wfs(f, WideFormat('# %-30s%s', [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';
{***
Check if source and destination session is connected to the same server.
}
samehost := todb;
if tohost then begin
i := CreateGuid(sameuuid);
if i <> 0 then raise Exception.Create('Could not create a GUID.');
sql := esc(appName + '_' + GuidToString(sameuuid));
try
i := StrToInt(cwin.GetVar('SELECT GET_LOCK(' + sql + ', 0)'));
if i <> 1 then raise Exception.Create('Could not create a server lock.');
query := RemoteExecQuery(
win2export,
'SELECT GET_LOCK(' + sql + ', 0)',
'Checking for same server...'
);
i := query.Fields[0].AsInteger;
query.Free;
if i <> 1 then samehost := true
else begin
query := RemoteExecQuery(
win2export,
'SELECT RELEASE_LOCK(' + sql + ')',
'Releasing remote lock...'
);
end;
finally
cwin.ExecuteNonQuery('SELECT RELEASE_LOCK(' + sql + ')');
end;
end;
{***
Avoid destructive actions (DROP before CREATE) on same host and database.
}
if tohost and samehost then begin
if exportdb and (comboDatabase.ItemIndex = DB_DROP_CREATE) then raise Exception.Create('Aborted: selected action "database recreate" on same source/destination host would drop source database.');
if exporttables and (comboTables.ItemIndex = TAB_DROP_CREATE) then begin
if sourceDb = destDb then raise Exception.Create('Aborted: selected action "tables recreate" on same source/destination host and database would drop source tables.');
end;
end;
{***
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
// 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,NO_BACKSLASH_ESCAPES''', 40101, tofile);
sql := fixSQL( sql, target_version, target_cliwa );
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, target_cliwa );
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, target_cliwa );
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 tofile then
f := InitFileStream(checkListTables.Items[i], f);
if exporttables then
begin
if tofile then
begin
if f = nil then
begin
Screen.Cursor := crDefault;
Abort;
end;
end;
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].AsWideString;
Query.Close;
FreeAndNil(Query);
sql := fixNewlines(sql);
sql := fixSQL( sql, target_version, target_cliwa );
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].AsWideString) + ' ' + Query.Fields[1].AsWideString;
if Query.Fields[2].AsString <> 'YES' then
sql := sql + ' NOT NULL';
if Query.Fields[4].AsWideString <> '' then
sql := sql + ' DEFAULT ''' + Query.Fields[4].AsWideString + '''';
if Query.Fields[5].AsWideString <> '' then
sql := sql + ' ' + Query.Fields[5].AsWideString;
if j < Query.Fieldcount then
sql := sql + ',' + crlf;
end;
Query.Close;
FreeAndNil(Query);
// 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 := TWideStringList.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].AsWideString)); // add column(s)
Query.Next;
end;
Query.Close;
FreeAndNil(Query);
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].AsWideString);
Query.Next;
end;
columnnames := columnnames+')';
Query.Close;
FreeAndNil(Query);
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;
// Set rows per step limit and detect total row count
// Be sure to do this step before the table is locked!
limit := 5000;
RecordCount_all := MakeInt(cwin.GetNamedVar('SHOW TABLE STATUS LIKE '+esc(checkListTables.Items[i]), 'Rows'));
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, 'LOCK TABLES '+ destMask(checkListTables.Items[i]) +' WRITE;' );
wfs(f, fixSQL( '/*!40000 ALTER TABLE '+ destMask(checkListTables.Items[i]) +' DISABLE KEYS;*/', target_version, target_cliwa) );
end
else if todb then
begin
cwin.ExecUpdateQuery( 'LOCK TABLES ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i])+ ' WRITE, ' + sourceMask(sourceDb) + '.' + sourceMask(checkListTables.Items[i])+ ' WRITE');
if target_version > 40000 then
cwin.ExecUpdateQuery( 'ALTER TABLE ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i])+ ' DISABLE KEYS' );
end
else if tohost then
begin
RemoteExecNonQuery(win2export, 'LOCK TABLES ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' WRITE');
if target_version > 40000 then
RemoteExecNonQuery(win2export, 'ALTER TABLE ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' DISABLE KEYS');
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].AsWideString;
ftBoolean:
value := esc( Bool2Str( Query.Fields[k].AsBoolean ) );
ftBlob:
value := '0x' + BinToWideHex(Query.Fields[k].AsString);
else
value := esc( Query.Fields[k].AsWideString, False, 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;
FreeAndNil(Query);
end;
// Set back to local setting:
setLocales;
if RecordCount_all > 0 then begin
if tofile then
begin
wfs(f, fixSQL( '/*!40000 ALTER TABLE '+destMask(checkListTables.Items[i])+' ENABLE KEYS;*/', target_version, target_cliwa) );
wfs(f, 'UNLOCK TABLES;' );
end
else if todb then
begin
if target_version > 40000 then
cwin.ExecUpdateQuery( 'ALTER TABLE ' + sourceMask(destDb) + '.' + sourceMask(checkListTables.Items[i]) + ' ENABLE KEYS' );
cwin.ExecUpdateQuery( 'UNLOCK TABLES' );
end
else if tohost then
begin
if target_version > 40000 then
RemoteExecNonQuery(win2export, 'ALTER TABLE ' + destMask(destDb) + '.' + destMask(checkListTables.Items[i]) + ' ENABLE KEYS');
RemoteExecNonQuery(win2export, 'UNLOCK TABLES');
end;
end;
barProgress.StepIt;
end;
end;
if tofile then
begin
f := InitFileStream('footer', f);
if f = nil then
begin
Screen.Cursor := crDefault;
Abort;
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, target_cliwa);
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, target_cliwa );
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.radioFileOrDirClick(Sender: TObject);
begin
validateRadioControls(Sender);
validateControls(Sender);
generateExampleSQL;
end;
procedure TExportSQLForm.fillcombo_anotherdb(Sender: TObject);
var
lastdb: WideString;
begin
comboOtherDatabase.Items := comboSelectDatabase.Items;
comboOtherDatabase.Items.delete(comboSelectDatabase.ItemIndex);
if comboOtherDatabase.ItemIndex = -1 then begin
lastdb := Utf8Decode(Mainform.GetRegValue(REGNAME_EXP_DESTDB, ''));
comboOtherDatabase.ItemIndex := comboOtherDatabase.Items.IndexOf(lastdb);
end;
if (comboOtherDatabase.ItemIndex = -1) and (comboOtherDatabase.Items.Count > 0) then
comboOtherDatabase.ItemIndex := 0;
end;
procedure TExportSQLForm.generateExampleSQL;
const
STR_DROP_DB = 'DROP DATABASE IF EXISTS <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 IF EXISTS <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);
const
EnabledColor = clWindow;
DisabledColor = clBtnFace;
var
ControlToFocus : TWinControl;
begin
// Disable all controls ...
EditFileName.Enabled := False;
EditFileName.Color := DisabledColor;
btnFileBrowse.Enabled := False;
EditDirectory.Enabled := False;
EditDirectory.Color := DisabledColor;
btnDirectoryBrowse.Enabled := False;
comboOtherDatabase.Enabled := False;
comboOtherDatabase.Color := DisabledColor;
comboOtherHost.Enabled := False;
comboOtherHost.Color := DisabledColor;
comboOtherHostDatabase.Enabled := False;
comboOtherHostDatabase.Color := DisabledColor;
// Silence compiler warning
ControlToFocus := EditFileName;
// ... and re-enable the selected controlset
if radioFile.Checked then begin
EditFileName.Enabled := True;
EditFileName.Color := EnabledColor;
btnFileBrowse.Enabled := True;
end else if radioDirectory.Checked then begin
EditDirectory.Enabled := True;
EditDirectory.Color := EnabledColor;
btnDirectoryBrowse.Enabled := True;
ControlToFocus := EditDirectory;
end else if radioOtherDatabase.Checked then begin
comboOtherDatabase.Enabled := True;
comboOtherDatabase.Color := EnabledColor;
ControlToFocus := comboOtherDatabase;
end else if radioOtherHost.Checked then begin
comboOtherHost.Enabled := True;
comboOtherHost.Color := EnabledColor;
comboOtherHostDatabase.Color := EnabledColor;
ControlToFocus := comboOtherHost;
end;
if ControlToFocus.CanFocus then
ControlToFocus.SetFocus;
// Disable target selection if exporting to known session.
comboTargetCompat.Enabled := radioFile.Checked or radioDirectory.Checked;
end;
procedure TExportSQLForm.validateControls(Sender: TObject);
begin
cbxDatabase.Enabled := cbxStructure.Checked and (radioFile.Checked or radioDirectory.Checked or radioOtherHost.Checked);
comboDatabase.Enabled := cbxDatabase.Enabled and cbxDatabase.Checked;
cbxTables.Enabled := cbxStructure.Checked;
comboTables.Enabled := cbxTables.Enabled and cbxTables.Checked;
comboData.Enabled := cbxData.Checked;
// Should possible be in validateRadioControls() but is dependent on properties decided above.
comboOtherHostDatabase.Enabled := not (cbxDatabase.Enabled and cbxDatabase.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 call change event
comboOtherHost.ItemIndex := 0;
comboOtherHost.OnSelect(comboOtherHost);
// 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(REGNAME_EXP_STRUCTURE, cbxStructure.Checked);
WriteBool(REGNAME_EXP_CREATEDB, cbxDatabase.Checked);
WriteBool(REGNAME_EXP_CREATETABLE, cbxTables.Checked);
WriteBool(REGNAME_EXP_DATA, cbxData.Checked);
WriteInteger(REGNAME_EXP_DBHOW, comboDatabase.ItemIndex);
WriteInteger(REGNAME_EXP_TABLESHOW, comboTables.ItemIndex);
WriteInteger(REGNAME_EXP_DATAHOW, comboData.ItemIndex);
WriteInteger(REGNAME_EXP_COMPAT, comboTargetCompat.ItemIndex);
WriteString(REGNAME_EXP_OUTFILE, EditFileName.Text);
WriteString(REGNAME_EXP_OUTDIR, EditDirectory.Text);
OutputTo := OUTPUT_FILE;
if radioDirectory.checked then
OutputTo := OUTPUT_DIR
else if radioOtherDatabase.checked then
OutputTo := OUTPUT_DB
else if radioOtherHost.checked then
OutputTo := OUTPUT_HOST;
WriteInteger(REGNAME_EXP_TARGET, OutputTo );
WriteString(REGNAME_EXP_DESTDB, Utf8Encode(comboOtherDatabase.Text));
WriteInteger(REGNAME_EXP_WINWIDTH, Width );
WriteInteger(REGNAME_EXP_WINHEIGHT, Height );
CloseKey();
Free;
end;
end;
{**
Browse for a directory
}
procedure TExportSQLForm.btnDirectoryBrowseClick(Sender: TObject);
var
Browse: TBrowseForFolder;
begin
// Avoid using platform specific SelectDirectory()
Browse := TBrowseForFolder.Create(Self);
Browse.Folder := EditDirectory.Text;
Browse.DialogCaption := 'Select output directory';
// Enable "Create new folder" button
Browse.BrowseOptions := Browse.BrowseOptions - [bifNoNewFolderButton] + [bifNewDialogStyle];
if Browse.Execute then
EditDirectory.Text := Browse.Folder;
end;
end.