View Issue Details

IDProjectCategoryView StatusLast Update
0030853FPCCompilerpublic2019-08-09 14:21
ReporterVladimir KAssigned ToLacaK 
PrioritynormalSeverityminorReproducibilityalways
Status feedbackResolutionreopened 
Platform64OSWindowsOS Version10
Product Version3.0.0Product BuildLazarus 1.6 
Target VersionFixed in Version3.1.1 
Summary0030853: VarToBcd for value 0 issue
DescriptionVarToBcd returns for value 0 structure filled with 0 (Precision, SignSpecialPlaces and Fraction) while Delphi returns Precision 10 and SignSpecialPlaces 2. It looks insignificant until BCD value sent to ASE (Sybase) and fails with message "Domain error during implicit conversion of NUMERIC value '' to a DECIMAL field".
Steps To Reproducevar
  v: Variant;
  bcd: TBcd;
begin
  v := 0;
  bcd := VarToBcd(v);
  
Additional InformationFor now avoidable by fix after conversion

if (bcd.Precision = 0) and (bcd.SignSpecialPlaces = 0) then begin
  bcd.Precision := 10;
  bcd.SignSpecialPlaces := 2;
end;
TagsNo tags attached.
Fixed in Revision38333
FPCOldBugId
FPCTarget
Attached Files
  • bug30853.pp (162 bytes)
    {$mode delphi}
    uses fmtbcd;
    var
      v: Variant;
      bcd: TBcd;
    begin
      v := 0;
      bcd := VarToBcd(v);
      writeln(bcd.precision,' ',bcd.signspecialplaces);
    end.
    bug30853.pp (162 bytes)
  • fmtbcd.pp.1.diff (1,565 bytes)
    --- fmtbcd.pp.ori	Fri Aug 09 13:34:11 2019
    +++ fmtbcd.pp	Fri Aug 09 13:38:49 2019
    @@ -797,10 +797,12 @@
     {$endif}
     
       function __get_null : tBCD; Inline;
    +  function __get_zero : tBCD; Inline;
       function __get_one : tBCD; Inline;
     
       PROPERTY
         NullBCD : tBCD Read __get_null;
    +    ZeroBCD : tBCD Read __get_zero;
         OneBCD : tBCD Read __get_one;
     
     //{$define __lo_bh := 1 * ( -( MaxFmtBCDFractionSize * 1 + 2 ) ) }
    @@ -887,16 +889,20 @@
         OneBCD_ : tBCD;
     
       function __get_null : tBCD; Inline;
    -
         begin
           __get_null := NullBCD_;
    -     end;
    +    end;
     
    -  function __get_one : tBCD; Inline;
    +  function __get_zero : tBCD; Inline;
    +    begin
    +      __get_zero := NullBCD_;
    +      __get_zero.Precision := 1;
    +    end;
     
    +  function __get_one : tBCD; Inline;
         begin
           __get_one := OneBCD_;
    -     end;
    +    end;
     
       type
         range_digits = 1..maxfmtbcdfractionsize;
    @@ -1584,7 +1590,7 @@
         begin
           _SELECT
             _WHEN aValue = 0
    -          _THEN result := NullBCD;
    +          _THEN result := ZeroBCD;
             _WHEN aValue = 1
               _THEN result := OneBCD;
             _WHEN aValue = low ( myInttype )
    @@ -4129,12 +4135,6 @@
             not_implemented;
         else { array or something like that }
             not_implemented;
    -    end;
    -  // peephole, avoids problems with databases, mantis #30853
    -  if (Result.Precision = 0) and (Result.SignSpecialPlaces = 0) then 
    -    begin
    -      Result.Precision := 10;
    -      Result.SignSpecialPlaces := 2;
         end;
     end;
     
    
    fmtbcd.pp.1.diff (1,565 bytes)

Activities

Marco van de Voort

2018-02-24 21:55

manager  

bug30853.pp (162 bytes)
{$mode delphi}
uses fmtbcd;
var
  v: Variant;
  bcd: TBcd;
begin
  v := 0;
  bcd := VarToBcd(v);
  writeln(bcd.precision,' ',bcd.signspecialplaces);
end.
bug30853.pp (162 bytes)

Marco van de Voort

2018-02-24 21:55

manager   ~0106596

Checked with Delphi, indeed. Fix committed.

LacaK

2018-05-29 13:54

developer   ~0108573

I checked with Delphi 7 and there is Precision=18 and SignSpecialPlaces=4.
May be it would be best to look why ASE returns error ...

@Vladimir: can you provide more information about database components you use and small code sample which can reproduce mentioned error.

LacaK

2019-08-09 12:30

developer   ~0117611

Last edited: 2019-08-09 12:46

View 4 revisions

Delphi7 returns (Precision SignSpecialPlaces):
value 0: VarToBcd: 18 4
value 0: DoubleToBcd: 8 2
value 0: IntegerToBcd: 8 2
value 1: IntegerToBcd: 1 0
(so for value 0 various BCD functions returns various results (two various internal representations for same 0 value) ... IMO pretty inconsistent, but not wrong; Probably newer versions of Delphi will return other results so we can not take here Delphi as strong standard (AFAIK FmtBCD unit was changed among Delphi version))

While FPC:
value 0: VarToBcd: 0 0
value 0: DoubleToBcd: 0 0
value 0: IntegerToBcd: 0 0
value 1: IntegerToBcd: 1 0

In all cases back-conversion BcdToStr() for 0 value returns '0'.

IMO problem is not in internal representation of value 0 (which may be correct), but how this value is later handled by "database" layer, which sends it to ASE server.
Fix povided by Marco is hot-fix for given particular VarToBCD situation, but does not handle for example IntegerToBcd or DoubleToBcd conversions of value 0.
IMO we need more details from "Vladimir K" to identify root of problem.

I have suspection that "Vladimir K" uses 3rd party "database" layer, because TMSSQLConnection and TODBCConnection should handle 0 BCD values correctly.

LacaK

2019-08-09 13:52

developer   ~0117612

Last edited: 2019-08-09 14:21

View 2 revisions

IMO we must say if we want to distinguish NullBcd (here null means undefined or unknown value) and "ZeroBcd".
I have attached patch, which introduces "ZeroBCD" with Precision=1, SignSpecialScale=0 and Fraction=all 0.
It is not perfect solution, but in this case - if "database" layer is sensitive to NullBCD (all zeroes in TBCD) - this should help.

"Vladimir K" can you test with this patch: fmtbcd.pp.1 ?

IMO it does not give sense to represent 0 in TBCD with Precisions 8,10 or 18 and/or scales of 2 or 4 (as we see it in Delphi), because 0 is integer (with zero decimal digits) so there is no sense have "Scale" other than 0. And also "Precision" should be only 0 or 1 (as there is only 0/1 significant digit before decimal point)



fmtbcd.pp.1.diff (1,565 bytes)
--- fmtbcd.pp.ori	Fri Aug 09 13:34:11 2019
+++ fmtbcd.pp	Fri Aug 09 13:38:49 2019
@@ -797,10 +797,12 @@
 {$endif}
 
   function __get_null : tBCD; Inline;
+  function __get_zero : tBCD; Inline;
   function __get_one : tBCD; Inline;
 
   PROPERTY
     NullBCD : tBCD Read __get_null;
+    ZeroBCD : tBCD Read __get_zero;
     OneBCD : tBCD Read __get_one;
 
 //{$define __lo_bh := 1 * ( -( MaxFmtBCDFractionSize * 1 + 2 ) ) }
@@ -887,16 +889,20 @@
     OneBCD_ : tBCD;
 
   function __get_null : tBCD; Inline;
-
     begin
       __get_null := NullBCD_;
-     end;
+    end;
 
-  function __get_one : tBCD; Inline;
+  function __get_zero : tBCD; Inline;
+    begin
+      __get_zero := NullBCD_;
+      __get_zero.Precision := 1;
+    end;
 
+  function __get_one : tBCD; Inline;
     begin
       __get_one := OneBCD_;
-     end;
+    end;
 
   type
     range_digits = 1..maxfmtbcdfractionsize;
@@ -1584,7 +1590,7 @@
     begin
       _SELECT
         _WHEN aValue = 0
-          _THEN result := NullBCD;
+          _THEN result := ZeroBCD;
         _WHEN aValue = 1
           _THEN result := OneBCD;
         _WHEN aValue = low ( myInttype )
@@ -4129,12 +4135,6 @@
         not_implemented;
     else { array or something like that }
         not_implemented;
-    end;
-  // peephole, avoids problems with databases, mantis #30853
-  if (Result.Precision = 0) and (Result.SignSpecialPlaces = 0) then 
-    begin
-      Result.Precision := 10;
-      Result.SignSpecialPlaces := 2;
     end;
 end;
 
fmtbcd.pp.1.diff (1,565 bytes)

Issue History

Date Modified Username Field Change
2016-11-03 15:59 Vladimir K New Issue
2018-02-24 21:55 Marco van de Voort File Added: bug30853.pp
2018-02-24 21:55 Marco van de Voort Fixed in Revision => 38333
2018-02-24 21:55 Marco van de Voort Note Added: 0106596
2018-02-24 21:55 Marco van de Voort Status new => resolved
2018-02-24 21:55 Marco van de Voort Fixed in Version => 3.1.1
2018-02-24 21:55 Marco van de Voort Resolution open => fixed
2018-02-24 21:55 Marco van de Voort Assigned To => Marco van de Voort
2018-05-29 13:54 LacaK Note Added: 0108573
2018-05-29 13:54 LacaK Status resolved => feedback
2018-05-29 13:54 LacaK Resolution fixed => reopened
2019-08-09 12:30 LacaK Note Added: 0117611
2019-08-09 12:30 LacaK Note Edited: 0117611 View Revisions
2019-08-09 12:40 LacaK Note Edited: 0117611 View Revisions
2019-08-09 12:46 LacaK Note Edited: 0117611 View Revisions
2019-08-09 13:39 Marco van de Voort Assigned To Marco van de Voort => LacaK
2019-08-09 13:52 LacaK File Added: fmtbcd.pp.1.diff
2019-08-09 13:52 LacaK Note Added: 0117612
2019-08-09 14:21 LacaK Note Edited: 0117612 View Revisions