Select() function

This forum is meant for questions about the Visual FoxPro Language support in X#.

Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Select() function

Post by Karl-Heinz »

A question for the VFP community. i´m wondering about the behaviour of the Select() function and found this in the help:

- Select()
returns the number of the current work area, or if SET COMPATIBLE is set to ON the number of the highest unused work area.

- Select(0)
returns the number of the current work area.

- Select(1)
returns the number of the highest unused work area.

- Select ( cAlias )
returns the work area number of a given alias.

is it correct that VFP throws a exception like FP-Dos does if any other param, e.g. a number > 1 is passed ?

regards
Karl-Heinz
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am

Select() function

Post by atlopes »

Karl-Heinz,

SELECT() treats 0 and 1 differently to any other value, both working as you described.

Any other value (numeric or character) will return either the number of the current WA, if it is in use, or 0 (zero) otherwise.

For instance, SELECT(2) will either return 0 or 2; SELECT("anyName") will either return a table number or 0.

An error 17 ("Table number is invalid") will be raised if the numeric argument is outside the 0..SELECT(1) range.
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Select() function

Post by Karl-Heinz »

Hi Antonio,

thanks for your answer.

it seems that even with VFP there´s no way to select the workarea 1 via select (1) ?

regards
Karl-Heinz
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am

Select() function

Post by atlopes »

Karl-Heinz,

The SELECT() function does not select work areas. The SELECT command does, and it will select work area 1 when required.

To select work area 1:

Code: Select all

SELECT 1
* or...
LOCAL WA AS Integer

m.WA = 1
SELECT (m.WA)
* or...
SELECT A
* or...
SELECT (EVL(ALIAS(1), 1))
* or....
SELECT (VAL("1"))
(that's off the top of my head, don't know if someone else has other ideas on how to do it - but the parser is a bit clumsy here since it does not accept the SELECT (literal number or numeric operation) construct - at least, it's consistent and rejects any work area number, 1 or other).
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Select() function

Post by Karl-Heinz »

Hi Antonio,

Yes, after looking at the help again i noticed that the way to select a area is to use the SELECT command.
Any other value (numeric or character) will return either the number of the current WA, if it is in use, or 0 (zero) otherwise. For instance, SELECT(2) will either return 0 or 2; SELECT("anyName") will either return a table number or 0.
So a Select(x) with e.g. a number > 1 is just a test to see if the given area is in use ?

Code: Select all

Select 4

use table

? Select(0)  //  shows 4

? Select(5)  // shows 0 - because there´s no table in the area 5  ?

? Select(0)  //  still shows 4

? Select(4)  // shows 4 - because there´s a table in the area 4 ?

Are that the results you expect?

regards
Karl-Heinz
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am

Select() function

Post by atlopes »

Karl-Heinz, to see if a given area is in use, we should probably use the USED() logical function instead. It will work even with work area #1.

Regarding your example, just a note: a SELECT command selects a work area even if there is no table open. So,

Code: Select all

SELECT 5

? SELECT(5)    && prints 0
? SELECT(0)    && prints 5
I would say that calling the SELECT() function with a string argument is what makes more sense most of the time, besides calling it with 0. Of course, while dealing with the implementation of VFP behavior, we must consider variations as much as we can, even when they may seem odd, now and then.
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Select() function

Post by Karl-Heinz »

Hi Antonio,
Regarding your example, just a note: a SELECT command selects a work area even if there is no table open.
Yes, VO works the same way.

i put the pieces together, and i think all the different Fox Select() options are working now as expected - at least i hope so ;-)

some notes:

- The modified Select() function works now different if the Foxpro dialect is active.
- the max work area number in X# is 4096.
- the SET COMPATIBLE command is not yet available, so i´m using the global var "glSetCompatibleOn" to simulate a SET COMPATIBLE ON/OFF
- before you run the code you should check the path where the required dbf is created.
cPath := "d:test"

Code: Select all

GLOBAL glSetCompatibleOn := FALSE AS LOGIC // simulates the Fox SET COMPATIBLE ON/OFF setting

FUNCTION TestSelect() AS VOID 
LOCAL cPath, cDBF AS STRING	

	SET EXCLUSIVE OFF
	
	
 	cPath := "d:test" 
 	
	cDBF := cPath + "Foo.dbf" 
	
	
	? DbCreate( cDBF , { { "LAST" , "C" , 20 , 0 }} )
	?
	 
	
	SELECT a
	USE (cdbf) ALIAS Foo1 
	
	SELECT b
	USE (cdbf) ALIAS Foo2

	SELECT 4
	USE (cdbf) ALIAS Foo3 
	
	
	// This seems to be the only way to detect the *lowest* unused area,
	// or does Fox offer another option ?
	
	SELECT 0
	? "currently lowest unused area:" , select(0)  // ok, 3 
	SELECT 4
		

 	?
    glSetCompatibleOn := FALSE 
    
	? "SET COMPATIBLE " + iif ( glSetCompatibleOn , "ON" , "OFF" )  
	? "Select()  == 4         " , Select()  == 4  
	? "Select(0) == 4         " , Select(0) == 4
	? "Select(1) == 4096      " , Select(1) == 4096
	? 'Select ( "foo2" ) == 2 ' , Select ( "foo2" ) == 2
	? 'Select ( 3 ) == 0      ' , Select(3) == 0    


	// ------------------- 
	
	? 
	
	// ------------------- 
	
	   
	glSetCompatibleOn := TRUE 
	
	? "SET COMPATIBLE " + iif ( glSetCompatibleOn , "ON" , "OFF" )  
	? "Select()  == 4096      " , Select()  == 4096
	? "Select(0) == 4         " , Select(0) == 4
	? "Select(1) == 4096      " , Select(1) == 4096
	? 'Select ( "foo2" ) == 2 ' , Select ( "foo2" ) == 2
	? 'Select ( 3 ) == 0      ' , Select(3) == 0    
	
	// ------------------- 
	 	
	?
	glSetCompatibleOn := FALSE 
	? "SET COMPATIBLE " + iif ( glSetCompatibleOn , "ON" , "OFF" )  
    ? "Select ( 7 ) == 0      ", Select(7) == 0
	? 'Select ( "Foo4" ) == 0 ', Select ( "Foo4" ) == 0  
	? 'Select ( "Foo3" ) == 4 ', Select ( "Foo3" ) == 4 
	? 'Select ( "Foo1" ) == 1 ', Select ( "Foo1" ) == 1
	? "Select ( 4095 ) == 0   " , Select(4095) == 0  
	? "Select ( 4096 ) == 0   " , Select(4096) == 0  
//	? "Select ( 4097 ) == 0   " , Select(4097) == 0 // this would throw a exception !		
    
	? 

	? "lowest unused area: " , RuntimeState.Workareas.FindEmptyArea( TRUE )  // ok, 3 
	? "highest unused area:" , RuntimeState.Workareas.FindEmptyArea( FALSE )   
	
    ?
    
	CLOSE DATABASES
	
	? "lowest unused area: " , RuntimeState.Workareas.FindEmptyArea( TRUE ) // ok, 1  
	? "highest unused area:" , RuntimeState.Workareas.FindEmptyArea( FALSE )   
	
	RETURN 			

// This Select() function extends the GitHub Select() code:
// https://github.com/X-Sharp/XSharpPublic/blob/feature/Runtime/Runtime/XSharp.RT/RDD/Db.prg#L16	
FUNCTION Select(uWorkArea) AS USUAL CLIPPER
    LOCAL sSelect   AS DWORD
	LOCAL sCurrent  AS DWORD
	 
	
	IF RuntimeState.Dialect == XSharpDialect.FoxPro  // KHR 
		
		// handles an alias string or a uWorkArea number > 1 
		IF IsString ( uWorkArea  ) .OR. ( IsNumeric ( uWorkArea )  .AND. uWorkArea > 1 ) 
			
			// Throws a exception if the uWorkArea number is > 4096 !
			IF IsNumeric ( uWorkArea ) .AND. uWorkArea > RuntimeState.Workareas.FindEmptyArea( FALSE )
				THROW ArgumentException{}				
			ENDIF 	 
			
			
			// note: No exception is thrown if a alias name doesn´t exist !
			
			sCurrent := VoDbGetSelect()  // save the current workarea
			
			sSelect := _Select(uWorkArea)  // activates temporary the area 
			
			// IF ! Used()		
			IF ! (sSelect) -> Used()
				sSelect := 0
			ENDIF 				
			
			VoDbSetSelect(INT(sCurrent))  // restore the workarea		 
		
		ELSE 		
			
			VAR lGetCurrentAreaNumber := ( PCount() == 1 .AND. IsNumeric( uWorkArea ) .AND. uWorkArea == 0 )
			VAR lGetHighestUnusedAreaNumber := ( PCount() == 1 .AND. IsNumeric( uWorkArea ) .AND. uWorkArea == 1 )
		
			// handles Select(), Select(0), Select(1) and takes care of 
			// the - not yet implemented - SET COMPATIBLE ON/OFF setting. 
			
			IF PCount() == 0 .OR. lGetHighestUnusedAreaNumber .OR. lGetCurrentAreaNumber 
			
				IF lGetHighestUnusedAreaNumber .OR. ( PCount() == 0 .AND. glSetCompatibleOn )  
					// get the number of the highest unused work area 
					sSelect := RuntimeState.Workareas.FindEmptyArea( FALSE )
				
				ELSE // Pcount()== 0 or lGetCurrentAreaNumber 
					sSelect := VoDbGetSelect()
								
				ENDIF 
			
			ELSE
				// Throw a exception if uWorkArea is something else  	
				THROW ArgumentException{}
			ENDIF 
			
		ENDIF 
		
	ELSE  // This is the already existing Select() code.
		
		sCurrent := VoDbGetSelect()
		sSelect := _Select(uWorkArea)
		VoDbSetSelect(INT(sCurrent))		 
			 
	ENDIF 	

	RETURN sSelect 
	


regards
Karl-Heinz
atlopes
Posts: 83
Joined: Sat Sep 07, 2019 11:43 am

Select() function

Post by atlopes »

Karl-Heinz, it seems to be quite complete. Good work!
Karl-Heinz
Posts: 774
Joined: Wed May 17, 2017 8:50 am

Select() function

Post by Karl-Heinz »

Hi Antonio,

good to know that it works. But i´m still wondering why my FP 2.0 doesn´t accept a area number > 1. it doesn ´t matter if a area is in use or not, i always get the strange error "Länge oder Decimalwert falsch" -> "Wrong length or decimal value". Anyway, it seems that FP didn't support a value > 1 earlier.

About how to get/set global settings like "COMPATIBLE"

According the help it works this way:

Set ( "COMPATIBLE" ) // returns "ON" or "OFF"

Set ( "COMPATIBLE" , "ON" | "OFF" ) // sets the value

but there are other settings that require an additional param like:

"ALTERNATE"
"ALTERNATE", 1

I´ll open a thread regarding the Set() function in the next few days.

regards
Karl-Heinz
User avatar
Eric Selje
Posts: 31
Joined: Sun Sep 22, 2019 3:16 pm

Select() function

Post by Eric Selje »

Karl-Heinz, did this make it into the latest build? I'm trying to do this:

Code: Select all

USE IN SELECT("ToDos")
Which essentially means, close that ToDos workarea if it's open. It doesn't change the current workarea, and doesn't throw an area if ToDos is not open. But I'm currently getting the error

SELECT("ToDos") is not a current workarea.

I tried adding a dbcmd.xh translation for it but had no luck. It's essentially

Code: Select all

iSelect = SELECT()
If CoreDb.SymSelect("ToDos") > 0
   CoreDb.CloseArea()    && It would actually be nice if CloseArea accepted an alias name
End
SELECT (iSelect)
I did get this to work, but it's not VFP-like:

Code: Select all

USE IN  (CoreDb.SymSelect("ToDos"))
Eric
Post Reply