Save cached updates.
Posted: 23.06.2007, 07:49
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.
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.
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;
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;