Programming Guide:xppguide

Determine information about DatabaseEngines Foundation

At runtime of a program it is sometimes necessary to determine information about loaded DBEs, work areas, or individual fields in work areas. Xbase++ provides the four functions listed in the following table for this:

Functions for information about DatabaseEngines
Function Description
DbeList() Determines which DBEs are loaded
DbeInfo() Returns information about the current DBE
DbInfo() Returns information about a work area
FieldInfo() Determines information about a field based on ordinal position

For a deeper understanding of these functions, knowledge of the internal mechanisms used for opening files with USE or DbUseArea() is required. These mechanisms are not immediately recognizable at the language level. A file can only be opened when at least one DBE is loaded that provides the DATA component for the requested file format. Only after such a component is available can a file be opened in a work area, otherwise a runtime error occurs. Whether or not a DBE is currently available can be determined at runtime using the function DbeList(). DbeList() returns a two column array: the first column contains the names of DBEs and the second column contains logical values representing the "hidden-flag" (see previous section).

Opening a file using the current DBE creates an instance of the DBE which is called a "database object" (DBO). The DBO makes use of all the characteristics of the current DBE and it is actually the database object that opens and manages files. A DBO represents the work area where the files are opened.

It is helpful to distinguish between the DatabaseEngine, which provides the functionality that allows files to be opened in a work area and the database object which exists only while the file is open in the work area. The database object is created by the DatabaseEngine when the file is opened. It manages the file and is automatically discarded when the file is closed.

The function DbeInfo()

The function DbeInfo() provides information about the current DBE. Therefore, it can only be executed when a DBE is loaded. It is similar to the functions DbInfo() and FieldInfo() that can only be called when a file is open in the current work area. Otherwise a runtime error occurs.

As well as returning information, DbeInfo() also allows a DBE to be configured in specific ways. Several settings of a DBE are changeable and can be redefined using DbeInfo(). As an example, the default extension for files can be changed:

#include "Dmlb.ch" 
#include "DbfDbe.ch" 

DbeLoad( "DBFDBE", .T.) 
DbeLoad( "NTXDBE", .T.)                  // create the compound DBE 
DbeBuild( "DBFNTX", "DBFDBE", "NTXDBE" ) // DBFNTX 

                                     // default extension DBF->FBD 
                                     // for database files 
DbeInfo( COMPONENT_DATA , DBE_EXTENSION, "FBD" ) 
                                     // default extension NTX->XTN 
                                     // for index files 
DbeInfo( COMPONENT_ORDER, DBE_EXTENSION, "XTN" ) 

DbCreate( "Temp", { { "LName", "C", 20, 0 }, ; 
                    { "FName", "C", 20, 0 }, } ) 

USE Temp                             // create database and 
INDEX ON Field->LName TO TempA       // index files 
INDEX ON Field->FName TO TempB 
CLOSE Temp 
                                     // display file names. Result: 
AEval( Directory( "Temp*.*" ), ;     //   Temp.FBD 
       {|a| QOut(a[1]) } )           //   TempA.XTN 
                                     //   TempB.XTN 

In this example, the default extensions for two different kinds of files are redefined using DbeInfo(). This affects the files managed by the DATA component of the DBFNTX DBE (the DBF file is created as a FBD file) and the files which are managed by the ORDER component (the NTX files are created as XTN files). All this happens in just two lines of the example:

DbeInfo( COMPONENT_DATA , DBE_EXTENSION, "FBD" ) 

DbeInfo( COMPONENT_ORDER, DBE_EXTENSION, "XTN" ) 

A special aspect of DbeInfo() is shown: if the function is called with parameters, the first parameter must always be a #define constant from the file DMLB.CH specifying one of the four components that can be contained in a DBE. Also, the second parameter must be a #define constant. There some constants that are universally valid and can be used with every DBE and other constants that may be used only with a specific DBE. The difference can be recognized by the prefix of the #define constant. The prefix DBE_ identifies universally valid constants and the prefix DBFDBE_ identifies constants which are only valid for the DBFDBE (more precisely, for the DATA component which manages DBF files). Constants containing the prefix DBFDBE_ are defined in the #include file DBFDBE.CH. The third parameter specifies the value which is to be set for the specific setting (in the example, the file extension) of a DBE.

Not all settings of a DBE are changeable, so the third parameter is only processed by DbeInfo() when the DBE allows the corresponding setting to be changed. The following table gives an overview of the universally valid settings that exist for all DBEs. The only setting which can be changed is the file extension:

Universal constants for characteristics of DatabaseEngines
Constant *) Data type Description
DBE_DATATYPES ro C Supported data types
DBE_EXTENSION a C Default file extension
DBE_MANUFACTURER ro C Producer of the DBE
DBE_NAME ro C Name of the DBE
DBE_VERSION ro C Version of the DBE
  1. ro=READONLY , a=ASSIGNABLE

Along with these general constants, most DatabaseEngines have specific #define constants that can only be used for the specific DBE (more precisely, for a specific component). In the chapter "Database Engines" DBE specific constants for DbeInfo() are described.

The function DbInfo()

When a file is opened in a work area, a database object (DBO) is created by the current DatabaseEngine to manage the file open in the work area. The DBO represents the work area and the function DbInfo() can read information about the DBO and can change settings of the DBO. DbInfo() requires that a file be open in the corresponding work area.

DbInfo(), as well as DbeInfo(), receives parameters that are constants defined in an #include file. Universally valid constants can be found in the file DMLB.CH and are listed in the next table:

Universal constants for database objects (work areas)
Constant *) Data type Description
DBO_ALIAS ro C Alias name
DBO_FILENAME ro C Name of the open file
DBO_ORDERS ro N Number of orders (indexes)
DBO_RELATIONS ro N Number of relations
DBO_SHARED ro L .T. if data is accessed in SHARED mode
DBO_REMOTE ro L .T. if the data is stored on a remote drive
DBO_SERVER ro L .T. if the data is managed by a server
DBO_DBENAME ro L Name of the DatabaseEngine managing this workarea
  1. ro=READONLY , a=ASSIGNABLE

The universally valid #define constants for DbInfo() starts with the prefix DBO_ (for database object). There are also constants which can be used only with DBOs created by a specific DatabaseEngine. An example of constants that can be passed to DbInfo() is given in the following program code:

#include "Dmlb.ch" 
#include "DbfDbe.ch" 

DbeLoad( "DBFDBE", .T.) 
DbeLoad( "NTXDBE", .T.)                  // create DBFNTX 
DbeBuild( "DBFNTX", "DBFDBE", "NTXDBE" ) // compound DBE 

USE Customer ALIAS Cust 

? DbInfo( DBO_ALIAS )                // result: Cust 
? DbInfo( DBO_FILENAME )             // result: C:\DATA\Customer.DBF 

                                     // file handles 
? DbInfo( DBFDBO_DBFHANDLE )         // result: 8 
? DbInfo( DBFDBO_DBTHANDLE )         // result: 9 

The example illustrates that the first parameter passed to DbInfo() is a #define constant which is either a universally valid constant (prefix DBO_) or a specific DBE constant. In the case of the DBFDBE, the specific constants for the function DbInfo() start with the prefix DBFDBO_ and are contained in the #include file DBFDBE. (To summarize: constants which contain DBE_ are valid for a DatabaseEngine, and for the function DbeInfo(). Constants which contain DBO_ are valid for database objects and for the function DbInfo()). The constants for DbInfo() that are dependent on the current DatabaseEngine are listed in the chapter "Database Engines".

A DBO is initialized with all the current settings of the DBE when the file is opened. If changes are later made to the DBE using DbeInfo(), all DBOs remain unaffected by the change. This means that all work areas where files are open are not affected by changes made to a database engine. Such changes affect only those work areas where a file is opened after the change is made.

The function FieldInfo()

As soon as a file is opened in a work area, field variables (fields) exist within this work area. Similar to Clipper, information about a field can be determined using the functions FieldName() or FieldPos(). Xbase++ also includes the function FieldInfo() to read or change information about an individual field in a work area. The function FieldInfo() behaves in a manner similar to DbeInfo() and DbInfo(), and takes a #define constant as the second parameter. The valid constants for FieldInfo() are listed in the following table:

Universal constants for field variables in a work area
Constant *) Data type Description
FLD_LEN ro N Length of field
FLD_DEC ro N Number of decimal places
FLD_TYPE ro C Data type of field variable on the Xbase++ language level
FLD_TYPE_AS_NUMERIC ro N as character and numeric value
FLD_NATIVETYPE ro C Original data type of field variable as defined in the DBE
FLD_NATIVETYPE_AS_NUMERIC ro N as character and numeric value
  1. ro=READONLY , a=ASSIGNABLE

FieldInfo() provides important pieces of information about fields in the database such as the length and the number of decimal places. Example:

(In this example, it is assumed that the DBFDBE is loaded)

#include "Dmlb.ch" 

                                     // create database 
DbCreate( "Part", { { "PartNo"   , "C",  6, 0 }, ; 
                    { "Part"     , "C", 20, 0 }, ; 
                    { "Price"    , "N",  8, 2 }  } ) 

USE Part 

? FieldInfo( 3, FLD_LEN )            // result: 8 
? FieldInfo( 3, FLD_DEC )            // result: 2 

? FieldInfo( 1, FLD_LEN )            // result: 6 
? FieldInfo( 2, FLD_LEN )            // result: 20 

The first parameter of the function FieldInfo() is the ordinal position of a field (as returned by FieldPos()) and the second parameter is a #define constant designating what information is being requested. To determine the length of a field or its decimal places, two simple pseudo functions can be defined for translation by the preprocessor into calls to FieldInfo():

#xtranslate  FieldLen( <nPos> ) => FieldInfo( <nPos>, FLD_LEN ) 
#xtranslate  FieldDec( <nPos> ) => FieldInfo( <nPos>, FLD_DEC ) 

The data type of a field is also important information and can be determined by passing the constant FLD_TYPE or FLD_NATIVETYPE. In both cases FieldInfo() returns a character value identifying the data type. Using the two constants, the data type which is available to be manipulated by the appropriate Xbase++ commands and functions can be distinguished from the original data type stored in the database. They are often, but not always identical. For example, at the language level of Xbase++ only a single numeric type exists. When numbers are stored in fields, however, integers and floating point numbers might be treated differently. Xbase++ recognizes the different representations for numbers and other data internally and distinguishes between data types that can exist on the language level and on the database level. Correspondingly, FieldInfo() can read the data type of a field as it exists on the language level (FLD_TYPE) or on the database level (FLD_NATIVETYPE). To determine the data type of a field on the Xbase++ language level, the constant FLD_TYPE is passed to FieldInfo(). The data type is returned by FieldInfo() equivalent to the return values of Valtype() or Type().

The numeric identification of data types uses constants defined in the #include file TYPES.CH. The constants from the following table are available for determining data types using FieldInfo() along with FLD_TYPE_AS_NUMERIC and FLD_NATIVETYPE_AS_NUMERIC:

Constants for data types (FieldInfo() return values)
Constant Description
XPP_CHARACTER Character value
XPP_DATE Date value
XPP_LOGICAL Logical value
XPP_MEMO Memo field
XPP_NUMERIC Numeric value
XPP_ARRAY *) Array
XPP_BLOCK *) Code block
XPP_DOUBLE *) Numeric value as double
XPP_ILLEGAL *) Invalid data type
XPP_OBJECT *) Object
XPP_UNDEF *) Undefined value (NIL)
  1. Return values with FieldInfo() are dependent on the DBE

Feedback

If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.