Alaska Software Inc. - DbInfo() return value
Username: Password:
AuthorTopic: DbInfo() return value
Carlos a Beling DbInfo() return value
on Thu, 24 Nov 2016 17:52:43 -0200
Good afternoon.
The documentation of DbInfo() defines that the #defines constants for to 
be used must start with DBFDBO... and that the return of DBFDBO_ANSI is 
.t. or .f.
I attached an example where DbInfo() is returning NIL.
Can someone, please, correct this example for it to work correctly?

Fraternally
Beling


testinfo.zip
Jim LeeRe: DbInfo() return value
on Fri, 25 Nov 2016 03:33:04 +0100
your Code, Add/Del DBE, does not work ... -> crash
seems you "DEL" wrong DBE ...

Constante in dbfdbe.ch are for DBFDBE (DATA-Komponente) not for FOXDBE !

Header of 0002.DBF show 30h -> Visual FoxPro

bit 30 -> ::_IsAnsi  := cTxt[30] $ chr(0x03)+chr(0xC8)
 chr(0x03)="WIN 1251"
 chr(0xC8)="WIN 1250"
 more ???
Carlos a Beling Re: DbInfo() return value
on Fri, 25 Nov 2016 10:09:18 -0200
Hello Jim.
Good morning.
Many thanks.
You are right.
The program crashes in executing the DBInfo() function. My problem is to 
know why.
The DBF really is Visual FoxPro. Please see the routine of opening the 
file. It tries to open the DBF with the first one DBE that can do it; 
this way it is not possible to know in advance which one it is.
The docs says about the parameter _define_:
<nDefine>
For the parameter <nDefine>, a #define constant must be used from an 
#include file. This determines the setting selected for the current 
database object. The file DMLB.CH contains the constants valid for any 
database object. Depending on the database engine used to produce a 
database object, other specific constants can also be set. For DBF 
files, the specific constants are contained in the file DBFDBE.CH. In 
this case, the constants for <nDefine> must begin with the prefix DBFDBO_.
</define>
If you do not mind, please debug the example and, if it is possible 
inform if the error can to be corrected? If yes, how?

Fraternaly
Beling


Em 25/11/2016 00:33, Jim Lee escreveu:
> your Code, Add/Del DBE, does not work ... -> crash
> seems you "DEL" wrong DBE ...
>
> Constante in dbfdbe.ch are for DBFDBE (DATA-Komponente) not for FOXDBE !
>
> Header of 0002.DBF show 30h -> Visual FoxPro
>
> bit 30 -> ::_IsAnsi  := cTxt[30] $ chr(0x03)+chr(0xC8)
>  chr(0x03)="WIN 1251"
>  chr(0xC8)="WIN 1250"
>  more ???
>
>
Carlos a Beling Re: DbInfo() return value complementation
on Fri, 25 Nov 2016 15:46:05 -0200
Hello:
good afternoon.
I made a correction in the TestInfo.prg (attached) and it is working fine.
Here is what I read in the documentation of DBFDBE (DATA component):
a) it defines that the DBInfo() returns the settings of the DbfDbe that 
opened the current work area
b) it defines too that DbInfo() must to use #defines begin with DBFDBO_
c) it informs that the return value of DbInfo(DBFDBO_ANSI) is .T. or .F. 
(as written in the line below >> bit 30 -> ::_IsAnsi  := cTxt[30] $ 
chr(0x03)+chr(0xC8)

Here is my problem:
a) when the database is created it seems to respect the current 
Set(_SET_CHARSET)
b) when debuging TestInfo.prg the result of DbInfo(DBFDBO_ANSI) is the 
number 1252, disaccording to the documentation
c) opening another old DOS database DbInfo(DBFDBO_ANSI) returns 0
d) please, how is the correct way for to know the result of 
f0002->DbInfo(DBFDBO_ANSI)?

Fraternally
Beling

Em 25/11/2016 10:09, Carlos a Beling escreveu:
> Hello Jim.
> Good morning.
> Many thanks.
> You are right.
> The program crashes in executing the DBInfo() function. My problem is to
> know why.
> The DBF really is Visual FoxPro. Please see the routine of opening the
> file. It tries to open the DBF with the first one DBE that can do it;
> this way it is not possible to know in advance which one it is.
> The docs says about the parameter _define_:
> <nDefine>
> For the parameter <nDefine>, a #define constant must be used from an
> #include file. This determines the setting selected for the current
> database object. The file DMLB.CH contains the constants valid for any
> database object. Depending on the database engine used to produce a
> database object, other specific constants can also be set. For DBF
> files, the specific constants are contained in the file DBFDBE.CH. In
> this case, the constants for <nDefine> must begin with the prefix DBFDBO_.
> </define>
> If you do not mind, please debug the example and, if it is possible
> inform if the error can to be corrected? If yes, how?
>
> Fraternaly
> Beling
>
>
> Em 25/11/2016 00:33, Jim Lee escreveu:
>> your Code, Add/Del DBE, does not work ... -> crash
>> seems you "DEL" wrong DBE ...
>>
>> Constante in dbfdbe.ch are for DBFDBE (DATA-Komponente) not for FOXDBE !
>>
>> Header of 0002.DBF show 30h -> Visual FoxPro
>>
>> bit 30 -> ::_IsAnsi  := cTxt[30] $ chr(0x03)+chr(0xC8)
>>  chr(0x03)="WIN 1251"
>>  chr(0xC8)="WIN 1250"
>>  more ???
>>
>>
Jim LeeRe: DbInfo() return value complementation
on Sat, 26 Nov 2016 00:35:13 +0100
>I made a correction in the TestInfo.prg (attached) and it is working fine.

no Attachment

>c) opening another old DOS database DbInfo(DBFDBO_ANSI) returns 0

Dbase III+ / Cl*pper DBF/DBT are always OEM but it can contain ANSI Sign >
CHR(128) or chinese DBCS Sign in a Field Type "C"/"M"

>Here is what I read in the documentation of DBFDBE (DATA component):
>
>d) please, how is the correct way for to know the result of
>f0002->DbInfo(DBFDBO_ANSI)?

DBF Header of 0002.DBF say 30H -> Visual Foxpro/Ads FOXCDX/ADSDBE CDX
foxdbe.ch does not include dbfdbe.ch

---

if you want to work with OEM and ANSI Database at same time i recommend to
use 2 Set of Fonts. this Way i can display chinese and german/english Sign 
in a XbpBrowse()
Andreas Gehrs-Pahl
Re: DbInfo() return value complementation
on Sat, 26 Nov 2016 13:13:53 -0500
Carlos,

>I made a correction in the TestInfo.prg (attached) and it is working fine.

As Jim already mentioned, you didn't attach any updated program.

>Here is what I read in the documentation of DBFDBE (DATA component):
>a) it defines that the DBInfo() returns the settings of the DbfDbe that 
>opened the current work area

That is (partially) correct, but your (original) program doesn't load the 
DBFDBE and doesn't open any files with it, so you can't use any DBFDBE-
specific DBFDBO_* define constants, only generic DBO_* and FOXDBE-specific 
FOXDBO_* define constants.

>b) it defines too that DbInfo() must to use #defines begin with DBFDBO_

That is incorrect. The DbInfo() function can use generic define constants 
that begin with DBO_ (as can be found in the "dmlb.ch" header file), as well 
as DBE-specific define constants, starting with ADSDBO_, DBFDBO_, FOXDBO_, 
etc. (as can be found in the corresponding "*dbe.ch" files).

In file "dbfdbe.ch", you can find:
#define DBFDBO_ANSI            DBE_USER+7

In file "foxdbe.ch", you can find:
#define FOXDBO_CODEPAGE        DBE_USER+7

So, if you open a database with the FOXDBE (as you do in your program) and 
then use the DBFDBO_ANSI define constant with DbInfo() on that database, you 
are actually using the FOXDBO_CODEPAGE define constant!

>c) it informs that the return value of DbInfo(DBFDBO_ANSI) is .T. or .F. 

This is also correct, but as you are using the FOXDBE, the DBFDBO_ANSI isn't 
appropriate, and what you actually use is the FOXDBO_CODEPAGE constant. And 
the return value for the FOXDBO_CODEPAGE constant is a numerical value that 
indicates the Code Page, as the name of the define constant implies.

>Here is my problem:
>b) when debuging TestInfo.prg the result of DbInfo(DBFDBO_ANSI) is the 
>number 1252, disaccording to the documentation

Actually, this is exactly as documented. The return value for DbInfo(1007) 
in a workarea with a database that was opened with the FOXDBE is a numerical 
Code Page value, which in your case is 1252.

>c) opening another old DOS database DbInfo(DBFDBO_ANSI) returns 0

If you open a non-VFP database with the FOXDBE, the DBE won't be able to 
determine the Code Page, as it isn't saved in non-VFP database headers, so 
it will always return 0 (Zero).

>d) please, how is the correct way for to know the result of 
>f0002->DbInfo(DBFDBO_ANSI)?

The only way to get a "correct" result is to open the database with the 
DBFDBE instead of the FOXDBE. But as this is a VFP database, you probably 
should open it with the FOXDBE, as you do.

The FOXDBE doesn't have an OEM/ANSI setting, but you can use the Code Page 
setting (FOXDBO_CODEPAGE) to determine the ANSI/OEM setting indirectly. If 
the used Code Page is reported as 437 -- the IBM PC OEM Code Page -- then 
the OEM character set is used. If the reported Code Page is between 1250 
and 1258, then the Windows ANSI character set is used.

There are also several other OEM and ANSI code page values possible, most 
of which are listed here: https://en.wikipedia.org/wiki/Code_page

Hope that helps,

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas@AbsoluteSoftwareLLC.com
web:   http://www.AbsoluteSoftwareLLC.com
[F]:   https://www.facebook.com/AbsoluteSoftwareLLC
Carlos a Beling Re: DbInfo() return value complementation - The attachment
on Mon, 28 Nov 2016 13:03:19 -0200
Hello:
excuse me to forget the attach.
Many thanks to all that is helping me.
Here is the attachment where I made in it changes according to the 
Andreas advise and I think that is the right way to know if the charset 
is ANSI without to know in advance which one DBE opened the file.
Please is it right?

Fraternally
Beling


Fraternally
Beling

Em 26/11/2016 16:13, Andreas Gehrs-Pahl escreveu:
> Carlos,
>
>> I made a correction in the TestInfo.prg (attached) and it is working fine.
>
> As Jim already mentioned, you didn't attach any updated program.
>
>> Here is what I read in the documentation of DBFDBE (DATA component):
>> a) it defines that the DBInfo() returns the settings of the DbfDbe that
>> opened the current work area
>
> That is (partially) correct, but your (original) program doesn't load the
> DBFDBE and doesn't open any files with it, so you can't use any DBFDBE-
> specific DBFDBO_* define constants, only generic DBO_* and FOXDBE-specific
> FOXDBO_* define constants.
>
>> b) it defines too that DbInfo() must to use #defines begin with DBFDBO_
>
> That is incorrect. The DbInfo() function can use generic define constants
> that begin with DBO_ (as can be found in the "dmlb.ch" header file), as well
> as DBE-specific define constants, starting with ADSDBO_, DBFDBO_, FOXDBO_,
> etc. (as can be found in the corresponding "*dbe.ch" files).
>
> In file "dbfdbe.ch", you can find:
> #define DBFDBO_ANSI            DBE_USER+7
>
> In file "foxdbe.ch", you can find:
> #define FOXDBO_CODEPAGE        DBE_USER+7
>
> So, if you open a database with the FOXDBE (as you do in your program) and
> then use the DBFDBO_ANSI define constant with DbInfo() on that database, you
> are actually using the FOXDBO_CODEPAGE define constant!
>
>> c) it informs that the return value of DbInfo(DBFDBO_ANSI) is .T. or .F.
>
> This is also correct, but as you are using the FOXDBE, the DBFDBO_ANSI isn't
> appropriate, and what you actually use is the FOXDBO_CODEPAGE constant. And
> the return value for the FOXDBO_CODEPAGE constant is a numerical value that
> indicates the Code Page, as the name of the define constant implies.
>
>> Here is my problem:
>> b) when debuging TestInfo.prg the result of DbInfo(DBFDBO_ANSI) is the
>> number 1252, disaccording to the documentation
>
> Actually, this is exactly as documented. The return value for DbInfo(1007)
> in a workarea with a database that was opened with the FOXDBE is a numerical
> Code Page value, which in your case is 1252.
>
>> c) opening another old DOS database DbInfo(DBFDBO_ANSI) returns 0
>
> If you open a non-VFP database with the FOXDBE, the DBE won't be able to
> determine the Code Page, as it isn't saved in non-VFP database headers, so
> it will always return 0 (Zero).
>
>> d) please, how is the correct way for to know the result of
>> f0002->DbInfo(DBFDBO_ANSI)?
>
> The only way to get a "correct" result is to open the database with the
> DBFDBE instead of the FOXDBE. But as this is a VFP database, you probably
> should open it with the FOXDBE, as you do.
>
> The FOXDBE doesn't have an OEM/ANSI setting, but you can use the Code Page
> setting (FOXDBO_CODEPAGE) to determine the ANSI/OEM setting indirectly. If
> the used Code Page is reported as 437 -- the IBM PC OEM Code Page -- then
> the OEM character set is used. If the reported Code Page is between 1250
> and 1258, then the Windows ANSI character set is used.
>
> There are also several other OEM and ANSI code page values possible, most
> of which are listed here: https://en.wikipedia.org/wiki/Code_page
>
> Hope that helps,
>
> Andreas
>


testinfo.zip
Andreas Gehrs-Pahl
Re: DbInfo() return value complementation - The attachment
on Tue, 29 Nov 2016 04:57:02 -0500
Carlos,

>Here is the attachment where I made in it changes according to the 
>Andreas advise and I think that is the right way to know if the charset 
>is ANSI without to know in advance which one DBE opened the file.

First a clarification. The DBFDBO_ANSI define constant was introduced with 
Xbase++ version 1.90.322, and the corresponding DBFDBE_ANSI define constant 
was introduced with version 1.90.331. Contrary to the documentation, using 
DbInfo(DBFDBO_ANSI) will always return a numeric value, either Zero (0) or 
One (1), rather than a logical value of FALSE (.f.) or TRUE (.t.), and it 
has worked that way since this feature was introduced in 2005/2006.

The FOXDBO_CODEPAGE define constant was added in Xbase++ version 2.00.720, 
so it is only a few months old! In earlier versions, you would have to use 
low-level file functions to check the database header manually.

Also, normal (non-VFP) database files do NOT contain any indicator for the 
used Character Set (OEM or ANSI), as they (should) ALWAYS contain only OEM 
characters. It is therefore meaningless to use DbInfo(DBFDBO_ANSI) the way 
you do in your code.

Xbase++ allows you to treat the data in database files as ANSI characters, 
though, which basically means you can enable and disable the implicit OEM/
ANSI conversion of the DBFDBE, by setting the DBFDBE_ANSI define constant to 
either TRUE (.t.) or FALSE (.f.) -- the default is FALSE -- before opening a 
database, using this: DbeInfo(COMPONENT_DATA, DBFDBE_ANSI, lValue).

You can then check the current setting of a database (or its DBO) using the 
DbInfo(DBFDBO_ANSI) function, which (strangely) will return either Zero (0) 
or One (1), instead of the expected and documented logical return value. If 
the database is treated as containing ANSI characters, the return value is 
One (1), otherwise it is Zero (0), which is the default.

This basically enables or disables the implicit character set conversions 
when reading or writing data with the DBFDBE for that database, depending on 
the current/active (thread-specific) Set CharSet setting. If both are set to 
OEM or both are set to ANSI, no conversion is done, otherwise the implicit 
OEM to ANSI and ANSI to OEM conversion is done when reading or writing data.

So, DbInfo(DBFDBO_ANSI) is a temporary setting, which is based on the actual 
DBFDBE setting at the time the database was opened. It is not something 
inherent to a database. So the way you try to use it in your program is not 
sensible at all. Unless you use DbeInfo(COMPONENT_DATA, DBFDBE_ANSI, .t.) 
before you open a database with the DBFDBE, the return value will always be 
Zero.

As there is no such settings for the Order Components -- neither the NTXDBE 
nor the CDXDBE can be configures like this -- the index will always be based 
on the default setting of the DBE, which is OEM for NTX files and ANSI for 
CDX files.

>Please is it right?

No, it isn't, even though it kind of works by accident. If you want this to 
work correctly, you need to do something like this:

In line 26 you should test which DBE was used, and then use the appropriate 
define constant:

if left(f0002->(DbInfo(DBO_DBENAME)), 3) == "DBF"
   xReturned := f0002->(DbInfo(DBFDBO_ANSI))

elseif left(f0002->(DbInfo(DBO_DBENAME)), 3) == "FOX"
   xReturned := f0002->(DbInfo(FOXDBO_CODEPAGE))
endif

You should never rely on the (coincidental) fact that the values of the two 
define constants DBFDBO_ANSI and FOXDBO_CODEPAGE are the same, as they could 
actually change in future versions of Xbase++. That's one of the reasons why 
those define constants were created; so you don't need to use a meaningless 
hard-coded numeric value (of 1007). Also, it always makes much more sense to 
determine which DBE is actually responsible for the DBO, before doing any 
further queries with define constants that depend on the used DBE.

Finally, it makes much more sense to overload the DbeSys() procedure and 
load, create, and configure only those DBEs that you want to use, rather 
than what you do in lines 8 - 19 of your code and your LoadDbe() function.

Andreas

Andreas Gehrs-Pahl
Absolute Software, LLC

phone: (989) 723-9927
email: Andreas@AbsoluteSoftwareLLC.com
web:   http://www.AbsoluteSoftwareLLC.com
[F]:   https://www.facebook.com/AbsoluteSoftwareLLC
Carlos a Beling Re: DbInfo() return value complementation - The attachment
on Tue, 29 Nov 2016 12:53:00 -0200
Hello Andreas.
Many thanks again.
Really the documentation made me confuse.
My real need is to convert DBFs created in Clipper for format VFP. It is 
because the databases have character fields storing L2Bin() data.
Those fields need to be converted to FieldType() == 'X' without data 
conversion.
As the read data is converted to he current Set(_SET_CHARSET) when they 
are read I think I need to compatibilize the reading and writing data.
Again many thanks.

Fraternally
Beling

Em 29/11/2016 07:57, Andreas Gehrs-Pahl escreveu:
> Carlos,
>
>> Here is the attachment where I made in it changes according to the
>> Andreas advise and I think that is the right way to know if the charset
>> is ANSI without to know in advance which one DBE opened the file.
>
> First a clarification. The DBFDBO_ANSI define constant was introduced with
> Xbase++ version 1.90.322, and the corresponding DBFDBE_ANSI define constant
> was introduced with version 1.90.331. Contrary to the documentation, using
> DbInfo(DBFDBO_ANSI) will always return a numeric value, either Zero (0) or
> One (1), rather than a logical value of FALSE (.f.) or TRUE (.t.), and it
> has worked that way since this feature was introduced in 2005/2006.
>
> The FOXDBO_CODEPAGE define constant was added in Xbase++ version 2.00.720,
> so it is only a few months old! In earlier versions, you would have to use
> low-level file functions to check the database header manually.
>
> Also, normal (non-VFP) database files do NOT contain any indicator for the
> used Character Set (OEM or ANSI), as they (should) ALWAYS contain only OEM
> characters. It is therefore meaningless to use DbInfo(DBFDBO_ANSI) the way
> you do in your code.
>
> Xbase++ allows you to treat the data in database files as ANSI characters,
> though, which basically means you can enable and disable the implicit OEM/
> ANSI conversion of the DBFDBE, by setting the DBFDBE_ANSI define constant to
> either TRUE (.t.) or FALSE (.f.) -- the default is FALSE -- before opening a
> database, using this: DbeInfo(COMPONENT_DATA, DBFDBE_ANSI, lValue).
>
> You can then check the current setting of a database (or its DBO) using the
> DbInfo(DBFDBO_ANSI) function, which (strangely) will return either Zero (0)
> or One (1), instead of the expected and documented logical return value. If
> the database is treated as containing ANSI characters, the return value is
> One (1), otherwise it is Zero (0), which is the default.
>
> This basically enables or disables the implicit character set conversions
> when reading or writing data with the DBFDBE for that database, depending on
> the current/active (thread-specific) Set CharSet setting. If both are set to
> OEM or both are set to ANSI, no conversion is done, otherwise the implicit
> OEM to ANSI and ANSI to OEM conversion is done when reading or writing data.
>
> So, DbInfo(DBFDBO_ANSI) is a temporary setting, which is based on the actual
> DBFDBE setting at the time the database was opened. It is not something
> inherent to a database. So the way you try to use it in your program is not
> sensible at all. Unless you use DbeInfo(COMPONENT_DATA, DBFDBE_ANSI, .t.)
> before you open a database with the DBFDBE, the return value will always be
> Zero.
>
> As there is no such settings for the Order Components -- neither the NTXDBE
> nor the CDXDBE can be configures like this -- the index will always be based
> on the default setting of the DBE, which is OEM for NTX files and ANSI for
> CDX files.
>
>> Please is it right?
>
> No, it isn't, even though it kind of works by accident. If you want this to
> work correctly, you need to do something like this:
>
> In line 26 you should test which DBE was used, and then use the appropriate
> define constant:
>
> if left(f0002->(DbInfo(DBO_DBENAME)), 3) == "DBF"
>     xReturned := f0002->(DbInfo(DBFDBO_ANSI))
>
> elseif left(f0002->(DbInfo(DBO_DBENAME)), 3) == "FOX"
>     xReturned := f0002->(DbInfo(FOXDBO_CODEPAGE))
> endif
>
> You should never rely on the (coincidental) fact that the values of the two
> define constants DBFDBO_ANSI and FOXDBO_CODEPAGE are the same, as they could
> actually change in future versions of Xbase++. That's one of the reasons why
> those define constants were created; so you don't need to use a meaningless
> hard-coded numeric value (of 1007). Also, it always makes much more sense to
> determine which DBE is actually responsible for the DBO, before doing any
> further queries with define constants that depend on the used DBE.
>
> Finally, it makes much more sense to overload the DbeSys() procedure and
> load, create, and configure only those DBEs that you want to use, rather
> than what you do in lines 8 - 19 of your code and your LoadDbe() function.
>
> Andreas
>