Alaska Software Inc. - Problems with dbregisterclient() function
Username: Password:
AuthorTopic: Problems with dbregisterclient() function
Milorad Milivoj+¬aProblems with dbregisterclient() function
on Wed, 25 Jul 2018 20:00:41 +0200
Hallo, colleagues.

I am using Xb++ 1.90, in character mode, DBFCDX drivers.

I want to introduce automatic timestamp creating to every record of every
table of my database, for append, replace and delete events.  I find that
dbregisterclient() function can do much for me.

For every table that my application open, I create an object variable from
class with :Notify() method, and register current work area with that
variable.  My idea was to update timestamp columns in :Notify() method, based
on events "append", "update" and "delete".

But, problems arised.

= Problem 1
When deleting a record, :Notify() event did fired with "update" event, not
with "delete" event.  OK, I understand it, because DBF driver do not remove
record from table, just mark it for deletion (marking is more like "updating").
That was not big problem - I agreed that deleting is just specific "updating".

= Problem 2
When deleting record, deleted record was not publicly visible as "deleted"
before current record pointer move to another record, so as consequence,
:Notify() method was not arised before skipping to other record.
OK, I skip to next record, than return to original record, write timestamp and
finish task.
But, in meantime - immediately after skip, :Notify() method do something
"ingenious" - it delete BOTH records, and make second (auxiliary) record
EXACTLY SAME as main record, just as it would be if I copy every column value
from first to second record!
I spent 3 days to investigate what happends, and finaly make a solution -
write one more function level, where program remember what have to be done and
- when main record became visible as deleted - go to it and update timestamp.

= Problem 3
At very start of program, I have this situation:
- open two very small tables
- lock both tables with file locks
- make changes to both of them (appending some records and updating others)
- unlock both tables
- close both tables with dbclosearea() function

After succesfuly finishing all tasks (except last), program fails with error
message "Lock is required for this operation" with error "operation" property
value equal "dbclosearea".  Why any lock would be needed for closing table?

OK, with memory buffers in mind, I then put COMMIT before closing tables, but
with no changes.

When I block-out that program segment, same happends at first next unlockall()
function call, with exact same error message!  Xbase tells me that I need to
lock table when I want to unlock it!!!

For check myself, then I just blocked new idea with opposite preprocessor
directive, and every operations works well, just as for years before.

I spent more than a week for this problem, and can not go any step behind it!
 On the other hand, I don't want to throw-out this improvement.

Who have deeper experience with dbregisterclient() function?
Any suggestion can make great change.  Thanks in advance.

Milorad
Jim LeeRe: Problems with dbregisterclient() function
on Wed, 25 Jul 2018 21:34:58 +0200
hi,

show us your Notify Methode

you got DBO_MOVE_PROLOG before move and DBO_MOVE_DONE when ready

so where do you have
DBO_TABLE_UPDATE
DBO_TABLE_DELETED
DBO_TABLE_APPEND
:
Milorad Milivoj+¬aRe: Problems with dbregisterclient() function
on Sat, 28 Jul 2018 11:24:16 +0200
Thank you for your answer, Jim.

I confess that I did not even look at events you mention.
One of the clearest versions of my :Notify() event follows:


METHOD SinhroLog:Notify(tnEvent, mp1, mp2)
   local lcOldAlias:=alias(), llWriteDone:=.T.

   if tnEvent <> xbeDBO_Notify
      return ( self )
   endif

   dbselectarea(::cAlias)

   DbSuspendNotifications()

   while .t.
      do case
         case mp1 == DBO_TABLE_APPEND
            if fieldpos( ::cAlias+'_CTIME' ) > 0
                update date/time column for "Creating" record
               fieldput(fieldpos(::cAlias+'_CTIME'), SetUpdTime())
            endif

         case mp1 == DBO_TABLE_UPDATE
            if fieldpos( ::cAlias+'_UTIME' ) > 0
                update date/time column for "Updating" record
               fieldput(fieldpos(::cAlias+'_UTIME'), SetUpdTime())
            endif

         case mp1 == DBO_TABLE_DELETED
            if fieldpos( ::cAlias+'_UTIME' ) > 0
                update date/time column for "Updating" record
               fieldput(fieldpos(::cAlias+'_UTIME'), SetUpdTime())
            endif

         otherwise
             non-writable events
            llWriteDone := NE
      endcase

      if llWriteDone
          set some object variables ...
          ...
      endif

      exit
   enddo

   DbResumeNotifications()

   if not empty(lcOldAlias)
      dbselectarea(lcOldAlias)
   endif
RETURN ( self )


Milorad



Jim Lee wrote in message news:735fad77$1285bd31$3d3c@news.alaska-software.com...
>hi,
>
>show us your Notify Methode
>
>you got DBO_MOVE_PROLOG before move and DBO_MOVE_DONE when ready
>
>so where do you have
>DBO_TABLE_UPDATE
>DBO_TABLE_DELETED
>DBO_TABLE_APPEND
>: