mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-26 11:17:57 +08:00
Detect all column properties from a SHOW CREATE TABLE result, instead of SHOW FULL COLUMNS, so the missing ON UPDATE CURRENT_TIMESTAMP can be taken into account. The new parsing part in is probably slightly unstable yet, although tested on 4.0, 4.1 and 5.1 servers. Fixes issue #1133.
This commit is contained in:
@ -152,7 +152,7 @@ type
|
|||||||
property OnButtonClick: TButtonClickEvent read FOnButtonClick write FOnButtonClick;
|
property OnButtonClick: TButtonClickEvent read FOnButtonClick write FOnButtonClick;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TColumnDefaultType = (cdtText, cdtNull, cdtCurTS, cdtAutoInc);
|
TColumnDefaultType = (cdtText, cdtTextUpdateTS, cdtNull, cdtNullUpdateTS, cdtCurTS, cdtCurTSUpdateTS, cdtAutoInc);
|
||||||
TColumnDefaultEditorLink = class(TInterfacedObject, IVTEditLink)
|
TColumnDefaultEditorLink = class(TInterfacedObject, IVTEditLink)
|
||||||
private
|
private
|
||||||
FTree: TCustomVirtualStringTree;
|
FTree: TCustomVirtualStringTree;
|
||||||
@ -161,6 +161,7 @@ type
|
|||||||
FStopping: Boolean;
|
FStopping: Boolean;
|
||||||
FPanel: TPanel;
|
FPanel: TPanel;
|
||||||
FRadioText, FRadioNULL, FRadioCurTS, FRadioAutoInc: TRadioButton;
|
FRadioText, FRadioNULL, FRadioCurTS, FRadioAutoInc: TRadioButton;
|
||||||
|
FCheckCurTS: TCheckbox;
|
||||||
FMemoText: TTNTMemo;
|
FMemoText: TTNTMemo;
|
||||||
FBtnOK, FBtnCancel: TButton;
|
FBtnOK, FBtnCancel: TButton;
|
||||||
procedure RadioClick(Sender: TObject);
|
procedure RadioClick(Sender: TObject);
|
||||||
@ -183,6 +184,7 @@ type
|
|||||||
|
|
||||||
|
|
||||||
function GetColumnDefaultType(var Text: WideString): TColumnDefaultType;
|
function GetColumnDefaultType(var Text: WideString): TColumnDefaultType;
|
||||||
|
function GetColumnDefaultClause(DefaultType: TColumnDefaultType; Text: WideString): WideString;
|
||||||
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
@ -1033,7 +1035,7 @@ var
|
|||||||
NodeText: WideString;
|
NodeText: WideString;
|
||||||
Default: TColumnDefaultType;
|
Default: TColumnDefaultType;
|
||||||
const
|
const
|
||||||
m = 5;
|
m = 3;
|
||||||
begin
|
begin
|
||||||
Ftree := Tree as TCustomVirtualStringTree;
|
Ftree := Tree as TCustomVirtualStringTree;
|
||||||
FNode := Node;
|
FNode := Node;
|
||||||
@ -1084,9 +1086,17 @@ begin
|
|||||||
FRadioCurTS.OnClick := RadioClick;
|
FRadioCurTS.OnClick := RadioClick;
|
||||||
FRadioCurTS.Caption := 'CURRENT_TIMESTAMP';
|
FRadioCurTS.Caption := 'CURRENT_TIMESTAMP';
|
||||||
|
|
||||||
|
FCheckCurTS := TCheckbox.Create(FPanel);
|
||||||
|
FCheckCurTS.Parent := FPanel;
|
||||||
|
FCheckCurTS.Top := FRadioCurTS.Top + FRadioCurTS.Height + m;
|
||||||
|
FCheckCurTS.Left := m;
|
||||||
|
FCheckCurTS.Width := FCheckCurTS.Parent.Width - 2 * FCheckCurTS.Left;
|
||||||
|
FCheckCurTS.OnClick := RadioClick;
|
||||||
|
FCheckCurTS.Caption := 'ON UPDATE CURRENT_TIMESTAMP';
|
||||||
|
|
||||||
FRadioAutoInc := TRadioButton.Create(FPanel);
|
FRadioAutoInc := TRadioButton.Create(FPanel);
|
||||||
FRadioAutoInc.Parent := FPanel;
|
FRadioAutoInc.Parent := FPanel;
|
||||||
FRadioAutoInc.Top := FRadioCurTS.Top + FRadioCurTS.Height + m;
|
FRadioAutoInc.Top := FCheckCurTS.Top + FCheckCurTS.Height + m;
|
||||||
FRadioAutoInc.Left := m;
|
FRadioAutoInc.Left := m;
|
||||||
FRadioAutoInc.Width := FRadioAutoInc.Parent.Width - 2 * FRadioAutoInc.Left;
|
FRadioAutoInc.Width := FRadioAutoInc.Parent.Width - 2 * FRadioAutoInc.Left;
|
||||||
FRadioAutoInc.OnClick := RadioClick;
|
FRadioAutoInc.OnClick := RadioClick;
|
||||||
@ -1115,19 +1125,22 @@ begin
|
|||||||
FMemoText.Anchors := [akLeft, akTop, akRight, akBottom];
|
FMemoText.Anchors := [akLeft, akTop, akRight, akBottom];
|
||||||
FRadioNull.Anchors := [akLeft, akBottom, akRight];
|
FRadioNull.Anchors := [akLeft, akBottom, akRight];
|
||||||
FRadioCurTS.Anchors := [akLeft, akBottom, akRight];
|
FRadioCurTS.Anchors := [akLeft, akBottom, akRight];
|
||||||
|
FCheckCurTS.Anchors := [akLeft, akBottom, akRight];
|
||||||
FRadioAutoInc.Anchors := [akLeft, akBottom, akRight];
|
FRadioAutoInc.Anchors := [akLeft, akBottom, akRight];
|
||||||
FBtnOk.Anchors := [akBottom, akRight];
|
FBtnOk.Anchors := [akBottom, akRight];
|
||||||
FBtnCancel.Anchors := FBtnOk.Anchors;
|
FBtnCancel.Anchors := FBtnOk.Anchors;
|
||||||
|
FPanel.Width := GetParentForm(FPanel).Canvas.TextWidth(FCheckCurTS.Caption) + 2*FCheckCurTS.Left + 16;
|
||||||
|
|
||||||
case DefaultType of
|
case DefaultType of
|
||||||
cdtText: begin
|
cdtText, cdtTextUpdateTS: begin
|
||||||
FRadioText.Checked := True;
|
FRadioText.Checked := True;
|
||||||
FMemoText.Text := DefaultText;
|
FMemoText.Text := DefaultText;
|
||||||
end;
|
end;
|
||||||
cdtNull: FRadioNull.Checked := True;
|
cdtNull, cdtNullUpdateTS: FRadioNull.Checked := True;
|
||||||
cdtCurTS: FRadioCurTS.Checked := True;
|
cdtCurTS, cdtCurTSUpdateTS: FRadioCurTS.Checked := True;
|
||||||
cdtAutoInc: FRadioAutoInc.Checked := True;
|
cdtAutoInc: FRadioAutoInc.Checked := True;
|
||||||
end;
|
end;
|
||||||
|
FCheckCurTS.Checked := DefaultType in [cdtTextUpdateTS, cdtNullUpdateTS, cdtCurTSUpdateTS];
|
||||||
Result := True;
|
Result := True;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -1188,19 +1201,36 @@ end;
|
|||||||
|
|
||||||
function TColumnDefaultEditorLink.EndEdit: Boolean; stdcall;
|
function TColumnDefaultEditorLink.EndEdit: Boolean; stdcall;
|
||||||
var
|
var
|
||||||
newtext: WideString;
|
newText: WideString;
|
||||||
|
newDefaultType: TColumnDefaultType;
|
||||||
begin
|
begin
|
||||||
Result := not FStopping;
|
Result := not FStopping;
|
||||||
if Result then begin
|
if Result then begin
|
||||||
FStopping := True;
|
FStopping := True;
|
||||||
if FRadioText.Checked then
|
if FRadioText.Checked and FCheckCurTS.Checked then
|
||||||
newText := IntToStr(Integer(cdtText)) + FMemoText.Text
|
newDefaultType := cdtTextUpdateTS
|
||||||
|
else if FRadioText.Checked then
|
||||||
|
newDefaultType := cdtText
|
||||||
|
else if FRadioNull.Checked and FCheckCurTS.Checked then
|
||||||
|
newDefaultType := cdtNullUpdateTS
|
||||||
else if FRadioNull.Checked then
|
else if FRadioNull.Checked then
|
||||||
newText := IntToStr(Integer(cdtNull)) + 'NULL'
|
newDefaultType := cdtNull
|
||||||
|
else if FRadioCurTS.Checked and FCheckCurTS.Checked then
|
||||||
|
newDefaultType := cdtCurTSUpdateTS
|
||||||
else if FRadioCurTS.Checked then
|
else if FRadioCurTS.Checked then
|
||||||
newText := IntToStr(Integer(cdtCurTS)) + 'CURRENT_TIMESTAMP'
|
newDefaultType := cdtCurTS
|
||||||
|
else if FRadioAutoInc.Checked then
|
||||||
|
newDefaultType := cdtAutoInc
|
||||||
else
|
else
|
||||||
newText := IntToStr(Integer(cdtAutoInc)) + 'AUTO_INCREMENT';
|
newDefaultType := cdtText;
|
||||||
|
|
||||||
|
case newDefaultType of
|
||||||
|
cdtText, cdtTextUpdateTS: newText := FMemoText.Text;
|
||||||
|
cdtNull, cdtNullUpdateTS: newText := 'NULL';
|
||||||
|
cdtCurTS, cdtCurTSUpdateTS: newText := 'CURRENT_TIMESTAMP';
|
||||||
|
cdtAutoInc: newText := 'AUTO_INCREMENT';
|
||||||
|
end;
|
||||||
|
newText := IntToStr(Integer(newDefaultType)) + newText;
|
||||||
if newtext <> IntToStr(Integer(DefaultType)) + DefaultText then
|
if newtext <> IntToStr(Integer(DefaultType)) + DefaultText then
|
||||||
FTree.Text[FNode, FColumn] := newtext;
|
FTree.Text[FNode, FColumn] := newtext;
|
||||||
if FTree.CanFocus then
|
if FTree.CanFocus then
|
||||||
@ -1243,4 +1273,18 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function GetColumnDefaultClause(DefaultType: TColumnDefaultType; Text: WideString): WideString;
|
||||||
|
begin
|
||||||
|
case DefaultType of
|
||||||
|
cdtText: Result := ' DEFAULT '+esc(Text);
|
||||||
|
cdtTextUpdateTS: Result := ' DEFAULT '+esc(Text)+' ON UPDATE CURRENT_TIMESTAMP';
|
||||||
|
cdtNull: Result := ' DEFAULT NULL';
|
||||||
|
cdtNullUpdateTS: Result := ' DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP';
|
||||||
|
cdtCurTS: Result := ' DEFAULT CURRENT_TIMESTAMP';
|
||||||
|
cdtCurTSUpdateTS: Result := ' DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP';
|
||||||
|
cdtAutoInc: Result := ' AUTO_INCREMENT';
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
@ -231,8 +231,12 @@ var
|
|||||||
ds: TDataset;
|
ds: TDataset;
|
||||||
Props: TWideStringlist;
|
Props: TWideStringlist;
|
||||||
IndexType: String;
|
IndexType: String;
|
||||||
LastKeyName, CreateTable, engine: WideString;
|
LastKeyName, CreateTable, engine, ColSpec: WideString;
|
||||||
rx: TRegExpr;
|
rx, rxCol: TRegExpr;
|
||||||
|
i: Integer;
|
||||||
|
InLiteral: Boolean;
|
||||||
|
ColDefaultType: TColumnDefaultType;
|
||||||
|
ColDefaultText: WideString;
|
||||||
begin
|
begin
|
||||||
SetStatus('Initializing ...');
|
SetStatus('Initializing ...');
|
||||||
FLoaded := False;
|
FLoaded := False;
|
||||||
@ -288,37 +292,123 @@ begin
|
|||||||
memoUnionTables.Text := rx.Match[1]
|
memoUnionTables.Text := rx.Match[1]
|
||||||
else
|
else
|
||||||
memoUnionTables.Clear;
|
memoUnionTables.Clear;
|
||||||
FreeAndNil(rx);
|
|
||||||
|
|
||||||
ds := Mainform.GetResults('SHOW FULL COLUMNS FROM '+Mainform.mask(FAlterTableName));
|
|
||||||
listColumns.BeginUpdate;
|
listColumns.BeginUpdate;
|
||||||
while not ds.Eof do begin
|
rx.ModifierS := False;
|
||||||
|
rx.Expression := '\s+`([^`]+)`\s(\w+)(.+)';
|
||||||
|
rxCol := TRegExpr.Create;
|
||||||
|
rxCol.ModifierI := True;
|
||||||
|
if rx.Exec(CreateTable) then while true do begin
|
||||||
Props := TWideStringlist.Create;
|
Props := TWideStringlist.Create;
|
||||||
Props.OnChange := ColumnsChange;
|
Props.OnChange := ColumnsChange;
|
||||||
Props.Add(UpperCase(GetFirstWord(ds.FieldByName('Type').AsString)));
|
// Create needed number of property columns
|
||||||
Props.Add(getEnumValues(ds.FieldByName('Type').AsWideString));
|
Props.CommaText := ',,,,,,';
|
||||||
Props.Add(BoolToStr(Pos('unsigned', ds.FieldByName('Type').AsWideString) > 0));
|
ColSpec := rx.Match[3];
|
||||||
Props.Add(BoolToStr(ds.FieldByName('Null').AsString = 'YES'));
|
|
||||||
if ds.FieldByName('Extra').AsWideString = 'auto_increment' then
|
// Strip trailing comma
|
||||||
Props.Add(IntToStr(Integer(cdtAutoInc))+'AUTO_INCREMENT')
|
if ColSpec[Length(ColSpec)] = ',' then
|
||||||
else if ds.FieldByName('Default').IsNull then
|
Delete(ColSpec, Length(ColSpec), 1);
|
||||||
Props.Add(IntToStr(Integer(cdtNull))+'NULL')
|
|
||||||
else if ds.FieldByName('Default').AsWideString = 'CURRENT_TIMESTAMP' then
|
// Datatype
|
||||||
Props.Add(IntToStr(Integer(cdtCurTS))+ds.FieldByName('Default').AsWideString)
|
Props[0] := UpperCase(rx.Match[2]);
|
||||||
else
|
|
||||||
Props.Add(IntToStr(Integer(cdtText))+ds.FieldByName('Default').AsWideString);
|
// Length / Set
|
||||||
if ds.FindField('Comment') <> nil then
|
// Various datatypes, e.g. BLOBs, don't have any length property
|
||||||
Props.Add(ds.FieldByName('Comment').AsWideString)
|
InLiteral := False;
|
||||||
else
|
if (ColSpec <> '') and (ColSpec[1] = '(') then begin
|
||||||
Props.Add('');
|
for i:=2 to Length(ColSpec) do begin
|
||||||
if (ds.FindField('Collation') <> nil) and (ds.FieldByName('Collation').AsString <> 'NULL') then
|
if (ColSpec[i] = ')') and (not InLiteral) then
|
||||||
Props.Add(ds.FieldByName('Collation').AsString)
|
break;
|
||||||
else
|
if ColSpec[i] = '''' then
|
||||||
Props.Add('');
|
InLiteral := not InLiteral;
|
||||||
Columns.AddObject(ds.FieldByName('Field').AsWideString, Props);
|
end;
|
||||||
ds.Next;
|
Props[1] := Copy(ColSpec, 2, i-2);
|
||||||
|
Delete(ColSpec, 1, i);
|
||||||
|
end;
|
||||||
|
ColSpec := Trim(ColSpec);
|
||||||
|
|
||||||
|
// Unsigned
|
||||||
|
if UpperCase(Copy(ColSpec, 1, 8)) = 'UNSIGNED' then begin
|
||||||
|
Props[2] := BoolToStr(True);
|
||||||
|
Delete(ColSpec, 1, 9);
|
||||||
|
end else
|
||||||
|
Props[2] := BoolToStr(False);
|
||||||
|
|
||||||
|
// Collation
|
||||||
|
rxCol.Expression := '^(CHARACTER SET \w+)?\s+COLLATE (\w+)\b';
|
||||||
|
if rxCol.Exec(ColSpec) then begin
|
||||||
|
Props[6] := rxCol.Match[2];
|
||||||
|
Delete(ColSpec, 1, rxCol.MatchLen[0]+1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
// Allow NULL
|
||||||
|
if UpperCase(Copy(ColSpec, 1, 8)) = 'NOT NULL' then begin
|
||||||
|
Props[3] := BoolToStr(False);
|
||||||
|
Delete(ColSpec, 1, 9);
|
||||||
|
end else
|
||||||
|
Props[3] := BoolToStr(True);
|
||||||
|
|
||||||
|
// Default value
|
||||||
|
ColDefaultType := cdtNull;
|
||||||
|
ColDefaultText := 'NULL';
|
||||||
|
if UpperCase(Copy(ColSpec, 1, 14)) = 'AUTO_INCREMENT' then begin
|
||||||
|
ColDefaultType := cdtAutoInc;
|
||||||
|
ColDefaultText := 'AUTO_INCREMENT';
|
||||||
|
Delete(ColSpec, 1, 15);
|
||||||
|
end else if UpperCase(Copy(ColSpec, 1, 8)) = 'DEFAULT ' then begin
|
||||||
|
Delete(ColSpec, 1, 8);
|
||||||
|
if UpperCase(Copy(ColSpec, 1, 4)) = 'NULL' then begin
|
||||||
|
ColDefaultType := cdtNull;
|
||||||
|
ColDefaultText := 'NULL';
|
||||||
|
Delete(ColSpec, 1, 5);
|
||||||
|
end else if UpperCase(Copy(ColSpec, 1, 17)) = 'CURRENT_TIMESTAMP' then begin
|
||||||
|
ColDefaultType := cdtCurTS;
|
||||||
|
ColDefaultText := 'CURRENT_TIMESTAMP';
|
||||||
|
Delete(ColSpec, 1, 18);
|
||||||
|
end else if ColSpec[1] = '''' then begin
|
||||||
|
InLiteral := True;
|
||||||
|
for i:=2 to Length(ColSpec) do begin
|
||||||
|
if ColSpec[i] = '''' then
|
||||||
|
InLiteral := not InLiteral
|
||||||
|
else if not InLiteral then
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
ColDefaultType := cdtText;
|
||||||
|
ColDefaultText := Copy(ColSpec, 2, i-3);
|
||||||
|
Delete(ColSpec, 1, i);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if Copy(ColSpec, 1, 27) = 'ON UPDATE CURRENT_TIMESTAMP' then begin
|
||||||
|
// Adjust default type
|
||||||
|
case ColDefaultType of
|
||||||
|
cdtText: ColDefaultType := cdtTextUpdateTS;
|
||||||
|
cdtNull: ColDefaultType := cdtNullUpdateTS;
|
||||||
|
cdtCurTS: ColDefaultType := cdtCurTSUpdateTS;
|
||||||
|
end;
|
||||||
|
Delete(ColSpec, 1, 28);
|
||||||
|
end;
|
||||||
|
Props[4] := IntToStr(Integer(ColDefaultType)) + ColDefaultText;
|
||||||
|
|
||||||
|
// Comment
|
||||||
|
if UpperCase(Copy(ColSpec, 1, 9)) = 'COMMENT ''' then begin
|
||||||
|
InLiteral := True;
|
||||||
|
for i:=10 to Length(ColSpec) do begin
|
||||||
|
if ColSpec[i] = '''' then
|
||||||
|
InLiteral := not InLiteral
|
||||||
|
else if not InLiteral then
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
Props[5] := Copy(ColSpec, 10, i-11);
|
||||||
|
Delete(ColSpec, 1, i);
|
||||||
|
end;
|
||||||
|
|
||||||
|
Columns.AddObject(rx.Match[1], Props);
|
||||||
|
if not rx.ExecNext then
|
||||||
|
break;
|
||||||
end;
|
end;
|
||||||
FreeAndNil(ds);
|
FreeAndNil(rx);
|
||||||
|
FreeAndNil(rxCol);
|
||||||
listColumns.EndUpdate;
|
listColumns.EndUpdate;
|
||||||
|
|
||||||
ds := Mainform.GetResults('SHOW KEYS FROM '+Mainform.mask(FAlterTableName));
|
ds := Mainform.GetResults('SHOW KEYS FROM '+Mainform.mask(FAlterTableName));
|
||||||
@ -491,12 +581,7 @@ begin
|
|||||||
if Props[4] <> '' then begin
|
if Props[4] <> '' then begin
|
||||||
DefaultText := Props[4];
|
DefaultText := Props[4];
|
||||||
DefaultType := GetColumnDefaultType(DefaultText);
|
DefaultType := GetColumnDefaultType(DefaultText);
|
||||||
case DefaultType of
|
ColSpec := ColSpec + ' ' + GetColumnDefaultClause(DefaultType, DefaultText);
|
||||||
cdtText: ColSpec := ColSpec + ' DEFAULT '+esc(DefaultText);
|
|
||||||
cdtNull: ColSpec := ColSpec + ' DEFAULT NULL';
|
|
||||||
cdtCurTS: ColSpec := ColSpec + ' DEFAULT CURRENT_TIMESTAMP';
|
|
||||||
cdtAutoInc: ColSpec := ColSpec + ' AUTO_INCREMENT';
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
if Props[5] <> '' then
|
if Props[5] <> '' then
|
||||||
ColSpec := ColSpec + ' COMMENT '+esc(Props[5]);
|
ColSpec := ColSpec + ' COMMENT '+esc(Props[5]);
|
||||||
@ -590,12 +675,7 @@ begin
|
|||||||
if ColProps[4] <> '' then begin
|
if ColProps[4] <> '' then begin
|
||||||
DefaultText := ColProps[4];
|
DefaultText := ColProps[4];
|
||||||
DefaultType := GetColumnDefaultType(DefaultText);
|
DefaultType := GetColumnDefaultType(DefaultText);
|
||||||
case DefaultType of
|
Result := Result + ' ' + GetColumnDefaultClause(DefaultType, DefaultText);
|
||||||
cdtText: Result := Result + ' DEFAULT '+esc(DefaultText);
|
|
||||||
cdtNull: Result := Result + ' DEFAULT NULL';
|
|
||||||
cdtCurTS: Result := Result + ' DEFAULT CURRENT_TIMESTAMP';
|
|
||||||
cdtAutoInc: Result := Result + ' AUTO_INCREMENT';
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
if ColProps[5] <> '' then
|
if ColProps[5] <> '' then
|
||||||
Result := Result + ' COMMENT '+esc(ColProps[5]);
|
Result := Result + ' COMMENT '+esc(ColProps[5]);
|
||||||
|
Reference in New Issue
Block a user