Page 1 of 1

Save cached updates.

Posted: 23.06.2007, 07:49
by Dennica
Hello there! Sorry my bad english...
I will try to explain an essence of a problem and its decision offered by me.

I use zeosdbo-6.5.1-alpha_cvs_13-10-2005 in DBS2007

In some cases I should edit at once some records containing in ZQuery, therefore I use CachedUpdates=True. After editing for record of changes in a DB I use the following code.

Code: Select all

conZC.StartTransaction;
try
  qryZQ.ApplyUpdates;
  ...
  qryZ.CommitUpdates;
  conZC.Commit;
except
  on E: Exception do begin
    conZC.Rollback;
    if Pos('duplicate key violates unique constraint ...', E.Message) > 0 then begin
      ...
      Exit;
    end;
    Raise;
  end;
end;
In a case when at preservation on a server there is an error, occurs rollback transaction. In this case happens that the changed records are lost some. Since at save cached changes they leave at once from CachedResultSet not waiting commit transactions. To correct it I has changed source in modules ZDbcCachedResultSet.pas and ZAbstractDataset.pas. :oops:

Code: Select all

//ZDbcCachedResultSet.pas

{**
  Posts all saved updates to the server.
}
procedure TZAbstractCachedResultSet.PostUpdates;
var           // + Dennica
  i: integer; // + Dennica
begin
  CheckClosed;
  if FInitialRowsList.Count > 0 then
  begin
    i := 0; // + Dennica
// - Dennica    while FInitialRowsList.Count > 0 do
    while i < FInitialRowsList.Count do
    begin
// - Dennica      OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[0]);
// - Dennica      NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[0]);
      OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[i]); // + Dennica
      NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[i]); // + Dennica

      { Updates default field values. }
      if NewRowAccessor.RowBuffer.UpdateType = utInserted then
        CalculateRowDefaults(NewRowAccessor);

      { Posts row updates and processes the exceptions. }
      PostRowUpdates(OldRowAccessor, NewRowAccessor);

      { If post was Ok - update the row update type. }
// - Dennica     if NewRowAccessor.RowBuffer.UpdateType <> utDeleted then
// - Dennica     begin
// - Dennica       NewRowAccessor.RowBuffer.UpdateType := utUnmodified;
// - Dennica       if (FSelectedRow <> nil)
// - Dennica         and (FSelectedRow.Index = NewRowAccessor.RowBuffer.Index) then
// - Dennica         FSelectedRow.UpdateType := utUnmodified;
// - Dennica     end;

      { Removes cached rows. }
// - Dennica      OldRowAccessor.Dispose;
// - Dennica      FInitialRowsList.Delete(0);
// - Dennica      FCurrentRowsList.Delete(0);
      Inc(i); // + Dennica
    end;
  end;
end;

{+ Dennica =)}
procedure TZAbstractCachedResultSet.CommitUpdates;
begin
  CheckClosed;
  if FInitialRowsList.Count > 0 then
  begin
    while FInitialRowsList.Count > 0 do
    begin
      OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[0]);
      NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[0]);

      { If post was Ok - update the row update type. }
      if NewRowAccessor.RowBuffer.UpdateType <> utDeleted then
      begin
       NewRowAccessor.RowBuffer.UpdateType := utUnmodified;
       if (FSelectedRow <> nil)
         and (FSelectedRow.Index = NewRowAccessor.RowBuffer.Index) then
         FSelectedRow.UpdateType := utUnmodified;
      end;

      { Removes cached rows. }
      OldRowAccessor.Dispose;
      FInitialRowsList.Delete(0);
      FCurrentRowsList.Delete(0);
    end;
  end;
end;

{**
  Switched the cached updates mode.
  @param Value boolean flag which turns on/off the cached updates mode.
}
procedure TZAbstractCachedResultSet.SetCachedUpdates(Value: Boolean);
begin
  if FCachedUpdates <> Value then
  begin
    FCachedUpdates := Value;
    if not FCachedUpdates then begin
      PostUpdates;
      CommitUpdates; // + Dennica
    end;
  end;
end;


{**
  Inserts the contents of the insert row into this
  <code>ResultSet</code> object and into the database.
  The cursor must be on the insert row when this method is called.
}
procedure TZAbstractCachedResultSet.InsertRow;
var
  TempRow: PZRowBuffer;
begin
  CheckClosed;

  { Creates a new row. }
  TempRow := FRowAccessor.RowBuffer;
  FRowAccessor.Alloc;
  FRowAccessor.MoveFrom(FInsertedRow);
  FRowAccessor.RowBuffer^.UpdateType := utInserted;
  FRowAccessor.RowBuffer^.Index := GetNextRowIndex;

  AppendRow(FRowAccessor.RowBuffer);

  { Posts non-cached updates. }
  if not FCachedUpdates then
  begin
    try
      PostUpdates;
      CommitUpdates; // + Dennica
    except
      on E: Exception do
      begin
        { Restore the previous state. }
        FRowAccessor.DisposeBuffer(FInitialRowsList[FInitialRowsList.Count - 1]);
        FInitialRowsList.Delete(FInitialRowsList.Count - 1);
        FRowAccessor.DisposeBuffer(FCurrentRowsList[FCurrentRowsList.Count - 1]);
        FCurrentRowsList.Delete(FCurrentRowsList.Count - 1);
        FRowAccessor.RowBuffer := TempRow;

        { Reraises the exception. }
        RaiseSQLException(E);
      end;
    end;
  end;

  FRowsList.Add(FRowAccessor.RowBuffer);
  LastRowNo := FRowsList.Count;
  MoveAbsolute(LastRowNo);
end;

Code: Select all

//ZAbstractDataset.pas

{**
  Clears cached updates buffer.
}
procedure TZAbstractDataset.CommitUpdates;
begin
  CheckBrowseMode;

  if CachedResultSet <> nil then
    CachedResultSet.CommitUpdates;
// - Dennica    CachedResultSet.CancelUpdates;
end;