Handle multiple queries in table editor's apply action. This way, special queries for edited foreign keys and dropping defaults are revealed in the "ALTER code" tab. Moved from ApplyModifications.

This commit is contained in:
Ansgar Becker
2011-02-19 08:22:17 +00:00
parent 7225c031e4
commit 06d7a97798

View File

@ -185,8 +185,8 @@ type
procedure ValidateIndexControls; procedure ValidateIndexControls;
procedure MoveFocusedIndexPart(NewIdx: Cardinal); procedure MoveFocusedIndexPart(NewIdx: Cardinal);
procedure ResetModificationFlags; procedure ResetModificationFlags;
function ComposeCreateStatement: String; function ComposeCreateStatement: TSQLBatch;
function ComposeAlterStatement: String; function ComposeAlterStatement: TSQLBatch;
procedure UpdateSQLcode; procedure UpdateSQLcode;
function CellEditingAllowed(Node: PVirtualNode; Column: TColumnIndex): Boolean; function CellEditingAllowed(Node: PVirtualNode; Column: TColumnIndex): Boolean;
procedure CalcMinColWidth; procedure CalcMinColWidth;
@ -361,39 +361,19 @@ end;
function TfrmTableEditor.ApplyModifications: TModalResult; function TfrmTableEditor.ApplyModifications: TModalResult;
var var
sql: String; Batch: TSQLBatch;
Query: TSQLSentence;
i: Integer; i: Integer;
Specs: TStringList;
Col: TTableColumn;
begin begin
// Create or alter table // Create or alter table
Result := mrOk; Result := mrOk;
Specs := TStringList.Create;
if DBObject.Name = '' then if DBObject.Name = '' then
sql := ComposeCreateStatement Batch := ComposeCreateStatement
else begin else
sql := ComposeAlterStatement; Batch := ComposeAlterStatement;
// Special case for altered foreign keys: These have to be dropped in a seperate query
// otherwise the server would return error 121 "Duplicate key on write or update"
// See also http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html :
// "You cannot add a foreign key and drop a foreign key in separate clauses of a single
// ALTER TABLE statement. Separate statements are required."
for i:=0 to FForeignKeys.Count-1 do begin
if FForeignKeys[i].Modified and (not FForeignKeys[i].Added) then
Specs.Add('DROP FOREIGN KEY '+QuoteIdent(FForeignKeys[i].OldKeyName));
end;
// Special case for removed default values on columns, which can neither be done in
// ALTER TABLE ... CHANGE COLUMN query, as there is no "no default" clause, nor by
// appending an ALTER COLUMN ... DROP DEFAULT, without getting an "unknown column" error
for Col in FColumns do begin
if (Col.FStatus = esModified) and (Col.DefaultType = cdtNothing) then
Specs.Add('ALTER '+QuoteIdent(Col.OldName)+' DROP DEFAULT');
end;
end;
try try
if Specs.Count > 0 then for Query in Batch do
MainForm.ActiveConnection.Query('ALTER TABLE '+QuoteIdent(DBObject.Name)+' '+ImplodeStr(', ', Specs)); MainForm.ActiveConnection.Query(Query.SQL);
MainForm.ActiveConnection.Query(sql);
tabALTERcode.TabVisible := DBObject.Name <> ''; tabALTERcode.TabVisible := DBObject.Name <> '';
if chkCharsetConvert.Checked then begin if chkCharsetConvert.Checked then begin
// Autoadjust column collations // Autoadjust column collations
@ -461,19 +441,53 @@ begin
end; end;
function TfrmTableEditor.ComposeAlterStatement: String; function TfrmTableEditor.ComposeAlterStatement: TSQLBatch;
var var
Specs: TStringList; Specs: TStringList;
ColSpec, IndexSQL: String; ColSpec, IndexSQL: String;
Query: TSQLSentence;
i: Integer; i: Integer;
Results: TMySQLQuery; Results: TMySQLQuery;
Col, PreviousCol: PTableColumn; Col, PreviousCol: PTableColumn;
Node: PVirtualNode; Node: PVirtualNode;
procedure AddQuery;
begin
if Specs.Count > 0 then begin
Query := TSQLSentence.Create;
Query.SQL := 'ALTER TABLE '+QuoteIdent(DBObject.Name) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs);
Query.SQL := Trim(Query.SQL);
Result.Add(Query);
Specs.Clear;
end;
end;
begin begin
// Compose ALTER query, called by buttons and for SQL code tab // Compose ALTER query, called by buttons and for SQL code tab
Mainform.ShowStatusMsg('Composing ALTER statement ...'); Mainform.ShowStatusMsg('Composing ALTER statement ...');
Result := TSQLBatch.Create;
Screen.Cursor := crHourglass; Screen.Cursor := crHourglass;
Specs := TStringList.Create; Specs := TStringList.Create;
// Special case for altered foreign keys: These have to be dropped in a seperate query
// otherwise the server would return error 121 "Duplicate key on write or update"
// See also http://dev.mysql.com/doc/refman/5.1/en/innodb-foreign-key-constraints.html :
// "You cannot add a foreign key and drop a foreign key in separate clauses of a single
// ALTER TABLE statement. Separate statements are required."
for i:=0 to FForeignKeys.Count-1 do begin
if FForeignKeys[i].Modified and (not FForeignKeys[i].Added) then
Specs.Add('DROP FOREIGN KEY '+QuoteIdent(FForeignKeys[i].OldKeyName));
end;
AddQuery;
// Special case for removed default values on columns, which can neither be done in
// ALTER TABLE ... CHANGE COLUMN query, as there is no "no default" clause, nor by
// appending an ALTER COLUMN ... DROP DEFAULT, without getting an "unknown column" error
for i:=0 to FColumns.Count-1 do begin
if (FColumns[i].FStatus = esModified) and (FColumns[i].DefaultType = cdtNothing) then
Specs.Add('ALTER '+QuoteIdent(FColumns[i].OldName)+' DROP DEFAULT');
end;
AddQuery;
if editName.Text <> DBObject.Name then if editName.Text <> DBObject.Name then
Specs.Add('RENAME TO ' + QuoteIdent(editName.Text)); Specs.Add('RENAME TO ' + QuoteIdent(editName.Text));
if memoComment.Tag = ModifiedFlag then if memoComment.Tag = ModifiedFlag then
@ -595,8 +609,7 @@ begin
Specs.Add('ADD '+FForeignKeys[i].SQLCode(True)); Specs.Add('ADD '+FForeignKeys[i].SQLCode(True));
end; end;
Result := 'ALTER TABLE '+QuoteIdent(DBObject.Name) + CRLF + #9 + ImplodeStr(',' + CRLF + #9, Specs); AddQuery;
Result := Trim(Result);
FreeAndNil(Specs); FreeAndNil(Specs);
Mainform.ShowStatusMsg; Mainform.ShowStatusMsg;
Mainform.ProgressBarStatus.Hide; Mainform.ProgressBarStatus.Hide;
@ -604,19 +617,23 @@ begin
end; end;
function TfrmTableEditor.ComposeCreateStatement: String; function TfrmTableEditor.ComposeCreateStatement: TSQLBatch;
var var
i, IndexCount: Integer; i, IndexCount: Integer;
Col: PTableColumn; Col: PTableColumn;
Node: PVirtualNode; Node: PVirtualNode;
tmp: String; tmp: String;
Query: TSQLSentence;
begin begin
// Compose CREATE query, called by buttons and for SQL code tab // Compose CREATE query, called by buttons and for SQL code tab
Result := 'CREATE TABLE '+QuoteIdent(editName.Text)+' ('+CRLF; Result := TSQLBatch.Create;
Query := TSQLSentence.Create;
Result.Add(Query);
Query.SQL := 'CREATE TABLE '+QuoteIdent(editName.Text)+' ('+CRLF;
Node := listColumns.GetFirst; Node := listColumns.GetFirst;
while Assigned(Node) do begin while Assigned(Node) do begin
Col := listColumns.GetNodeData(Node); Col := listColumns.GetNodeData(Node);
Result := Result + #9 + Col.SQLCode + ','+CRLF; Query.SQL := Query.SQL + #9 + Col.SQLCode + ','+CRLF;
Node := listColumns.GetNextSibling(Node); Node := listColumns.GetNextSibling(Node);
end; end;
@ -624,43 +641,43 @@ begin
for i:=0 to FKeys.Count-1 do begin for i:=0 to FKeys.Count-1 do begin
tmp := FKeys[i].SQLCode; tmp := FKeys[i].SQLCode;
if tmp <> '' then begin if tmp <> '' then begin
Result := Result + #9 + tmp + ','+CRLF; Query.SQL := Query.SQL + #9 + tmp + ','+CRLF;
Inc(IndexCount); Inc(IndexCount);
end; end;
end; end;
for i:=0 to FForeignKeys.Count-1 do for i:=0 to FForeignKeys.Count-1 do
Result := Result + #9 + FForeignKeys[i].SQLCode(True) + ','+CRLF; Query.SQL := Query.SQL + #9 + FForeignKeys[i].SQLCode(True) + ','+CRLF;
if Integer(listColumns.RootNodeCount) + IndexCount + FForeignKeys.Count > 0 then if Integer(listColumns.RootNodeCount) + IndexCount + FForeignKeys.Count > 0 then
Delete(Result, Length(Result)-2, 3); Delete(Query.SQL, Length(Query.SQL)-2, 3);
Result := Result + CRLF + ')' + CRLF; Query.SQL := Query.SQL + CRLF + ')' + CRLF;
if memoComment.Text <> '' then if memoComment.Text <> '' then
Result := Result + 'COMMENT='+esc(memoComment.Text) + CRLF; Query.SQL := Query.SQL + 'COMMENT='+esc(memoComment.Text) + CRLF;
if comboCollation.Text <> '' then if comboCollation.Text <> '' then
Result := Result + 'COLLATE='+esc(comboCollation.Text) + CRLF; Query.SQL := Query.SQL + 'COLLATE='+esc(comboCollation.Text) + CRLF;
if comboEngine.Text <> '' then begin if comboEngine.Text <> '' then begin
if MainForm.ActiveConnection.ServerVersionInt < 40018 then if MainForm.ActiveConnection.ServerVersionInt < 40018 then
Result := Result + 'TYPE='+comboEngine.Text + CRLF Query.SQL := Query.SQL + 'TYPE='+comboEngine.Text + CRLF
else else
Result := Result + 'ENGINE='+comboEngine.Text + CRLF; Query.SQL := Query.SQL + 'ENGINE='+comboEngine.Text + CRLF;
end; end;
if comboRowFormat.Tag = ModifiedFlag then if comboRowFormat.Tag = ModifiedFlag then
Result := Result + 'ROW_FORMAT='+comboRowFormat.Text + CRLF; Query.SQL := Query.SQL + 'ROW_FORMAT='+comboRowFormat.Text + CRLF;
if chkChecksum.Checked then if chkChecksum.Checked then
Result := Result + 'CHECKSUM='+IntToStr(Integer(chkChecksum.Checked)) + CRLF; Query.SQL := Query.SQL + 'CHECKSUM='+IntToStr(Integer(chkChecksum.Checked)) + CRLF;
if editAutoInc.Text <> '' then if editAutoInc.Text <> '' then
Result := Result + 'AUTO_INCREMENT='+editAutoInc.Text + CRLF; Query.SQL := Query.SQL + 'AUTO_INCREMENT='+editAutoInc.Text + CRLF;
if editAvgRowLen.Text <> '' then if editAvgRowLen.Text <> '' then
Result := Result + 'AVG_ROW_LENGTH='+editAvgRowLen.Text + CRLF; Query.SQL := Query.SQL + 'AVG_ROW_LENGTH='+editAvgRowLen.Text + CRLF;
if editMaxRows.Text <> '' then if editMaxRows.Text <> '' then
Result := Result + 'MAX_ROWS='+editMaxRows.Text + CRLF; Query.SQL := Query.SQL + 'MAX_ROWS='+editMaxRows.Text + CRLF;
if memoUnionTables.Enabled and (memoUnionTables.Text <> '') then if memoUnionTables.Enabled and (memoUnionTables.Text <> '') then
Result := Result + 'UNION=('+memoUnionTables.Text+')' + CRLF; Query.SQL := Query.SQL + 'UNION=('+memoUnionTables.Text+')' + CRLF;
if comboInsertMethod.Enabled and (comboInsertMethod.Text <> '') then if comboInsertMethod.Enabled and (comboInsertMethod.Text <> '') then
Result := Result + 'INSERT_METHOD='+comboInsertMethod.Text + CRLF; Query.SQL := Query.SQL + 'INSERT_METHOD='+comboInsertMethod.Text + CRLF;
Result := Trim(Result); Query.SQL := Trim(Query.SQL);
end; end;
@ -1723,18 +1740,23 @@ end;
procedure TfrmTableEditor.UpdateSQLcode; procedure TfrmTableEditor.UpdateSQLcode;
var var
OldTopLine: Integer; OldTopLine: Integer;
Query: TSQLSentence;
begin begin
if (PageControlMain.ActivePage = tabALTERCode) and (not AlterCodeValid) then begin if (PageControlMain.ActivePage = tabALTERCode) and (not AlterCodeValid) then begin
SynMemoALTERcode.BeginUpdate; SynMemoALTERcode.BeginUpdate;
OldTopLine := SynMemoALTERcode.TopLine; OldTopLine := SynMemoALTERcode.TopLine;
SynMemoALTERcode.Text := ComposeAlterStatement; SynMemoALTERcode.Clear;
for Query in ComposeAlterStatement do
SynMemoALTERcode.Text := SynMemoALTERcode.Text + Query.SQL + ';' + CRLF;
SynMemoALTERcode.TopLine := OldTopLine; SynMemoALTERcode.TopLine := OldTopLine;
SynMemoALTERcode.EndUpdate; SynMemoALTERcode.EndUpdate;
AlterCodeValid := True; AlterCodeValid := True;
end else if (PageControlMain.ActivePage = tabCREATECode) and (not CreateCodeValid) then begin end else if (PageControlMain.ActivePage = tabCREATECode) and (not CreateCodeValid) then begin
SynMemoCREATEcode.BeginUpdate; SynMemoCREATEcode.BeginUpdate;
OldTopLine := SynMemoCREATEcode.TopLine; OldTopLine := SynMemoCREATEcode.TopLine;
SynMemoCREATEcode.Text := ComposeCreateStatement; SynMemoCREATEcode.Clear;
for Query in ComposeCreateStatement do
SynMemoCREATEcode.Text := SynMemoCREATEcode.Text + Query.SQL + ';' + CRLF;
SynMemoCREATEcode.TopLine := OldTopLine; SynMemoCREATEcode.TopLine := OldTopLine;
SynMemoCREATEcode.EndUpdate; SynMemoCREATEcode.EndUpdate;
CreateCodeValid := True; CreateCodeValid := True;