unit copytable; // ------------------------------------- // Copy table // ------------------------------------- interface uses Windows, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, CheckLst, WideStrings, mysql_connection; type TCopyTableForm = class(TForm) editNewTablename: TEdit; lblNewTablename: TLabel; radioStructure: TRadioButton; radioStructureAndData: TRadioButton; CheckListBoxFields: TCheckListBox; CheckBoxWithAllFields: TCheckBox; ButtonCancel: TButton; CheckBoxWithIndexes: TCheckBox; lblTargetDB: TLabel; ComboSelectDatabase: TComboBox; ButtonOK: TButton; chkSelectAll: TCheckBox; procedure radioStructureClick(Sender: TObject); procedure radioStructureAndDataClick(Sender: TObject); procedure CheckBoxWithAllFieldsClick(Sender: TObject); procedure editNewTablenameChange(Sender: TObject); procedure FormShow(Sender: TObject); procedure ButtonOKClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure CheckListBoxFieldsClickCheck(Sender: TObject); procedure chkSelectAllClick(Sender: TObject); private { Private declarations } oldTableName : String; public { Public declarations } end; function CopyTableWindow(AOwner: TComponent): Boolean; implementation uses helpers, main; {$R *.DFM} {** Create form on demand @param TComponent Owner of form (should be calling form) @return Boolean Form closed using modalresult mrOK } function CopyTableWindow(AOwner: TComponent): Boolean; var f : TCopyTableForm; begin f := TCopyTableForm.Create(AOwner); Result := (f.ShowModal=mrOK); FreeAndNil(f); end; procedure TCopyTableForm.radioStructureClick(Sender: TObject); begin radioStructureAndData.Checked := not radioStructure.Checked; end; procedure TCopyTableForm.radioStructureAndDataClick(Sender: TObject); begin radioStructure.Checked := not radioStructureAndData.Checked; end; procedure TCopyTableForm.CheckBoxWithAllFieldsClick(Sender: TObject); begin CheckListBoxFields.Enabled := not CheckBoxWithAllFields.Checked; chkSelectAll.Enabled := CheckListBoxFields.Enabled; end; procedure TCopyTableForm.editNewTablenameChange(Sender: TObject); begin // validate tablename try ensureValidIdentifier( editNewTablename.Text ); editNewTablename.Font.Color := clWindowText; editNewTablename.Color := clWindow; // Enable "OK"-Button if we have a valid name ButtonOK.Enabled := True; except editNewTablename.Font.Color := clRed; editNewTablename.Color := clYellow; ButtonOK.Enabled := False; end; end; procedure TCopyTableForm.FormCreate(Sender: TObject); begin InheritFont(Font); end; procedure TCopyTableForm.FormShow(Sender: TObject); var i : Integer; struc_data : Byte; NodeData: PVTreeData; begin if Mainform.DBtree.Focused then oldTableName := Mainform.SelectedTable.Name else begin NodeData := Mainform.ListTables.GetNodeData(Mainform.ListTables.FocusedNode); oldTableName := NodeData.Captions[0]; end; editNewTablename.Text := oldTableName + '_copy'; editNewTablename.SetFocus; lblNewTablename.Caption := 'Copy ''' + oldTableName + ''' to new table:'; // Select TargetDatabase ComboSelectDatabase.Items.Clear; ComboSelectDatabase.Items.Assign(Mainform.Databases); ComboSelectDatabase.ItemIndex := ComboSelectDatabase.Items.IndexOf( Mainform.ActiveDatabase ); if comboSelectDatabase.ItemIndex = -1 then comboSelectDatabase.ItemIndex := 0; // fill columns: CheckListBoxFields.Items.Text := Mainform.Connection.GetCol('SHOW FIELDS FROM ' + mainform.mask(oldTableName)).Text; // select all: for i:=0 to CheckListBoxFields.Items.Count-1 do CheckListBoxFields.checked[i] := true; {*** restore last settings @see feature #1647058 } struc_data := GetRegValue( REGNAME_COPYTABLE_STRUCDATA, DEFAULT_COPYTABLE_STRUCDATA ); case struc_data of REGVAL_COPYTABLE_STRUCTURE: radioStructure.Checked := true; REGVAL_COPYTABLE_STRUCTURE_AND_DATA: radioStructureAndData.Checked := true; end; CheckBoxWithIndexes.Checked := GetRegValue( REGNAME_COPYTABLE_INDEXES, CheckBoxWithIndexes.Checked ); CheckBoxWithAllFields.Checked := GetRegValue( REGNAME_COPYTABLE_ALLFIELDS, CheckBoxWithAllFields.Checked ); // Ensure CheckListBoxFields + chkSelectAll are en/disabled CheckBoxWithAllFieldsClick(Sender); // Ensure chkSelectAll shows its correct state CheckListBoxFieldsClickCheck(Sender); end; procedure TCopyTableForm.ButtonOKClick(Sender: TObject); var strquery : String; i,which,k : Integer; keylist : Array of TMyKey; keystr : String; notnull, default : String; Results : TMySQLQuery; isFulltext : Boolean; struc_data : Byte; Fixes : TWideStringlist; DBObjects : TDBObjectList; begin // copy table! // store settings if radioStructure.Checked then struc_data := REGVAL_COPYTABLE_STRUCTURE else struc_data := REGVAL_COPYTABLE_STRUCTURE_AND_DATA; OpenRegistry; MainReg.WriteInteger( REGNAME_COPYTABLE_STRUCDATA, struc_data ); MainReg.WriteBool( REGNAME_COPYTABLE_INDEXES, CheckBoxWithIndexes.Checked ); MainReg.WriteBool( REGNAME_COPYTABLE_ALLFIELDS, CheckBoxWithAllFields.Checked ); strquery := 'CREATE TABLE ' + mainform.mask(ComboSelectDatabase.Text) + '.' + mainform.mask(editNewTablename.Text) + ' '; // keys > if CheckBoxWithIndexes.Checked then begin Results := Mainform.Connection.GetResults('SHOW KEYS FROM ' + mainform.mask(oldtablename)); setLength(keylist, 0); keystr := ''; for i:=1 to Results.RecordCount do begin which := -1; for k:=0 to length(keylist)-1 do begin if keylist[k].Name = Results.Col(2) then // keyname exists! which := k; end; if which = -1 then begin setlength(keylist, length(keylist)+1); which := high(keylist); keylist[which].Columns := TWideStringList.Create; keylist[which].SubParts := TWideStringList.Create; // set properties for new key if Mainform.Connection.ServerVersionInt < 40002 then isFulltext := Results.Col('Comment') = 'FULLTEXT' else isFulltext := Results.Col('Index_type') = 'FULLTEXT'; keylist[which].Name := Results.Col(2); if Results.Col(2) = 'PRIMARY' then keylist[which]._type := 'PRIMARY' else if isFulltext then keylist[which]._type := 'FULLTEXT' else if Results.Col(1) = '1' then keylist[which]._type := '' else if Results.Col(1) = '0' then keylist[which]._type := 'UNIQUE'; end; // add column keylist[which].Columns.add(Results.Col('Column_name')); keylist[which].SubParts.add(Results.Col('Sub_part')); Results.Next; end; FreeAndNil(Results); for k:=0 to high(keylist) do begin if k > 0 then keystr := keystr + ','; if keylist[k].Name = 'PRIMARY' then keystr := keystr + ' PRIMARY KEY (' else keystr := keystr + ' ' + keylist[k]._type + ' KEY ' + Mainform.Mask(keylist[k].Name) + ' ('; for i := 0 to keylist[k].Columns.count - 1 do begin if i > 0 then keystr := keystr + ', '; keystr := keystr + mainform.mask(keylist[k].Columns[i]); if keylist[k].SubParts[i] <> '' then keystr := keystr + '(' + keylist[k].SubParts[i] + ')'; end; keystr := keystr + ')'; end; if keystr<> '' then strquery := strquery + '(' + keystr + ')' end; // < keys // Add collation and engine clauses DBObjects := Mainform.Connection.GetDBObjects(Mainform.ActiveDatabase); for i:=0 to DBObjects.Count-1 do begin if DBObjects[i].Name = oldTableName then begin if DBObjects[i].Collation <> '' then strquery := strquery + ' COLLATE ' + DBObjects[i].Collation; if DBObjects[i].Engine <> '' then strquery := strquery + ' ENGINE=' + DBObjects[i].Engine; strquery := strquery + ' COMMENT=' + esc(DBObjects[i].Comment); break; end; end; strquery := strquery + ' SELECT'; // which fields? if CheckBoxWithAllFields.Checked then strquery := strquery + ' *' else begin for i:=0 to CheckListBoxFields.Items.Count-1 do if CheckListBoxFields.Checked[i] then strquery := strquery + ' ' + mainform.mask(CheckListBoxFields.Items[i]) + ','; delete(strquery, length(strquery), 1); end; strquery := strquery + ' FROM ' + mainform.mask(oldTableName); // what? if radioStructure.Checked then strquery := strquery + ' WHERE 1 = 0'; try Mainform.Connection.Query(strquery, False); // Fix missing auto_increment property and CURRENT_TIMESTAMP defaults in new table Results := Mainform.Connection.GetResults('SHOW FIELDS FROM ' + mainform.mask(oldtablename)); Fixes := TWideStringlist.Create; while not Results.Eof do begin notnull := ''; if Results.Col('Null') = '' then notnull := 'NOT NULL'; default := ''; if Results.Col('Default') <> '' then begin default := 'DEFAULT '; if Results.Col('Default') = 'CURRENT_TIMESTAMP' then default := default + Results.Col('Default') else default := default + esc(Results.Col('Default')); end; if (CheckBoxWithIndexes.Checked and (Results.Col('Extra') = 'auto_increment')) or (Results.Col('Default') = 'CURRENT_TIMESTAMP') then begin Fixes.Add('CHANGE '+Mainform.mask(Results.Col('Field'))+' '+ Mainform.mask(Results.Col('Field'))+' '+ Results.Col('Type')+' '+default+' '+notnull+' '+Results.Col('Extra')); end; Results.Next; end; if Fixes.Count > 0 then begin Mainform.Connection.Query('ALTER TABLE '+Mainform.mask(ComboSelectDatabase.Text) + '.'+Mainform.mask(editNewTablename.Text)+ ' '+ ImplodeStr(', ', Fixes) ); end; Results.Free; FreeAndNil(Fixes); Mainform.actRefresh.Execute; except on E:Exception do begin MessageDlg(E.Message, mtError, [mbOk], 0); ModalResult := mrNone; end; end; end; procedure TCopyTableForm.CheckListBoxFieldsClickCheck(Sender: TObject); var i : Integer; allSelected, noneSelected : Boolean; begin allselected := True; noneSelected := True; for i := 0 to CheckListBoxFields.Items.Count - 1 do begin if CheckListBoxFields.Checked[i] then noneSelected := False else allSelected := False; end; if noneSelected then chkSelectAll.State := cbUnchecked else if allSelected then chkSelectAll.State := cbChecked else chkSelectAll.State := cbGrayed; end; procedure TCopyTableForm.chkSelectAllClick(Sender: TObject); begin // Avoid executing when checkbox was toggled by code (see proc below) if (Sender as TCheckBox).Focused then ToggleCheckListBox( CheckListBoxFields, (Sender as TCheckBox).Checked ); end; end.