Delphi TIBquery EAccessViolation error only in debug mode

Hi,

   I have a problem with a TIBQUERY. I have make an example here without all data and a simply count of the record.

   In the table there are only 5000 records and the table contain some integer records, is very small!

   When I execute it at Runtime there are no error and the result is OK.

   When I execute in debug mode I have this error:

   Project project_my.exe raised exception class EAccessViolation with message 'Access violation at address 12345678 in module 'project_my.exe'. Read of address 87654321'. Process stopped.

   With address every time different (here I have write 12345678).
   If I try to continue the program go and I have the just count!

   There is a way to solve this?

   Delphi 7 - InterbaseExpress 6.


   var
     Q_MY: TIBQuery;
     record_number:longint;
   begin
      Q_MY:=TIBQuery.Create(Self);
      try
         Q_MY.Database:=B1.IBDatabase;
         Q_MY.Sql.Clear;
         Q_MY.Sql.Add('SELECT * FROM VISTA_HP_03');
         Q_MY.Open;
         record_number:=0;
         while not Q_MY.eof do
         begin
            inc(record_number);
            Q_MY.Next; // passo al Cliente successivo
         end;
         caption:=inttostr(record_number);
      finally
         Q_MY.Free;
      end;
  end;
Andrea MatthiaeSoftware engineeringAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

jimyXCommented:
Try to close your table before and after finish:
   var
     Q_MY: TIBQuery;
     record_number:longint;
   begin
      Q_MY:=TIBQuery.Create(Self);
      try
         Q_MY.Database:=B1.IBDatabase;
         Q_MY.Close;
         Q_MY.Sql.Clear;
         Q_MY.Sql.Add('SELECT * FROM VISTA_HP_03');
         Q_MY.Open;
         Q_MY.First;
         record_number:=0;
         while not Q_MY.eof do
         begin
            inc(record_number);
            Q_MY.Next; // passo al Cliente successivo
         end;
         caption:=inttostr(record_number);
      finally
         Q_MY.Close;
         Q_MY.Free;
      end;
  end;

Open in new window


But isn't there a better way to get the records count?
You can try something like this:
   var
     Q_MY: TIBQuery;
   begin
      Q_MY:=TIBQuery.Create(Self);
      try
         Q_MY.Database:=B1.IBDatabase;
         Q_MY.Close;
         Q_MY.Sql.Clear;
         Q_MY.Sql.Add('SELECT * FROM VISTA_HP_03');
         Q_MY.Open;
         caption:=inttostr(Q_MY.RecordCount);
      finally
         Q_MY.Close;
         Q_MY.Free;
      end;
  end;

Open in new window

0
jimyXCommented:
Another way is:
   var
     Q_MY: TIBQuery;
   begin
      Q_MY:=TIBQuery.Create(Self);
      try
         Q_MY.Database:=B1.IBDatabase;
         Q_MY.Close;
         Q_MY.Sql.Clear;
         Q_MY.Sql.Add('SELECT Count(*) FROM VISTA_HP_03');
         Q_MY.ExecSQL;
         caption := Q_MY.Fields[0].AsString;
      finally
         Q_MY.Close;
         Q_MY.Free;
      end;
  end;

Open in new window

0
Andrea MatthiaeSoftware engineeringAuthor Commented:
Hi,
thanks for your response.

>But isn't there a better way to get the records count?
I have just make an example for this question. But really:

try
 ....
   here I read the data and do some calculations...
finally
end;

I have tested your code with the Close before and after and I have also the problem.
I repeat... the problem is NOT at Runtime but in Debug mode.
I have this error only with more than 1000-4000 records.
0
C++ 11 Fundamentals

This course will introduce you to C++ 11 and teach you about syntax fundamentals.

jimyXCommented:
Do you handle large fields in that database (blob, graphics,...etc).
It could be memory issue.

Does that happen with different tables or different database suite other than TIBQuery?
Make sure you do not have memory leak from other operations or process.

Also try to change from the Delphi menu -> Tools -> Debugger options... -> Language exceptions -> select "Stop on Delphi Exceptions".
0
Ephraim WangoyaCommented:

You can improve your query but that does not seem to be the problem, to get a count of records, use the following


function TForm1.GetRecordCount: Int64;
var
  Q_MY: TIBQuery;
begin
  Result := 0;
  Q_MY:=TIBQuery.Create(nil); //use nil, no need to attach other components
  try
    Q_MY.Database:=B1.IBDatabase;
    Q_MY.Sql.Add('SELECT COUNT(1) CNT FROM VISTA_HP_03');
    Q_MY.Active := True;
    if not Q_MY.IsEmpty then
      Result := Q_MY.FieldByName('CNT').AsInteger;
    Q_MY.Active := False;  //close the query 
  finally
    FreeAndNil(Q_MY);
  end;
end;

//call it like this
  Self.Caption := IntToStr(GetRecordCount);

Open in new window

0
LelikInsideCommented:
Why don't you use something like Q_MY.Count? instead of the cycle
0
Andrea MatthiaeSoftware engineeringAuthor Commented:
Hi,
sorry LelikInside but the problem is not to get the Count of the array!
This is only an example! Please read the question.

For jimyX for the "Stop on Delphi Exceptions"  thanks!  
This can be solve the problem. But is very strange that I must use this system to ignore the error.




0
Ephraim WangoyaCommented:

"Stop on Delphi Exceptions"
This does not stop the problem, it just masks it so its not displayed
0
Andrea MatthiaeSoftware engineeringAuthor Commented:
Yes, this not solve the problem.

I have try this two code and after I try close the project with the FormClose (see in the code).
After the project stay in memory and I can see it in the Windows Task Manager.
I must use the "Program reset" (Ctrl+F2) in Delphi to remove the .EXE form the memory!
This only happens when I try to read a TABLE or VIEW with more tha 1000-5000 records.
There is a system to release the memory of the TIBQuery?

I have Incresead the point value.
// 1
var
   Q_MY: TIBQuery;
   record_number:longint;
begin
   Button1Click(Sender);
   Q_MY:=TIBQuery.Create(nil);
   try
      Q_MY.Database:=B1.IBDatabase;
      Q_MY.Close;
      Q_MY.Sql.Clear;
      Q_MY.Sql.Add('SELECT * FROM VISTA_HP_03');
      Q_MY.Open;
      Q_MY.First;
      record_number:=0;
      while not Q_MY.eof do
      begin
         inc(record_number);
         Q_MY.Next;
      end;
      caption:=inttostr(record_number);
   finally
      Q_MY.Close;
      Q_MY.Free;
   end;
end;


// 2
var
  Q_MY: TIBQuery;
  record_number:longint;
begin
   Button1Click(Sender);
  Q_MY:=TIBQuery.Create(nil); //use nil, no need to attach other components
  try
    Q_MY.Database:=B1.IBDatabase;
    Q_MY.Sql.Add('SELECT * FROM VISTA_HP_03');
    Q_MY.Active := True;
    record_number:=0;
    while not Q_MY.eof do
    begin
       inc(record_number);
       Q_MY.Next;
    end;
    caption:=inttostr(record_number);
    Q_MY.Active := False;
  finally
    FreeAndNil(Q_MY);
  end;


procedure MY_FORM.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
   B1.IBDatabase.ForceClose;
   Action:=caFree;
end;

Open in new window

0
Ephraim WangoyaCommented:

You may be trying to close the application when the loop is still being processed.

Try this, add a variable to indicate you are closing your application

  private
     FAppClosing: Boolean;
var
  Q_MY: TIBQuery;
  record_number:longint;
begin
   Button1Click(Sender);
  Q_MY:=TIBQuery.Create(nil); //use nil, no need to attach other components
  try
    Q_MY.Database:=B1.IBDatabase;
    Q_MY.Sql.Add('SELECT * FROM VISTA_HP_03');
    Q_MY.Active := True;
    record_number:=0;
    while not (Q_MY.eof or FAppClosing) do
    begin
       inc(record_number);
       Q_MY.Next;
       Application.ProcessMessages; 
    end;
    caption:=inttostr(record_number);
    Q_MY.Active := False;
  finally
    FreeAndNil(Q_MY);
  end;

procedure MY_FORM.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
   FAppClosing := True; //this should stop your loop
   B1.IBDatabase.ForceClose;
   Action:=caFree;
end;

Open in new window

0
Andrea MatthiaeSoftware engineeringAuthor Commented:
Sorry, I don't want to stop the application in the loop.
The memory problem is when I try to close the application (my project.exe with a normal "Close" button that call the FormClose) after a complete execution of the query and only if the query read many records.
0
Ephraim WangoyaCommented:

How do your create and close your form?

do you use code similar to this
   form := TForm.Create(Self);
   try
      form.showmodal;
   finally
     FreeAndNil(form);
   end;

or do you use
   Form.Show;
0
Andrea MatthiaeSoftware engineeringAuthor Commented:
I use Form.Show;
0
Ephraim WangoyaCommented:

Change your form close to

procedure MY_FORM.FormClose(Sender: TObject;  var Action: TCloseAction);
begin
   B1.IBDatabase.ForceClose;
   Action := caNone;  //let the application worry about freeing the form since you dont create it
end;
0
Geert GOracle dbaCommented:
aren't you missing TForm and My_Form ????
 
type
  [b]TMy_Form[/b] = class(TForm)
  end;

implementation

procedure [b]TMy_Form[/b].FormClose(Sender: TObject);
begin
end;

Open in new window


never use "procedure My_Form.FormClose"

the type name should be the same as the header for the procedure name

procedure TYPE_NAME.proc_name


My_Form is an instance of type TMy_Form

You understand the difference between an instance and a class ?
0
Andrea MatthiaeSoftware engineeringAuthor Commented:
Yes I know the difference. I have rename the form for this example... see it like

procedure TMY_FORM.FormClose(Sender: TObject;  var Action: TCloseAction);
begin
   B1.IBDatabase.ForceClose;
   Action := caNone;  //let the application worry about freeing the form since you dont create it
end;

0
Ephraim WangoyaCommented:

Another thing to consider, since these forms are autocreated, is B1 still valid at this point
Check with this

procedure TMY_FORM.FormClose(Sender: TObject;  var Action: TCloseAction);
begin
   if Assigned(B1) then
      B1.IBDatabase.ForceClose;
   Action := caNone;  //let the application worry about freeing the form since you dont create it
end;
0
Andrea MatthiaeSoftware engineeringAuthor Commented:
I have find the problem!

I have in the DataModule the component IBSQLMonitor that stay at true!
When I do the:

IBSQLMonitor1.Enabled:=False

all works well!
I think that this is a IB Component bug.
0
Ephraim WangoyaCommented:

Thats good, also just take into account the advice I gave you in my comments, they will be very useful to you

cheers
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Andrea MatthiaeSoftware engineeringAuthor Commented:
In fact I could not explain why I had all these problems for some code that I used so many times!

Thanks anyway to all
0
Andrea MatthiaeSoftware engineeringAuthor Commented:
Yes... you have help me to find the problem...
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.