mirror of
https://github.com/HeidiSQL/HeidiSQL.git
synced 2025-08-06 18:24:26 +08:00
Prefer local formatting over raw numbers in grids:
* This time, also support formatted integers, not only floats. * Do not quote both types in grid updates/deletes/inserts. * Do no internal conversion from string to float and back to string (FloatToStr did that) to avoid silent data corruption. Just use strings in all places. * Replace FloatStr() function with UnformatNumber(), which is also able to handle integers Should fix issue #1012
This commit is contained in:
@ -133,7 +133,6 @@ type
|
|||||||
function Mince(PathToMince: String; InSpace: Integer): String;
|
function Mince(PathToMince: String; InSpace: Integer): String;
|
||||||
function MakeInt( Str: String ) : Int64;
|
function MakeInt( Str: String ) : Int64;
|
||||||
function MakeFloat( Str: String ): Extended;
|
function MakeFloat( Str: String ): Extended;
|
||||||
function FloatStr(Val: String): String;
|
|
||||||
function esc(Text: WideString; ProcessJokerChars: Boolean = false; sql_version: integer = 50000): WideString;
|
function esc(Text: WideString; ProcessJokerChars: Boolean = false; sql_version: integer = 50000): WideString;
|
||||||
function ScanNulChar(Text: WideString): Boolean;
|
function ScanNulChar(Text: WideString): Boolean;
|
||||||
function ScanLineBreaks(Text: WideString): TLineBreaks;
|
function ScanLineBreaks(Text: WideString): TLineBreaks;
|
||||||
@ -144,6 +143,7 @@ type
|
|||||||
function getFilesFromDir( dir: String; pattern: String = '*.*'; hideExt: Boolean = false ): TStringList;
|
function getFilesFromDir( dir: String; pattern: String = '*.*'; hideExt: Boolean = false ): TStringList;
|
||||||
function goodfilename( str: String ): String;
|
function goodfilename( str: String ): String;
|
||||||
function FormatNumber( str: String ): String; Overload;
|
function FormatNumber( str: String ): String; Overload;
|
||||||
|
function UnformatNumber(Val: String): String;
|
||||||
function FormatNumber( int: Int64 ): String; Overload;
|
function FormatNumber( int: Int64 ): String; Overload;
|
||||||
function FormatNumber( flt: Double; decimals: Integer = 0 ): String; Overload;
|
function FormatNumber( flt: Double; decimals: Integer = 0 ): String; Overload;
|
||||||
procedure setLocales;
|
procedure setLocales;
|
||||||
@ -953,7 +953,7 @@ begin
|
|||||||
// Remove 0x.
|
// Remove 0x.
|
||||||
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
|
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
|
||||||
// Unformat float values
|
// Unformat float values
|
||||||
if GridData.Columns[i].DatatypeCat = dtcReal then Data := FloatStr(Data);
|
if GridData.Columns[i].DatatypeCat in [dtcInteger, dtcReal] then Data := UnformatNumber(Data);
|
||||||
// Escape encloser characters inside data per de-facto CSV.
|
// Escape encloser characters inside data per de-facto CSV.
|
||||||
Data := WideStringReplace(Data, Encloser, Encloser + Encloser, [rfReplaceAll]);
|
Data := WideStringReplace(Data, Encloser, Encloser + Encloser, [rfReplaceAll]);
|
||||||
// Special handling for NULL (MySQL-ism, not de-facto CSV: unquote value)
|
// Special handling for NULL (MySQL-ism, not de-facto CSV: unquote value)
|
||||||
@ -1031,7 +1031,7 @@ begin
|
|||||||
// Remove 0x.
|
// Remove 0x.
|
||||||
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
|
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
|
||||||
// Unformat float values
|
// Unformat float values
|
||||||
if GridData.Columns[i].DatatypeCat = dtcReal then Data := FloatStr(Data);
|
if GridData.Columns[i].DatatypeCat in [dtcInteger, dtcReal] then Data := UnformatNumber(Data);
|
||||||
// Escape XML control characters in data.
|
// Escape XML control characters in data.
|
||||||
Data := htmlentities(Data);
|
Data := htmlentities(Data);
|
||||||
// Add data and cell end tag.
|
// Add data and cell end tag.
|
||||||
@ -1109,7 +1109,7 @@ begin
|
|||||||
// Remove 0x.
|
// Remove 0x.
|
||||||
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
|
if GridData.Columns[i].DatatypeCat = dtcBinary then Delete(Data, 1, 2);
|
||||||
// Unformat float values
|
// Unformat float values
|
||||||
if GridData.Columns[i].DatatypeCat = dtcReal then Data := FloatStr(Data);
|
if GridData.Columns[i].DatatypeCat in [dtcInteger, dtcReal] then Data := UnformatNumber(Data);
|
||||||
// Add data and cell end tag.
|
// Add data and cell end tag.
|
||||||
tmp := tmp + esc(Data);
|
tmp := tmp + esc(Data);
|
||||||
end;
|
end;
|
||||||
@ -1506,18 +1506,6 @@ begin
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
{**
|
|
||||||
Unformat a formatted float value. Used for CSV export and composing WHERE clauses for grid editing.
|
|
||||||
}
|
|
||||||
function FloatStr(Val: String): String;
|
|
||||||
begin
|
|
||||||
Result := Val;
|
|
||||||
if ThousandSeparator <> DecimalSeparator then
|
|
||||||
Result := StringReplace(Val, ThousandSeparator, '', [rfReplaceAll]);
|
|
||||||
Result := StringReplace(Val, DecimalSeparator, '.', [rfReplaceAll]);
|
|
||||||
end;
|
|
||||||
|
|
||||||
|
|
||||||
{***
|
{***
|
||||||
Attempt to do string replacement faster than StringReplace and WideStringReplace.
|
Attempt to do string replacement faster than StringReplace and WideStringReplace.
|
||||||
}
|
}
|
||||||
@ -1834,19 +1822,35 @@ end;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
{***
|
{**
|
||||||
Return a formatted number from a string
|
Unformat a formatted integer or float. Used for CSV export and composing WHERE clauses for grid editing.
|
||||||
by first converting it to a float and then to the desired format
|
}
|
||||||
|
function UnformatNumber(Val: String): String;
|
||||||
|
begin
|
||||||
|
Result := Val;
|
||||||
|
if ThousandSeparator <> DecimalSeparator then
|
||||||
|
Result := StringReplace(Result, ThousandSeparator, '', [rfReplaceAll]);
|
||||||
|
Result := StringReplace(Result, DecimalSeparator, '.', [rfReplaceAll]);
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{***
|
||||||
|
Return a formatted integer or float from a string
|
||||||
@param string Text containing a number
|
@param string Text containing a number
|
||||||
@return string
|
@return string
|
||||||
}
|
}
|
||||||
function FormatNumber( str: String ): String; Overload;
|
function FormatNumber( str: String ): String; Overload;
|
||||||
|
var
|
||||||
|
i, p: Integer;
|
||||||
begin
|
begin
|
||||||
if str <> '' then
|
Result := str;
|
||||||
result := FormatNumber( StrToFloat( str ) )
|
Result := StringReplace(Result, '.', DecimalSeparator, [rfReplaceAll]);
|
||||||
else
|
p := Pos(DecimalSeparator, Result);
|
||||||
result := FormatNumber( 0 );
|
if p = 0 then p := Length(Result)+1;
|
||||||
|
if p > 0 then for i:=p-1 downto 2 do begin
|
||||||
|
if (p-i) mod 3 = 0 then
|
||||||
|
Insert(ThousandSeparator, Result, i);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
@ -4030,10 +4030,11 @@ begin
|
|||||||
ActiveGridResult.Rows[i].Loaded := True;
|
ActiveGridResult.Rows[i].Loaded := True;
|
||||||
SetLength(ActiveGridResult.Rows[i].Cells, Results.ColumnCount);
|
SetLength(ActiveGridResult.Rows[i].Cells, Results.ColumnCount);
|
||||||
for j:=0 to Results.ColumnCount-1 do begin
|
for j:=0 to Results.ColumnCount-1 do begin
|
||||||
if ActiveGridResult.Columns[j].DatatypeCat = dtcBinary then
|
case ActiveGridResult.Columns[j].DatatypeCat of
|
||||||
ActiveGridResult.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j))
|
dtcInteger, dtcReal: ActiveGridResult.Rows[i].Cells[j].Text := FormatNumber(Results.Col(j));
|
||||||
else
|
dtcBinary: ActiveGridResult.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j));
|
||||||
ActiveGridResult.Rows[i].Cells[j].Text := Results.Col(j);
|
else ActiveGridResult.Rows[i].Cells[j].Text := Results.Col(j);
|
||||||
|
end;
|
||||||
ActiveGridResult.Rows[i].Cells[j].IsNull := Results.IsNull(j);
|
ActiveGridResult.Rows[i].Cells[j].IsNull := Results.IsNull(j);
|
||||||
end;
|
end;
|
||||||
Results.Next;
|
Results.Next;
|
||||||
@ -6443,10 +6444,11 @@ begin
|
|||||||
SetLength(res.Rows[Node.Index].Cells, Results.ColumnCount);
|
SetLength(res.Rows[Node.Index].Cells, Results.ColumnCount);
|
||||||
i := Node.Index;
|
i := Node.Index;
|
||||||
for j := 0 to Results.ColumnCount - 1 do begin
|
for j := 0 to Results.ColumnCount - 1 do begin
|
||||||
if res.Columns[j].DatatypeCat = dtcBinary then
|
case res.Columns[j].DatatypeCat of
|
||||||
res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j))
|
dtcInteger, dtcReal: res.Rows[i].Cells[j].Text := FormatNumber(Results.Col(j));
|
||||||
else
|
dtcBinary: res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j));
|
||||||
res.Rows[i].Cells[j].Text := Results.Col(j);
|
else res.Rows[i].Cells[j].Text := Results.Col(j);
|
||||||
|
end;
|
||||||
res.Rows[i].Cells[j].IsNull := Results.IsNull(j);
|
res.Rows[i].Cells[j].IsNull := Results.IsNull(j);
|
||||||
end;
|
end;
|
||||||
res.Rows[Node.Index].Loaded := True;
|
res.Rows[Node.Index].Loaded := True;
|
||||||
@ -6524,10 +6526,11 @@ begin
|
|||||||
for i:=start to start+limit-1 do begin
|
for i:=start to start+limit-1 do begin
|
||||||
SetLength(res.Rows[i].Cells, Results.ColumnCount);
|
SetLength(res.Rows[i].Cells, Results.ColumnCount);
|
||||||
for j:=0 to Results.ColumnCount-1 do begin
|
for j:=0 to Results.ColumnCount-1 do begin
|
||||||
if res.Columns[j].DatatypeCat = dtcBinary then
|
case res.Columns[j].DatatypeCat of
|
||||||
res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j))
|
dtcInteger, dtcReal: res.Rows[i].Cells[j].Text := FormatNumber(Results.Col(j));
|
||||||
else
|
dtcBinary: res.Rows[i].Cells[j].Text := '0x' + BinToWideHex(Results.Col(j));
|
||||||
res.Rows[i].Cells[j].Text := Results.Col(j);
|
else res.Rows[i].Cells[j].Text := Results.Col(j);
|
||||||
|
end;
|
||||||
res.Rows[i].Cells[j].IsNull := Results.IsNull(j);
|
res.Rows[i].Cells[j].IsNull := Results.IsNull(j);
|
||||||
end;
|
end;
|
||||||
res.Rows[i].Loaded := True;
|
res.Rows[i].Loaded := True;
|
||||||
@ -6809,13 +6812,14 @@ begin
|
|||||||
for i := 0 to Length(DataGridResult.Columns) - 1 do begin
|
for i := 0 to Length(DataGridResult.Columns) - 1 do begin
|
||||||
if Row.Cells[i].Modified then begin
|
if Row.Cells[i].Modified then begin
|
||||||
Val := Row.Cells[i].NewText;
|
Val := Row.Cells[i].NewText;
|
||||||
if DataGridResult.Columns[i].DatatypeCat = dtcReal then
|
case DataGridResult.Columns[i].DatatypeCat of
|
||||||
Val := FloatStr(Val)
|
dtcInteger, dtcReal: Val := UnformatNumber(Val);
|
||||||
else if DataGridResult.Columns[i].DatatypeCat = dtcBinary then begin
|
dtcBinary: begin
|
||||||
CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + DataGridResult.Columns[i].Name + '".');
|
CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + DataGridResult.Columns[i].Name + '".');
|
||||||
if Val = '0x' then Val := esc('');
|
if Val = '0x' then Val := esc('');
|
||||||
end else
|
end;
|
||||||
Val := esc(Val);
|
else Val := esc(Val);
|
||||||
|
end;
|
||||||
if Row.Cells[i].NewIsNull then Val := 'NULL';
|
if Row.Cells[i].NewIsNull then Val := 'NULL';
|
||||||
sql := sql + ' ' + mask(DataGridResult.Columns[i].Name) + '=' + Val + ', ';
|
sql := sql + ' ' + mask(DataGridResult.Columns[i].Name) + '=' + Val + ', ';
|
||||||
end;
|
end;
|
||||||
@ -6898,13 +6902,11 @@ begin
|
|||||||
// Find old value of key column
|
// Find old value of key column
|
||||||
KeyVal := Row.Cells[j].Text;
|
KeyVal := Row.Cells[j].Text;
|
||||||
// Quote if needed
|
// Quote if needed
|
||||||
if DataGridResult.Columns[j].DatatypeCat = dtcReal then
|
case DataGridResult.Columns[j].DatatypeCat of
|
||||||
KeyVal := FloatStr(KeyVal)
|
dtcInteger, dtcReal: KeyVal := UnformatNumber(KeyVal);
|
||||||
else if DataGridResult.Columns[j].DatatypeCat = dtcBinary then begin
|
dtcBinary: if KeyVal = '0x' then KeyVal := esc('');
|
||||||
if KeyVal = '0x' then
|
else KeyVal := esc(KeyVal);
|
||||||
KeyVal := esc('');
|
end;
|
||||||
end else
|
|
||||||
KeyVal := esc(KeyVal);
|
|
||||||
|
|
||||||
if Row.Cells[j].IsNull then KeyVal := ' IS NULL'
|
if Row.Cells[j].IsNull then KeyVal := ' IS NULL'
|
||||||
else KeyVal := '=' + KeyVal;
|
else KeyVal := '=' + KeyVal;
|
||||||
@ -7018,14 +7020,15 @@ begin
|
|||||||
if Row.Cells[i].Modified then begin
|
if Row.Cells[i].Modified then begin
|
||||||
Cols := Cols + mask(DataGridResult.Columns[i].Name) + ', ';
|
Cols := Cols + mask(DataGridResult.Columns[i].Name) + ', ';
|
||||||
Val := Row.Cells[i].NewText;
|
Val := Row.Cells[i].NewText;
|
||||||
if DataGridResult.Columns[i].DatatypeCat = dtcReal then
|
case DataGridResult.Columns[i].DatatypeCat of
|
||||||
Val := FloatStr(Val)
|
dtcInteger, dtcReal: Val := UnformatNumber(Val);
|
||||||
else if DataGridResult.Columns[i].DatatypeCat = dtcBinary then begin
|
dtcBinary: begin
|
||||||
CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + DataGridResult.Columns[i].Name + '".');
|
CheckHex(Copy(Val, 3), 'Invalid hexadecimal string given in field "' + DataGridResult.Columns[i].Name + '".');
|
||||||
if Val = '0x' then
|
if Val = '0x' then
|
||||||
Val := esc('');
|
Val := esc('');
|
||||||
end else
|
end;
|
||||||
Val := esc(Val);
|
else Val := esc(Val);
|
||||||
|
end;
|
||||||
if Row.Cells[i].NewIsNull then Val := 'NULL';
|
if Row.Cells[i].NewIsNull then Val := 'NULL';
|
||||||
Vals := Vals + Val + ', ';
|
Vals := Vals + Val + ', ';
|
||||||
end;
|
end;
|
||||||
@ -7202,8 +7205,11 @@ begin
|
|||||||
' WHERE ' + GetWhereClause(Row, @DataGridResult.Columns)
|
' WHERE ' + GetWhereClause(Row, @DataGridResult.Columns)
|
||||||
;
|
;
|
||||||
Results := Connection.GetResults(sql);
|
Results := Connection.GetResults(sql);
|
||||||
if Col.DatatypeCat = dtcBinary then Cell.Text := '0x' + BinToWideHex(Results.Col(0))
|
case Col.DatatypeCat of
|
||||||
|
dtcInteger, dtcReal: Cell.Text := FormatNumber(Results.Col(0));
|
||||||
|
dtcBinary: Cell.Text := '0x' + BinToWideHex(Results.Col(0));
|
||||||
else Cell.Text := Results.Col(0);
|
else Cell.Text := Results.Col(0);
|
||||||
|
end;
|
||||||
Cell.IsNull := Results.IsNull(0);
|
Cell.IsNull := Results.IsNull(0);
|
||||||
end else
|
end else
|
||||||
Result := False;
|
Result := False;
|
||||||
|
Reference in New Issue
Block a user