This feature exists in the RDDs for many years.
Simple Syntax:
- Code: Select all Expand view RUN
dbInfo( DBI_ROLLBACK )
This rolls back any modifications (including DBDELETE() and DBRECALL()) made to the current record in the current work area.
Just like any RDBMS, RollBack does not work after COMMIT.
FWH was using this feature in TDataBase class for many years. Please see METHOD RollBack().
Limitations of DBF ROLLBACK feature:
1) Rollback works only if the record pointer is not changed. Any SKIP() operation implicitly commits the transaction.
So, we can not use this RollBack with more than one record in the same work area.
While programming we need to remember this carefully.
2) RollBack does not work with DBAPPEND(). In real time applications, we need to use some work arounds.
We already know the functions:
dbCommit() // works on current work area and
dbCommitAll() // command COMMIT.
From the next version FWH provides two new functions:
dbRollBack() and
dbRollBackAll()
Source code of these functions:
- Code: Select all Expand view RUN
function DBROLLBACK()
if DbRecordInfo( DBRI_UPDATED )
DbInfo( DBI_ROLLBACK )
endif
return nil
//----------------------------------------------------------------------------//
function DBROLLBACKALL()
local n, cAlias
for n := 1 to 255
if !Empty( cAlias := ALIAS( n ) ) .and. ( cAlias )->( RDDNAME() ) $ "DBFCDX,DBFNTX"
( cAlias )->( dbRollBack() )
endif
next
return nil
Here is a test program:
- Code: Select all Expand view RUN
- #include "fivewin.ch"
REQUEST DBFCDX
function Main()
local cCust, cStat
local cFirst, cName
USE CUSTOMER NEW SHARED ALIAS ( cCust := cGetNewAlias( "CUST" ) ) VIA "DBFCDX"
USE STATES NEW SHARED ALIAS ( cStat := cGetNewAlias( "STAT" ) ) VIA "DBFCDX"
// save values
cFirst := ( cCust )->FIRST
cName := ( cStat )->NAME
// Start testing
TRY
if ( cCust )->( RLOCK() ) .and. ( cStat )->( RLOCK() )
? "Original Values:", ( cCust )->FIRST, ( cStat )->NAME
( cCust )->FIRST := NTOCDOW( hb_RandomInt( 1, 7 ) )
( cStat )->NAME := NTOCMONTH( hb_RandomInt( 1, 12 ) )
? "Modified Values:", ( cCust )->FIRST, ( cStat )->NAME
if Alert( "CHOOSE", { "COMMIT", "ROLLBACK" }, "OPTION" ) == 1
COMMIT
UNLOCK ALL
else
dbRollBackAll()
UNLOCK ALL
endif
else
UNLOCK ALL
endif
CATCH
dbRollBackAll()
UNLOCK ALL
END
? "Final Values:", ( cCust )->FIRST, ( cStat )->NAME
// Restore Values
if ( cCust )->( RLOCK() ) .and. ( cStat )->( RLOCK() )
( cCust )->FIRST := cFirst
( cStat )->NAME := cName
COMMIT
UNLOCK ALL
endif
CLOSE DATA
return nil
Caution:
We should not modify more than one record in the same workarea.
If we want to modify more than one record in the same dbf, we need to open the same dbf in different workareas
This is not difficult. I successfully used transaction tracking with DBFs.