Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TCustomADODataSet catching EOleException (not EDatabaseError)

Tags:

delphi

ado

In some situation (in a multi-user environment) when I Edit a TADODataSet and Post it, I get an Exception raised by ADO:

"Row cannot be located for updating. Some values may have been changed since it was last read."

If I run my program from the IDE the exception is raised as EOleException with Error number -2147217864.
I want to be able to catch this exception, but when I run the program outside the IDE the exception is raised as EDatabaseError which does not have the ErrorCode I need to examine. Here is part of my code:

procedure TForm1.DataSetCommit(ds: TADODataSet);
begin
  ds.Connection.BeginTrans;
  try    
    try
      ds.Post; // <- Exception is raised here
    except
      on E: EOleException do; // EOleException is NOT fired! (E.ErrorCode = -2147217864) - see "ADODB.TCustomADODataSet.InternalPost"
      on E: EDatabaseError do 
      begin
        // todo: Handle this situation
      end;
    end;
    ds.Connection.CommitTrans;
  except
    ds.Connection.RollbackTrans;
    raise;
  end;
end;

If you look in ADODB.TCustomADODataSet.InternalPost you will notice that it's wrapped as so:

procedure TCustomADODataSet.InternalPost;
begin
  UpdateCursorPos;
  try
    ... // <- Exception is raised here
  except
    on E: Exception do
      DatabaseError(E.Message);
  end;
  CheckForFlyAway;
end;

The exception is raised inside the local procedure UpdateData: Recordset.Update(EmptyParam, EmptyParam); which triggers a EOleException (what I need) but the wrapper raises EDatabaseError! (grrrrrrr).

My question is how do I get my hands on the original EOleException so I can query EOleException.ErrorCode?

like image 894
kobik Avatar asked Nov 02 '22 07:11

kobik


1 Answers

I've tried to utilize the System.RaiseList to get the TRaiseFrame.NextRaise to no avail - I'm not getting the desired EOleException... So I found a rather elegant solution which is specific to my case (ADO) and does not rely on the RTL - I'm testing the Errors object of the TADODataSet.Connection:

procedure TForm1.DataSetCommit(ds: TADODataSet);
begin
  ds.Connection.BeginTrans;
  try      
    try
      ds.Post;
    except          
      on E: EDatabaseError do 
      begin          
        if Assigned(ds.Connection.Errors) and (ds.Connection.Errors.Count > 0) then
          with ds.Connection.Errors.Item[0] do
            // if (Number = -2147217864) then ...
            ShowMessage(Format('Number:%d; Source:%s; Description:%s; NativeError:%d; SQLState:%s',
              [Number, Source, Description, NativeError, SQLState]));
      end;
    end;
    ds.Connection.CommitTrans;
  except
    ds.Connection.RollbackTrans;
    raise;
  end;
end;

This will be my solution to the specific problem, but I'm still interested in other ideas on how to trap the previous exception of EOleException.

like image 106
kobik Avatar answered Nov 15 '22 12:11

kobik