TCustomADODataSet catching EOleException (not EDatabaseError)

ado, delphi

Solution

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`.

Problem

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`?

Original source