*********************************** *- thisform.SaveChanges pseudo-code *********************************** Loop through all members of DE getting a list of dirty buffers into array laBuffers llLogging = .T. && or .F.; <user has turned on logging function> llRollBack = .F. && initialized for clarity BEGIN TRANSACTION Loop through all members of dirty buffers array laBuffers IF NOT thisform.MyTableUpdate(1,.F.,<dirty buffer alias>,llLogging,1) llRollBack = NOT thisform.Resolve(<dirty buffer name>) ENDIF END loop IF llRollBack ROLLBACK thisform.DoRevert() && TABLEREVERT() all dirty buffers ELSE END TRANSACTION ENDIF RETURN NOT llRollBack ******************************* *- thisform.Resolve pseudo-code ******************************* USE AFIELDS() to loop through all fields checking for field collisions IF any found, give user an option to manually resolve *- in current problem, there are NO field collisons ENDIF endloop *- now force a table update RETURN thisform.MyTableUpdate(0,.T.,<dirty buffer alias>,llLogging,3) ************************************* *- Actual thisform.MyTableUpdate Code ************************************* LPARAMETERS tnRows,tlForce,tcTableAlias,tlLogging,tnCalledFrom LOCAL ; lnCount,; llReturn,; laErrorArray[1],; lcMessage,; lnI,; lnMax,; lnDelay,; lnFlush WITH thisform lnMax = .nMaxTries && set at 10 by default lnDelay = .nDelay && set at 0.05 by default ENDWITH lnCount = 0 DO WHILE lnCount < lnMax AND !llReturn llReturn = TABLEUPDATE(tnRows,tlForce,tcTableAlias,'laErrorArray') lnFlush = SYS(1104) && this added at Microsoft Tech Support's suggestion IF !llReturn IF tlLogging IF lnCount = 0 = AERROR(laErrorArray) && Data from most recent error lcMessage = 'Source = ' + TRANSFORM(tnCalledFrom) + '; flush = ' + TRANSFORM(lnFlush) + '; ' FOR lnI = 1 TO 7 && Display all elements of the error array lcMessage = lcMessage + TRANSFORM(lnI) + ': ' + TRANSFORM(laErrorArray(lnI)) + CRLF ENDFOR ELSE lcMessage = 'Attempt # ' + TRANSFORM(lnCount) + ', delay = ' + TRANSFORM(lnDelay) + ', flush = ' + TRANSFORM(lnFlush) ENDIF oLogger.LogMileStone('TABLEUPDATE failed: ' + tcTableAlias + ', ' + lcMessage) ENDIF lnCount = lnCount + 1 =INKEY(lnDelay,'HM') ENDIF ENDDO RETURN llReturnThe above version of the MyTableUpdate() code solves the problem on my development network,
*- Revised thisform.MyTableUpdate code LPARAMETERS tnRows,tlForce,tcTableAlias,tlLogging,tnCalledFrom LOCAL ; lnCount,; llReturn,; laErrorArray[1],; lcMessage,; lnI,; lnMax,; lnDelay,; lnFlush,; lnOldSetReprocess WITH thisform lnMax = .nMaxTries && set at 10 by default lnDelay = .nDelay && set at 0.05 by default ENDWITH lnOldSetReprocess = SET('REPROCESS') SET REPROCESS TO 1 lnCount = 0 DO WHILE lnCount < lnMax AND !RLOCK('0',tcTableAlias) WAIT 'Save Changes waiting for lock' WINDOW TIMEOUT 1 lnCount = lnCount + 1 ENDDO llReturn = TABLEUPDATE(tnRows,tlForce,tcTableAlias,'laErrorArray') UNLOCK ALL && also tried UNLOCK RECORD 0 here, no difference lnFlush = SYS(1104) IF !llReturn AND tlLogging = AERROR(laErrorArray) && Data from most recent error lcMessage = 'Source = ' + TRANSFORM(tnCalledFrom) + '; flush = ' + TRANSFORM(lnFlush) + '; ' FOR lnI = 1 TO 7 && Display all elements of the error array lcMessage = lcMessage + TRANSFORM(lnI) + ': ' + TRANSFORM(laErrorArray(lnI)) + CRLF ENDFOR oLogger.LogMileStone('TABLEUPDATE failed: ' + tcTableAlias + ', ' + lcMessage) ENDIF SET REPROCESS TO (lnOldSetReprocess) RETURN llReturn