Page 1 of 2
Select() function
Posted: Mon Jul 20, 2020 6:56 pm
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
Select() function
Posted: Tue Jul 21, 2020 10:55 am
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.
Select() function
Posted: Tue Jul 21, 2020 12:59 pm
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
Select() function
Posted: Tue Jul 21, 2020 8:35 pm
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).
Select() function
Posted: Tue Jul 21, 2020 9:18 pm
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
Select() function
Posted: Tue Jul 21, 2020 10:01 pm
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.
Select() function
Posted: Wed Jul 22, 2020 9:25 am
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
Select() function
Posted: Wed Jul 22, 2020 11:00 am
by atlopes
Karl-Heinz, it seems to be quite complete. Good work!
Select() function
Posted: Thu Jul 23, 2020 1:08 pm
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
Select() function
Posted: Sat Aug 08, 2020 7:17 pm
by Eric Selje
Karl-Heinz, did this make it into the latest build? I'm trying to do this:
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