[英]Delphi 10.4 fails to show decimal(5,2) BCD fields on DBGrids if there also is a datetime field
When I have a ClientDataset with datetime fields and decimal(5,2) fields, Delphi 10.4 can't show them on a TDBGrid, it raises a convert exception.当我有一个带有日期时间字段和十进制(5,2)字段的 ClientDataset 时,Delphi 10.4 无法在 TDBGrid 上显示它们,它会引发转换异常。
I have prepared an small test project to show this error (my real data comes from SQL Server, although I can get the same error filling the Clientdataset manually).我准备了一个小测试项目来显示这个错误(我的真实数据来自 SQL 服务器,虽然我可以手动填充 Clientdataset 得到相同的错误)。
procedure TForm1.FormCreate(Sender: TObject);
var ClientDataset: TClientDataset;
Datasource: TDatasource;
DBGrid: TDBGrid;
begin
ClientDataset := TClientDataset.Create(Self);
ClientDataset.FieldDefs.Add('Id', ftInteger);
ClientDataset.FieldDefs.Add('Date', ftDateTime);
ClientDataset.FieldDefs.Add('Decimal', ftBCD, 2);
ClientDataset.FieldDefs.Find('Decimal').Precision := 5;
ClientDataset.CreateDataSet;
Datasource := TDatasource.Create(Self);
Datasource.Dataset := ClientDataset;
ClientDataset.Insert;
ClientDataset.FieldValues['id'] := 1;
ClientDataset.FieldValues['Date'] := Now;
ClientDataset.FieldValues['Decimal'] := 7.55;
ClientDataset.Post;
ClientDataset.Insert;
ClientDataset.FieldValues['id'] := 2;
ClientDataset.FieldValues['Date'] := Now;
ClientDataset.FieldValues['Decimal'] := 8.2;
ClientDataset.Post;
DBGrid := TDBGrid.Create(Self);
DBGrid.Parent := Self;
DBGrid.Align := alClient;
DBGrid.Datasource := Datasource;
end;
It raises this exception: '8200@' is not a valid integer value
它引发了这个异常:
'8200@' is not a valid integer value
A decimal(18,2) doesn't have this problem, if I comment the line ClientDataset.FieldDefs.Find('Decimal').Precision:= 5;
如果我注释
ClientDataset.FieldDefs.Find('Decimal').Precision:= 5;
行,小数(18,2)就没有这个问题then no error is raised.然后不会引发错误。
Also, if there is no datetime field then no error is raised either.此外,如果没有日期时间字段,则也不会引发错误。 This runs fine:
这运行良好:
procedure TForm1.FormCreate(Sender: TObject);
var ClientDataset: TClientDataset;
Datasource: TDatasource;
DBGrid: TDBGrid;
begin
ClientDataset := TClientDataset.Create(Self);
ClientDataset.FieldDefs.Add('Id', ftInteger);
ClientDataset.FieldDefs.Add('Decimal', ftBCD, 2);
ClientDataset.FieldDefs.Find('Decimal').Precision := 5;
ClientDataset.CreateDataSet;
Datasource := TDatasource.Create(Self);
Datasource.Dataset := ClientDataset;
ClientDataset.Insert;
ClientDataset.FieldValues['id'] := 1;
ClientDataset.FieldValues['Decimal'] := 7.55;
ClientDataset.Post;
ClientDataset.Insert;
ClientDataset.FieldValues['id'] := 2;
ClientDataset.FieldValues['Decimal'] := 8.2;
ClientDataset.Post;
DBGrid := TDBGrid.Create(Self);
DBGrid.Parent := Self;
DBGrid.Align := alClient;
DBGrid.Datasource := Datasource;
end;
Do you think that this could be fixed without having to replace all my decimal(5,2) fields with decimal(18,2) fields?.您是否认为无需将所有小数(5,2)字段替换为小数(18,2)字段即可解决此问题?
UPDATE: This is a problem specific of the ClientDataset.更新:这是特定于 ClientDataset 的问题。 If I open the same data on a TADOQuery or TFDMemTable (with the exact same datetime and decimal(5,2) BCD fields), Delphi 10.4 shows the DBGrid without any issue.
如果我在 TADOQuery 或 TFDMemTable 上打开相同的数据(具有完全相同的 datetime 和 decimal(5,2) BCD 字段),Delphi 10.4 显示 DBGrid 没有任何问题。
The problem is also specific of the DBGrid.该问题也特定于 DBGrid。 There is no problem displaying those fields on DBEdits.
在 DBEdits 上显示这些字段没有问题。
Changes have been made in version 10.4 on the unit Data.FmtBcd about functions BCDToCurr e BCDToCurrency.版本 10.4 中已对单元 Data.FmtBcd 关于函数 BCDToCurr e BCDToCurrency 进行了更改。
Delphi 10.3 Delphi 10.3
function BCDToCurr(const BCD: TBcd; var Curr: Currency): Boolean;
Curr := StrToCurr(string(Bcd));
Result := True;
end;
function BCDToCurrency(const BCD: TBcd): Currency;
begin
Result := StrToCurr(string(Bcd));
end;
Delphi 10.4 Delphi 10.4
function BCDToCurr(const BCD: TBcd; var Curr: Currency): Boolean;
var
B: TBcd;
S: string;
const
DecimalSeparator = '.';
begin
// B := BCD * 10000;
B := BCD;
if BcdScale(B) >= 4 then
Dec(B.SignSpecialPlaces, 4)
else if BcdPrecision(B) <= (MaxFMTBcdFractionSize - 4) then
Inc(B.Precision, 4)
else
OverflowError(SBcdOverflow);
S := BcdToStr(B, DecimalSeparator);
Round(S, DecimalSeparator, 0);
// The real format of Currency type is Int64.
PInt64(@Curr)^ := StrToInt64(S);
Result := True;
end;
function BCDToCurrency(const BCD: TBcd): Currency;
begin
BCDToCurr(BCD, Result);
end;
So, with precision:=5 in BCDToCurr function:因此,精度:= 5 in BCDToCurr function:
else if BcdPrecision(B) <= (MaxFMTBcdFractionSize - 4) then Inc(B.Precision, 4)否则,如果 BcdPrecision(B) <= (MaxFMTBcdFractionSize - 4) 那么 Inc(B.Precision, 4)
and B.Precision increment to 9. The variable Curr then takes an incorrect value. B.Precision 增量为 9。然后变量 Curr 采用不正确的值。
I reported the bug and now has been fixed in the recent Delphi 10.4 Update 1.我报告了这个错误,现在已经在最近的 Delphi 10.4 Update 1 中修复。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.