views:

727

answers:

4

I´m using Delphi 7 with devart dbExpress to connect to SQLServer. The problem is that when I add a bigInt field to a ClientQuery it comes as TFMTBCDField.

And the TFMTBCDField don´t have a method to get the 64 bit value.

I can use the Field.AsVariant or the StrToInt64(Field.AsString) to pick this 64 bits value.

Is there a better way to pick/use this value?

A: 

I dont have Delphi 7 installed here anymore, but looking in the help, I see you can get as Float (Double), like this:

function GetFieldAsInt64(Field: TField): Int64;
begin
  Result:= Int64(Round(Field.GetAsFloat));
end;

And then, call the function:

var
  Value: Int64;
begin
  Value:= GetFieldAsInt64(MyFMTBCDField);

end;
Cesar Romero
A double does not offer enough significant digits (15-16) to store a 64 bit integer (19 digits for max int64)
The_Fox
@ The Fox: So any new version of Delphi will have problems, after see your negative reply, I check Delphi 2010 sources, and is how it is done.
Cesar Romero
Perhaps they offer GetAsFloat for your convenience, but a TFMTBCDField offers greater precision than a Double can offer.
The_Fox
A: 

You can convert the BCD to Variant and than to int64 with VarFMTBcdCreate from unit FMTBcd.

Try this:

var value64 : int64;
...
value64 := VarFMTBcdCreate(Field.Value);
Matthias Alleweldt
This still uses a Variant
Gerry
Added variable declaration to make it clear
Matthias Alleweldt
Matthias, the variable declaration doesn't address Gerry's comment at all. `VarFMTBcdCreate` returns a value of type `Variant`. The assignment statement then converts that `Variant` to an `Int64`.
Rob Kennedy
+1  A: 

Maybe add a TLargeIntField manualy to dataset, set it's FieldName to appropriate name and use such code:

SomeInt64Value := (qryMyQuery.FieldByName('blahblah') as TLargeIntField).AsLargeInt;

Do not remember exactly types, but it worked this way in Delphi6.

smok1
Is it kosher to simply add another field to the dataset that's of a different type from the one that was added automatically? I mean, will the driver send data that's compatible with the new field's type, or will the driver continue sending BCD data and the field object merely interpret that block of bytes as an Int64 instead? Anyway, **if** that's allowed at all, the type-cast to `TLargeintField` isn't necessary; the `AsLargeInt` property getter is virtual, so the right code will be used even when called directly on the `TField` value.
Rob Kennedy
I do nont know if this is kosher. Probably this is strongly dependant of particular TDataSet implementation. And by the way - typecasting was the only option in delphi6 and before, since qryMyQuery.FieldByName('blahblah').AsLargeints not allowed (TField did not have AsLargeint property).
smok1
A: 

The data format for TFMTBCDField is the TBcd record from the FMTBcd unit. You can get that raw value by reading the field's Value or AsBCD properties.

Depending on what you need the value for, TBcd might be sufficient. That is, you might not need to convert it to an Int64. The FMTBcd unit provides functions to add, subtract, multiply, and divide TBcd values.

The unit provides no conversions to Int64. There are conversions to Variant, string, Currency, Double, and Integer. If we were going to write an Int64 conversion, the Integer conversion is probably a good place to start, so let's take a look at how it's implemented:

function BcdToInteger(const Bcd: TBcd; Truncate: Boolean = False): Integer;
var
  ABcd: TBcd;
begin
  if Truncate and (BcdScale(Bcd) > 0) then
    NormalizeBcd(Bcd, ABcd, Bcd.Precision, 0)
  else
    ABcd := Bcd;
  Result := StrToInt(BcdToStr(ABcd));    
end;

So, the VCL itself doesn't provide any more direct way to convert a TBcd to an Integer than to go through string. Therefore, it looks like your idea to call StrToInt64 on the string version of the field is fine.

Rob Kennedy