`BB_GetLockedRecordList(->Table or IndexedField;ReturnLockedRecordsSetName)
  `By: Tony Ringsmuth of Business Brothers, Inc, 01/21/10, 15:17:36

  `FUNCTION: 
  `Find a list of all locked records in Table.
  `Note: in order to work, the specified table must have at least one queryable field.  (All tables should)
  `Return, either in $2 set name, or in Current Selection, the list of locked records.
  `Requires 4D Version 11.0 or higher.  (tested with V11.5)

  `01/21/2010: Performance Note: testing on a table of about 2 million records, this method took about 7 seconds to run on a moderatly fast PC.
  `     During those 7 seconds, the server was at near 100% of activity.

  `--------------------------------------------------------------------------------
  `PARAMETERS
  `$1: Pointer to a Table, or a Field (prefferably an indexed field)
  `$2: Text: optional:  If passed, and not null, then this is a set name in which to return the list of locked records.

  `--------------------------------------------------------------------------------
  `REVISION HISTORY
  `01/21/10: New

  `--------------------------------------------------------------------------------
C_POINTER($1;$pTable;$pField)
C_TEXT($2;$LockedRecordsSetName)

C_LONGINT($iTable)
Case of 
	: (Count parameters<1)
		ALERT("Method: \"BB_GetLockedRecordList\" requires at least one parameter.")
		
	: (Nil($1))
		ALERT("Method: \"BB_GetLockedRecordList\" $1 was nil.")
		
	: (Is a variable($1))
		ALERT("Method: \"BB_GetLockedRecordList\" $1 was not a pointer to a Table or a Field.")
		
	Else 
		$pField:=$1
		
		$iTable:=Table($pField)
		$pTable:=Table($iTable)
		
		$LockedRecordsSetName:=""
		If (Count parameters>1)
			$LockedRecordsSetName:=$2
		End if 
		
		If (Length($LockedRecordsSetName)=0)
			$LockedRecordsSetName:="_BBLockedRecordList"
		Else 
			CUT NAMED SELECTION($pTable->;"BB_MyPreviousSel")
		End if 

		C_LONGINT($iTable;$iFieldCtr;$iType;$iLength;$iTextFieldNum)
		C_BOOLEAN($bIndex)
		
		If (Field($pField)=0)
			  `If the developer has passed a pointer to the table (not a field in the table), then try to find an indexed field to query on.
			For ($iFieldCtr;1;Get last field number($iTable))
				If (Is field number valid($iTable;$iFieldCtr))
					GET FIELD PROPERTIES($iTable;$iFieldCtr;$iType;$iLength;$bIndex)
					If ($bIndex)
						$pField:=Field($iTable;$iFieldCtr)
						$iFieldCtr:=Get last field number($iTable)  `Exit the loop: we've found an indexed field.
					End if 
				End if 
			End for 
		End if 
		If (Field($pField)=0)
			  `No indexed field has been found: find any query-able field
			$iTextFieldNum:=-1
			For ($iFieldCtr;1;Get last field number($iTable))
				If (Is field number valid($iTable;$iFieldCtr))
					GET FIELD PROPERTIES($iTable;$iFieldCtr;$iType;$iLength;$bIndex)
					Case of 
						: ($iType=Is Integer ) | ($iType=Is LongInt ) | ($iType=Is Real ) | ($iType=Is Integer 64 bits ) | ($iType=Is Float ) | ($iType=Is Alpha Field ) | ($iType=Is Date ) | ($iType=Is Boolean )  `Skip Text fields
							$pField:=Field($iTable;$iFieldCtr)
							$iFieldCtr:=Get last field number($iTable)  `Exit the loop: we've found an indexed field.
							
						: ($iType=Is Text )
							$iTextFieldNum:=$iFieldCtr
					End case 
				End if 
			End for 
			If ((Field($pField)=0) & ($iTextFieldNum>-1))
				$pField:=Field($iTable;$iTextFieldNum)  `Last ditch effort: use a text field.
			End if 
		End if 
		
		If (Field($pField)=0)
			ALERT("Method: \"GetLockedRecordList\": Can't find a field to query by.")
		Else 
			
			C_LONGINT($iType)
			$iType:=Type($pField->)
			
			ALL RECORDS($pTable->)
			CREATE SET($pTable->;"Remain_To_Check")
			CREATE EMPTY SET($pTable->;$LockedRecordsSetName)
			CLEAR SET("Lockedset")
			
			START TRANSACTION
			SET QUERY AND LOCK(True)
			
			$bDone:=False
			Repeat 
				
				USE SET("Remain_To_Check")
				Case of 
					: ($iType=Is Integer ) | ($iType=Is LongInt ) | ($iType=Is Real ) | ($iType=Is Integer 64 bits ) | ($iType=Is Float ) | ($iType=Is Time )
						  `Warning :This query won't find NANs
						QUERY SELECTION($pTable->;$pField->=0;*)
						QUERY SELECTION($pTable->; | ;$pField->#0)
						
					: ($iType=Is Alpha Field ) | ($iType=Is Text )
						QUERY SELECTION($pTable->;$pField->="@")
						
					: ($iType=Is Date )
						QUERY SELECTION($pTable->;$pField->=!00/00/00!;*)
						QUERY SELECTION($pTable->;$pField->>!00/00/00!)
						
					: ($iType=Is Boolean )
						QUERY SELECTION($pTable->;$pField->=True;*)
						QUERY SELECTION($pTable->;$pField->=False)
						
				End case 
				
				If (ok=0)
					If (Records in set("Lockedset")>0)
						UNION("Lockedset";$LockedRecordsSetName;$LockedRecordsSetName)
						DIFFERENCE("Remain_To_Check";"Lockedset";"Remain_To_Check")
					End if 
				Else 
					$bDone:=True
				End if 
				
			Until ($bDone)
			SET QUERY AND LOCK(False)
			CANCEL TRANSACTION
			
			CLEAR SET("Lockedset")
			CLEAR SET("Remain_To_Check")
			
			If ($LockedRecordsSetName="_BBLockedRecordList")
				  `User did not pass a set name: the output will be the current selection of records.
				USE SET("_BBLockedRecordList")
				CLEAR SET("_BBLockedRecordList")
			Else 
				  `User passed a set name: the output will be the specified set.  Unload any records.
				USE NAMED SELECTION("BB_MyPreviousSel")
			End if 
		End if 
End case 
  `