Delphi 10.4 Update3 не может отображать десятичные (5,2) поля BCD в DBGrids, если также есть поле datetime - PullRequest
0 голосов
/ 04 августа 2020

Когда у меня есть ClientDataset с полями datetime и decimal (5,2), Delphi 10.4 не может отображать их в TDBGrid, возникает исключение преобразования.

Я подготовил небольшой тестовый проект, чтобы показать эту ошибку (мои реальные данные поступают с сервера 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;

Это вызывает следующее исключение: '8200@' is not a valid integer value

Десятичное число (18,2) не имеет этой проблемы, если я прокомментирую строку ClientDataset.FieldDefs.Find('Decimal').Precision := 5;, то ошибка не возникает.

Кроме того, если нет поля datetime, то ошибка не возникает либо. Это работает нормально:

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;

Как вы думаете, можно ли это исправить, не заменяя все мои поля decimal (5,2) на поля decimal (18,2)?.

ОБНОВЛЕНИЕ: Это проблема, указанная в c ClientDataset. Если я открою те же данные в TADOQuery или TFDMemTable (с точно такими же полями datetime и decimal (5,2) BCD), Delphi 10.4 покажет DBGrid без каких-либо проблем.

Проблема также определена c из DBGrid. Нет проблем с отображением этих полей в DBEdits.

1 Ответ

1 голос
/ 26 августа 2020

В версии 10.4 в модуль Data.FmtBcd внесены изменения, касающиеся функций 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;

Итак, с точностью: = 5 в функции BCDToCurr:

иначе, если BcdPrecision (B) <= (MaxFMTBcdFractionSize - 4), то In c (B.Precision, 4) </strong>

и B.Precision приращение до 9. Переменная Curr принимает неверное значение.

...