FUNCTION GetID( tcTable, tcIDField, tcIDIndexExp ) IF VARTYPE( tcTable ) <> "C" .OR. !USED( tcTable ) RETURN 0 ENDIF LOCAL lcTable, lcIDField, lcIDIndexExp, lnSelect, lnBuffering, llCloseIDs, lnID, lnI, lnLoops IF VARTYPE( tcIDField ) <> "C" lcIDField = "ID" ENDIF IF VARTYPE( tcIDIndexExp ) <> "C" lcIDIndexExp = lcIDField ENDIF lcTable = UPPER( TRIM( tcTable ) ) *!* Note where we came from lnSelect = SELECT() *!* Open the table of IDs table IF !USED( 'ids' ) USE IDTable IN 0 llCloseIDs = USED( 'IDs' ) ENDIF *!* We want the table to update immediately. LOCAL lnBuffering lnBuffering = CURSORGETPROP('buffering','IDs') IF lnBuffering # 1 CURSORSETPROP('buffering','IDs',1) ENDIF IF !INDEXSEEK(lcTable, .F., 'IDs', "TableName" ) IF FLOCK('IDs') INSERT INTO IDs ( 'TableName', 'ID' ) VALUES (lcTable, MINKEY) UNLOCK ELSE *!* TODO: reset environment before returning. RETURN 0 ENDIF ELSE lnID = IIF( BETWEEN( IDs.ID, MINKEY, MAXKEY ), MINKEY, IDs.ID ) ENDIF lnLoops = MAXKEY - MINKEY + 1 RLOCK( 'IDs' ) llOK = !INDEXSEEK(lnID, .F., lcTable, lcIDIndexExp ) lni = 1 DO WHILE !llOK *!* Increment and Keep hunting for an unused ID UNLOCK lnI = lnI + 1 lnID = lnID + 1 RLOCK( "IDs" ) llOK = !INDEXSEEK(lnID, .F., lcTable, lcIDIndexExp ) .AND. lnID < MAXKEY && lnLoops ENDDO IF llOK *!* We have a good ID REPLACE ID WITH lnID + 1 IN IDs UNLOCK IN 'IDs' ELSE UNLOCK lnID = MINKEY DO WHILE SEEK( lcTable, lnID, lcIDIndexExp ) .AND. lnI < lnLoops *!* Keep hunting for an unused ID lnI = lnI + 1 lnID = lnID + 1 RLOCK( 'IDs' ) llOK = !INDEXSEEK( lnID, .F., lcTable, lcIDIndexExp ) .AND. lnID < lnLoops ENDDO IF llOK *!* We have a good ID REPLACE ID WITH lnID + 1 IN IDs ENDIF UNLOCK ENDIF IF llCloseIDs USE IN IDs ELSE CURSORSETPROP( 'buffering', lnBuffering, 'IDs' ) ENDIF RETURN lnID ENDFUNC