0

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.

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).

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

A decimal(18,2) doesn't have this problem, if I comment the line ClientDataset.FieldDefs.Find('Decimal').Precision := 5; 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 ?.

UPDATE: This is a problem specific of the 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.

The problem is also specific of the DBGrid. There is no problem displaying those fields on DBEdits.

Marc Guillot
  • 6,090
  • 1
  • 15
  • 42
  • Strange bug. Did you try with a `TFDMemTable`? – Olivier Aug 04 '20 at 11:36
  • Is the Beta Unicode UTF-8 unchecked in the region section of windows? – Ravaut123 Aug 04 '20 at 11:47
  • @Olivier, I just tried the TFDMemTable and it works fine. Strange bug indeed. :-( – Marc Guillot Aug 04 '20 at 11:48
  • @Ravaut123 I've never heard about this setting, where can I find it ?. It's a clean installation of Delphi 10.4, with just the Delphi updates and Report Builder, nothing more has been done on it. – Marc Guillot Aug 04 '20 at 11:52
  • 1
    @Ravaut123 Why do you think the issue has anything to do with that setting? – Olivier Aug 04 '20 at 12:06
  • @Olivier Few week ago I did have some problem with the datetime in the database. This was with devart component. After 2 days searching, I found the probem in the region setting of windows system. The beta utf was checked, I unchecked the beta utf and all works back fine. – Ravaut123 Aug 05 '20 at 12:27
  • @Ravaut123 On my system that setting was already unchecked. – Marc Guillot Aug 05 '20 at 13:14
  • @MarcGuillot Ok the beta utf uncheck was not the solution – Ravaut123 Aug 05 '20 at 13:22

2 Answers2

1

Changes have been made in version 10.4 on the unit Data.FmtBcd about functions BCDToCurr e BCDToCurrency.

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

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:

else if BcdPrecision(B) <= (MaxFMTBcdFractionSize - 4) then Inc(B.Precision, 4)

and B.Precision increment to 9. The variable Curr then takes an incorrect value.

Barba
  • 11
  • 1
0

I reported the bug and now has been fixed in the recent Delphi 10.4 Update 1.

Marc Guillot
  • 6,090
  • 1
  • 15
  • 42