Still celebrating National IT Professionals Day with 3 months of free Premium Membership. Use Code ITDAY17

x
?
Solved

How to get ERangeError when casting Int64 to LongInt (db.pas)

Posted on 2002-06-11
12
Medium Priority
?
1,122 Views
Last Modified: 2012-06-27
Hello all,

The reason I as this is the following: In DB.pas there is a method TFloatField.GetAsInteger.

It is implemented as follows:

function TFloatField.GetAsFloat: Double;
begin
  if not GetData(@Result) then Result := 0;
end;

function TFloatField.GetAsInteger: Longint;
begin
  Result := Longint(Round(GetAsFloat));
end;

Round returns a Int64 and the result is casted to Integer. My problem is that some developer in my team use AsInteger for numeric(11,0) fields (which delphi translated into TFloatField) and Delphi generates no error at all also when Range Checking is on and Overflow Checking is on ($R- is specified in db.pas). I even tried the following:

function GetAsFloat: Double;
begin
  Result := 4000000000000000000;
end;

{$R+} {$Q+}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Lines.Add(IntToStr(LongInt(Round(GetAsFloat))));
end;

But I never get an error.

My question is the following:
- Can I get an error in D5 for this problem (without rewriting or patching the VCL)
- If so how?
- If it is not possible how should this patching:
  - By disabeling the AsInteger property for TFloatFields
  - By checking in the GetAsFloat for values that do not fit
- What advice do you have when patching the VCL (we want to be able to use a new version of Delphi without to much repatching the new VCL version)

Thanks Jacco
0
Comment
Question by:Jacco
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 4
  • 2
12 Comments
 
LVL 7

Expert Comment

by:Cynna
ID: 7072484
Jacco,

If I understood you correctly, you want GetAsInteger function to raise ERangeError exception. You are wondering why this doesnt't happen when you try to convert obviously too large value for LongInt, right?

Solution
----------------

Get rid of the typecast - change GetAsInteger function from:

   Result := Longint(Round(GetAsFloat));

 to    

   {$R+} {$Q+}
   Result := Round(GetAsFloat);



Explanation
----------------

When you perform a typecast you are actually telling compiler:
"Don't check this assignment, I know what I'm doing".

So, regardless of {$R+}, when you did Longint(...) you told compiler to trust your judgement, and not to waste time implementing a range check code.
In your case, casting was redundant, as Int64 and LongInt have assignment-compatibility.

So, directly assigning Int64 to LongInt will firstly check if value you are about to assign to LongInt falls within the LongInt range, which is exactly what you need, right?
0
 
LVL 10

Author Comment

by:Jacco
ID: 7074039
Thanks Cynna,

You have explained one part of the question.

The code mentioned is in DB.pas of the Delphi VCL. The second part is how to handle this. Do I patch the VCL? We have a team of developers that would mean spreading a Delphi patch? Or is there a simpler solution.

I want some advice on how to go ahead with this.

I can award you 100 pts for explaining why $R+ $Q+ didn't help in this case, and what typecasting integers does.

Regards Jacco
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 7074440
create your own version?

type
  TRangeFloatField = class(TFloatField)
  protected
    procedure GetAsInteger: Integer; reintroduce;
  end;

...

procedure TRangeFloatField.GetAsInteger: Integer;
begin
  Result := Round(GetAsFloat);
end;


... and in later parts of your code

MyInteger := TRangeFloatField(MyFloatField).AsInteger;




not tested though, but I think it should work.




HTH
DragonSlayer
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 10

Author Comment

by:Jacco
ID: 7074737
Thanks DragonSlayer,

Ok, but how will I fool the TDataSet to create a TRangeFloatField in stead of a TFloatField in the IDE?

The team of programmers must not easily make a mistake. We use TTable, TQuery, TAdsTabe and TAdsQuery a lot.

One mistake can cause a disaster. The advantage tables have a "autoinc" field numeric(11,0). Both FoxPro apps and Delphi apps increase the numbers. One developer used

FieldByName('autoinc').AsInteger := FieldByName('autoinc').AsInteger + 1

Which is logical but cause all kinds of errors...

Regards Jacco

Regards Jacco
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 7074752
It can create TFloatField, you just typecast it to TRangeFloatField in code.
0
 
LVL 10

Author Comment

by:Jacco
ID: 7075120
Hi DragonSlayer,

What if a developer forgets to typecast...

Are there any other solutions?

Regards Jacco
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 7077012
I think there are no other ways :(
0
 
LVL 7

Accepted Solution

by:
Cynna earned 1200 total points
ID: 7077609
Jacco,

Well, I don't see any elegant solution to your problem.
As far as I can see, this could be handled in several ways:

1. Perform range check yourself. You could do it:
   a) implicitly, by using direct Int64 to LongInt assignement (as I noted earlier), and letting Delphi raise ERangeError exception for you,
   or
   b) explicitly, by checking if value falls within Low(LongInt) and High(LongInt) range, and raising exception yourself.

You could encapsulate this check in a simple function, and use it either at data entry point (when data is entered, check its range) or data retreival point. Access it as float, and then convert it to LongInt yourself, checking its range.

The proper thing to do, IMO, is checking data at entry point. This way, you can latter safely access it AsInteger.

I know this is a bit clumsy, but I don't see anything more elegant for your problem.


2. Patch VCL. I know this is not a popular solution (as it certainly shouldn't be!), but, in your case it's just a minor incision. All you have to do is remove LongInt(..) cast from TFloatField.GetAsInteger and that's it.
I know this is a hassle and you have to implement it on your developer machines, but once this is done, you have zero effort in changing your code.
BTW, you might think of flagging this as a bug to Borland.
If they accept, you don't even have to patch a new Delphi version :)


So basically, as I see it, your choice boils down to this:

1. Make (presumably) extensive, although simple, changes in you existing code, and leave VCL alone

    or

2. Make simple VCL patch and leave your code alone.


0
 
LVL 10

Author Comment

by:Jacco
ID: 7080210
Thanks Cynna,

Fortunately we do not use packages (just one 6.5 MB exe) otherwise we would have to distribute a new BPL as well. Developers on the other hand need both altered PAS and DCU since some don't compile the Delphi sources...

I will flag Borland :)

I will award you the 300 points.

DragonSlayer if you want some points as well please tell me.

Regards Jacco
0
 
LVL 10

Author Comment

by:Jacco
ID: 7080211
Here you are
0
 
LVL 14

Expert Comment

by:DragonSlayer
ID: 7082736
it's okay, points are up to you :)
0
 
LVL 10

Author Comment

by:Jacco
ID: 7084415
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Monitoring a network: how to monitor network services and why? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the philosophy behind service monitoring and why a handshake validation is critical in network monitoring. Software utilized …
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses

705 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question