Alaska Software Inc. - Re: DbInfo() return value complementation - The attachment
Username: Password:
AuthorTopic: Re: DbInfo() return value complementation - The attachment
Andreas Gehrs-Pahl

View the complete thread for this message in:

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