Subject Re: is 0.208 some magic value ? (3th post)
Author Duilio Foschi
--- In IBObjects@y..., "Jason Wharton" <jwharton@i...> wrote:

Jason,

congratulation for the recent award.

When you are done with the toasts (that you well deserve), could you please
help me in getting rid of the 0.208 problem ?

It took me a lot of time (and God knows if I have it in short supply), but
I isolated the bug in the (partly) enclosed procedure.

The bug is in

procedure TIBODataset.InternalSetFieldData( Field: TField; Buffer: Pointer );

(contained in IBDataset.pas) .

I did the following test:

I input 0 in a DBgrid (in the column corresponding to a field of type
numeric(9,3) )
and post.

The DBGrid is linked (thru a TDatasource) to a TIBOQuery.

(Don't forget that we are speaking of IBO v. 3 here).

Procedure InternalSetFieldData is called. Buffer points to char $20
(blank). SQLScale is -3.

The infamous 0.208 first appears in line {1}.

I cannot understand why.

Please take the wheel and fix the bug :)

TIA

Duilio Foschi


procedure TIBODataset.InternalSetFieldData( Field: TField; Buffer: Pointer );

function _TrimExt(e: extended): extended;
const
CorrFactor: Longint = 100000000;
CW: word = $1332; //same as system.Default8087CW
var
PlaceFor64Bit: packed array [0..1] of longint;
asm
fldcw word ptr [CW] //reset control word if modified to default
fld tbyte ptr [e] //load function param to ST
fimul dword ptr [CorrFactor] //mult ST with CorrFactor, result stored in ST
fistp qword ptr [PlaceFor64Bit]//int store with rnd rslt to PFor64Bit &
clr ST
fwait
fild qword ptr [PlaceFor64Bit] //load integer result of fmul into ST
fidiv dword ptr [CorrFactor] //divide by CorrFactor, result stored in ST
fstp tbyte ptr [Result] //store result into funtions Result and clear ST
fwait
end;

var
ARecBuf: pointer;
ACalcBuf: pointer;
ANode: PIB_Node;
tmpData: pointer;
tmpExt: extended;
tmpInt: integer;
tmpInd: ^smallint;
tmpLen: integer;
NewTimeStamp: TTimeStamp;
tmpStr: string;
begin
if not (State in dsWriteModes) then DatabaseError(SNotEditing);
if (State = dsSetKey) then
if ((Field.FieldNo < 0) or (IndexFieldCount > 0) and
not Field.IsIndexField) then
DatabaseErrorFmt( SNotIndexField, [Field.DisplayName]);
if not GetActiveRecBuf( ARecBuf, ACalcBuf, ANode ) then Exit;
if Field.FieldNo > 0 then
begin
if State = dsCalcFields then
DatabaseError(SNotEditing);
if ReadOnly and not (State in [dsSetKey, dsFilter]) then
DatabaseErrorFmt(SFieldReadOnly, [Field.DisplayName]);
Field.Validate(Buffer);
with InternalDataset.Fields.PSQLDA^.SQLVAR[ Field.FieldNo - 1 ] do
begin
tmpData := pointer( longint( ARecBuf ) +
longint( SQLData ) -
longint( InternalDataset.Fields.RowBuffer ));
tmpInd := pointer( longint( tmpData ) - SizeOf( smallint ));
if Buffer = nil then
tmpInd^ := IB_Null
else
begin
tmpInd^ := IB_NotNull;
if ( Field.DataType = ftBoolean ) and
( SQLScale <> 0 ) then
EIB_Error.Create( E_Unsupp_Col_Conversion )
else
case SQLtype of
SQL_SHORT,
SQL_SHORT_: if SQLScale <> 0 then
begin
case Field.DataType of
ftBCD:
tmpExt := pcurrency(Buffer)^;
ftCurrency,ftFloat:
tmpExt := pdouble(Buffer)^;
else
raise EIB_Error.Create( E_Unsupp_Col_Conversion );
end;
for tmpInt := 0 downto SQLScale + 1 do
tmpExt := tmpExt * 10;
smallint(tmpData^) := Trunc( _TrimExt(tmpExt) );
end
else
begin
case Field.DataType of
ftBCD: psmallint(tmpData)^ := Trunc(currency(Buffer^));
ftCurrency,
ftFloat: psmallint(tmpData)^ := Trunc( double(Buffer^));
ftSmallint: psmallint(tmpData)^ := smallint(Buffer^);
ftAutoInc,
ftInteger: psmallint(tmpData)^ := integer(Buffer^);
{$IFDEF IBO_VCL40_OR_GREATER}
ftLargeInt: psmallint(tmpData)^ := largeint(Buffer^);
{$ENDIF}
ftBoolean,
ftWord: psmallint(tmpData)^ := word(Buffer^);
else
raise EIB_Error.Create( E_Unsupp_Col_Conversion );
end;
end;
SQL_LONG,
SQL_LONG_:
if SQLScale <> 0 then
begin
case Field.DataType of
ftBCD:
tmpExt := pcurrency(Buffer)^; // line 1 0.208 first here
ftCurrency,ftFloat:
tmpExt := pdouble(Buffer)^;
else
raise EIB_Error.Create( E_Unsupp_Col_Conversion );
end;
for tmpInt := 0 downto SQLScale + 1 do
tmpExt := tmpExt * 10;
integer(tmpData^) := Trunc( _TrimExt(tmpExt) ); //line 2
end

<cut>

TIA

Duilio Foschi