C5DG-4 DBFCDX Driver

Clipper 5.x – Drivers Guide

Chapter 4

DBFCDX Driver Installation and Usage

DBFCDX is the FoxPro 2 compatible RDD for Clipper. As such, it connects to the low-level database management subsystem in the Clipper architecture. When you use the DBFCDX RDD, you add a number of new features including:

. FoxPro 2 file format compatibility

. Compact indexes

. Compound indexes

. Conditional indexes

. Memo files smaller than DBFNTX format

In This Chapter

This chapter explains how to install DBFCDX and how to use it in your applications. The following major topics are discussed:

. Overview of the DBFCDX RDD

. Installing DBFCDX Driver Files

. Linking the DBFCDX Driver

. Using the DBFCDX Driver

Overview of the DBFCDX RDD

The DBFCDX driver lets you create and maintain (.cdx) and (.idx) files with features different from those supplied with the original DBFNTX driver and is compatible with files created under FoxPro 2. The new features are supplied in the form of several syntactical additions to the INDEX and REINDEX commands. Specifically, you can:

. Create indexes smaller than those created with the DBFNTX
driver. The key data is stored in a compressed format that
substantially reduces the size of the index file.

. Create a compound index file that contains multiple indexes
(TAGs), making it possible to open several indexes under one file
handle. A single (.cdx) file may contain up to 99 index keys.

. Create conditional indexes (FOR / WHILE / REST / NEXT).

. Create files with FoxPro 2 file format compatibility.

Compact Indexes

Like FoxPro 2, The DBFCDX driver creates compact indexes. This means that the key data is stored in a compressed format, resulting in a substantial size reduction in the index file. Compact indexes store only the actual data for the index keys. Trailing blanks and duplicate bytes between keys are stored in one or two bytes. This allows considerable space savings in indexes with much empty space and similar keys. Since the amount of compression is dependent on many variables, including the number of unique keys in an index, the exact amount of compression is impossible to predetermine.

Compound Indexes

A compound index is an index file that contains multiple indexes (called tags). Compound indexes (.cdx)’s make several indexes available to your application while only using one file handle. Therefore, you can overcome the Clipper index file limit of 15. A compound index can have as many as 99 tags, but the practical limit is around 50. Once you open a compound index, all the tags in the file are automatically updated as the records are changed.

Once you open a compound index, all the tags contained in the file are automatically updated as the records are changed. A tag in a compound index is essentially identical to an individual index (.idx) and supports all the same features. The first tag (in order of creation) in the compound index is, by default, the controlling index.

Conditional Indexes

The DBFCDX driver can create indexes with a built-in FOR clause. These are conditional indexes in which the condition can be any expression, including a user-defined function. As the database is updated, only records that match the index condition are added to the index, and records that satisfied the condition before, but don’t any longer, are automatically removed.

Expanded control over conditional indexing is supported with the revised INDEX and REINDEX command options as in the new DBFNTX driver.

Installing DBFCDX Driver Files

The DBFCDX driver is supplied as the file, DBFCDX.LIB.

The Clipper installation program installs this driver in the \CLIPPER5\LIB subdirectory on the drive that you specify, so you need not install the driver manually.

Linking the DBFCDX Database Driver

To link the DBFCDX database driver into an application program, you must specify DBFCDX.LIB to the linker in addition to your application object files (.OBJ).

1. To link with .RTLink using positional syntax:

C>RTLINK <appObjectList> ,,,DBFCDX

2. To link with .RTLink using freeformat syntax:

C>RTLINK FI <appObjectList> LIB DBFCDX

Note: These link commands all assume the LIB, OBJ, and PLL environment variables are set to the standard locations. They also assume that the Clipper programs were compiled without the /R option.

Using the DBFCDX Database Driver

To use FoxPro 2 files in a Clipper program:

1. Place REQUEST DBFCDX at the beginning of your application or at the top of the first program file       (.prg) that opens a database file using the DBFCDX driver.

2. Specify the VIA “DBFCDX” clause if you open the database file with the USE command.

    -OR-

3. Specify “DBFCDX” for the <cDriver> argument if you open the database file with the DBUSEAREA()       function.

   -OR-

4. Use ( “DBFCDX” ) to set the default driver to DBFCDX.

    Except in the case of REQUEST, the RDD name must be a literal character string or a variable. In all       cases it is important that the driver name be spelled correctly.

The following program fragments illustrate:

  REQUEST DBFCDX
  .
  .
  .
  USE Customers INDEX Name, Address NEW VIA "DBFCDX"

     -OR-

  REQUEST DBFCDX
  RDDSETDEFAULT( "DBFCDX" ) .
  . 
  .
  USE Customers INDEX Name, Address NEW

Using (.idx) and (.ntx) Files Concurrently

You can use both (.idx) and (.ntx) files concurrently in a Clipper program like this:

// (.ntx) file using default DBFNTX driver
 USE File1 INDEX File1 NEW
// (.idx) files using DBFCDX driver
 USE File2 VIA "DBFCDX" INDEX File2 NEW

Note, however, that you cannot use (.idx) and (.ntx) files in the same work area. For example, the following does not work:

USE File1 VIA "DBFNTX" INDEX File1.ntx, File2.idx

Using (.cdx) and (.idx) Files Concurrently

You may use (.cdx) with (.idx) files concurrently (even in the same work area); however, in most cases it is easier to use a single (.cdx) index for each database file or separate (.idx) files. When using both types of index at the same time, attempting to select an Order based on its Order Number can be confusing and will become difficult to maintain.

File Maintenance under DBFCDX

When an existing tag in a compound index (.cdx) is rebuilt using INDEX ON…TAG… the space used by the original tag is not automatically reclaimed. Instead, the new tag is added to the end of the file, increasing file size.

You can use the REINDEX command to “pack” the index file. REINDEX rebuilds each tag, eliminating any unused space in the file.

If you rebuild your indexes on a regular basis, you should either delete your (.cdx) files before rebuilding the tags or use the REINDEX command to rebuild them instead.

DBFCDX and Memo Files

The DBFCDX driver uses FoxPro compatible memo (.fpt) files to store data for memo fields. These memo files have a default block size of 64 bytes rather than the 512 byte default for (.dbt) files.

DBFCDX memo files can store any type of data. While (.dbt) files use an end of file marker (ASCII 26) at the end of a memo entry, (.fpt) files store the length of the entry. This not only eliminates the problems normally encountered with storing binary data in a memo field but also speeds up memo field access since the data need not be scanned to determine the length.

Tips For Using DBFCDX

1. Make sure index extensions aren’t hard-coded in your application. The default extension for DBFCDX indexes is (.idx), not (.ntx). You can still use (.ntx) as the extension as long as you specify the extension when you create your indexes. The best way to determine index extensions in an application is to call ORDBAGEXT().

For example, if you currently use the following code to determine the existence of an index file:

IF .NOT. FILE("index.ntx")
    INDEX ON field TO index
ENDIF

Change the code to include the INDEXEXT() function, as follows:

IF .NOT. FILE("index"+ORDBAGEXT())
   INDEX ON field TO index
ENDIF

2. If your application uses memo fields, you should convert your (.dbt) files to (.fpt) files.

There are some good reasons for using (.fpt) files. Most important is the smaller block size (64 bytes). Clipper’s (.dbt) files use a fixed block size of 512 bytes which means that every time you store even 1 byte in a memo field Clipper uses 512 bytes to store it. If the data in a memo field grows to 513 bytes, then two blocks are required.

When creating (.fpt) files, the block size is set at 64 bytes to optimize it for your needs. A simple conversion from (.dbt) files to (.fpt) files will generally shrink your memo files by approximately 30%.

3. Add DBFCDX.LIB as a library to your link command or link script.

Summary

In this chapter, you were given an overview of the features and benefits of the DBFCDX RDD. You also learned how to link this driver and how to use it in your applications.

Simple Clipper Extensions

Simple extensions

Exact comparisons,
Name precedence,
SELECT 0,
Alias functions,
Call by reference and value,
Other Clipper extensions

Strong Relation

Build strong relationships

Basics of building databases, indexs and relations.

C5 Index Commands and Functions

Index Commands and Functions

Commands :

DELETE TAG :

Delete a Tag

DELETE TAG <cOrderName> [IN <xcOrderBagName>]
    [, <cOrderName> [IN xcOrderBagName] list>]

INDEX ON … :

Create an index file

INDEX ON <expKey>
    [TAG <cOrderName>]
    TO <xcOrderBagName>
    [FOR <lCondition>] [ALL]
    [WHILE <lCondition>]
    [NEXT <nNumber>]
    [RECORD <nRecord>]
    [REST]
    [EVAL <bBlock>
    [EVERY <nInterval>]
    [UNIQUE]
    [ASCENDING|DESCENDING]

REINDEX :

Rebuild open indexes in the current workarea

REINDEX
    [EVAL <lCondition>]
    [EVERY <nRecords>]]

SET INDEX

Open index file(s) in the current work area

SET INDEX TO [<xcIndex list>]

SET ORDER

Set a new controlling index

SET ORDER TO [<nOrder> | [TAG <cOrderName>]
    [IN <xcOrderBagName>]]>

SET UNIQUE* : 

Toggle the inclusion of nonunique keys into an index

SET UNIQUE on | OFF | <xlToggle>

Functions :

DBCLEARINDEX() :

Close all indexes for the current work area

DBCLEARINDEX() --> NIL

DBCREATEINDEX() :

Create an index file

DBCREATEINDEX( <cIndexName>, <cKeyExpr>,
    <bKeyExpr>, 
    [<lUnique>] ) --> NIL

DBREINDEX() : 

Recreate all active indexes for the current work area

DBREINDEX() --> NIL

DBSEEK() : 

Move to the record having the specified key value

DBSEEK( <expKey>, [<lSoftSeek>] ) --> lFound

DBSETINDEX() : 

Open an index for the current work area

 DBSETINDEX( <cIndexName> ) --> NIL
 DBSETINDEX( <cOrderBagName> ) --> NIL

DBSETORDER() : 

Set the controlling order for the current work area

DBSETORDER( <nOrderNum> ) --> NIL

DESCEND() : 

Return a descending index key value

DESCEND( <exp> ) --> ValueInverted

FOUND() : 

Determine if the previous search operation succeeded

FOUND() --> lSuccess

INDEXEXT() : 

Return the default index extension

INDEXEXT() --> cExtension

INDEXKEY() : 

Return the key expression of a specified index

INDEXKEY( <nOrder> ) --> cKeyExp

INDEXORD() : 

Return the order position of the controlling index

INDEXORD() --> nOrder

ORDBAGEXT() :

Return the default Order Bag RDD extension

ORDBAGEXT() --> cBagExt

ORDBAGNAME() :

Return the Order Bag name of a specific Order

ORDBAGNAME(<nOrder> | <cOrderName>) --> cOrderBagName

ORDCOND()

Specify conditions for ordering

ORDCOND([FOR <lCondition>]
             [ALL] [WHILE <;lCondition>]
             [EVAL <bBlock> [EVERY <nInterval>]]
             [RECORD <nRecord>] [NEXT <nNumber>]
             [REST] [DESCENDING])

ORDCONDSET()

Set the condition and scope for an order

     ORDCONDSET([<cForCondition>],
        [<bForCondition>],
        [<lAll>],
        [<bWhileCondition>],
        [<bEval>],
        [<nInterval>],
        [<nStart>],
        [<nNext>],
        [<nRecord>],
        [<lRest>],
        [<lDescend>],
        [<lAdditive>],
        [<lCurrent>],
        [<lCustom>],
        [<lNoOptimize>]) --> lSuccess

ORDCREATE():

Create an Order in an Order Bag

ORDCREATE(<cOrderBagName>,[<cOrderName>], <cExpKey>,

    [<bExpKey>], [<lUnique>]) --> NIL

ORDDESCEND()

Return and optionally change the descending flag of an order

ORDDESCEND([<cOrder> | <nPosition>],[<cIndexFile>],
            [<lNewDescend>]) --> lCurrentDescend

ORDDESTROY() :

Remove a specified Order from an Order Bag

ORDDESTROY(<cOrderName> [, <cOrderBagName> ]) --> NIL

ORDFOR() :

Return the FOR expression of an Order

ORDFOR(<cOrderName> | <nOrder>
    [, <cOrderBagName>]) --> cForExp

ORDISUNIQUE()

          Return the status of the unique flag for a given order

    ORDISUNIQUE([<cOrder> | <nPosition>],
        [<cIndexFile>]) --> lUnique

ORDKEY() :

Return the Key expression of an Order

ORDKEY(<cOrderName> | <nOrder>
 [, <cOrderBagName>]) --> cExpKey

ORDKEYADD()

Add a key to a custom built order

         ORDKEYADD([<cOrder> | <nPosition>],
            [<cIndexFile>],[<expKeyValue>]) --> lSuccess

 

ORDKEYCOUNT()

Return the number of keys in an order

         ORDKEYCOUNT([<cOrder> | <nPosition>],
              [<cIndexFile>]) --> nKeys

ORDKEYDEL()

Delete a key from a custom built order

        ORDKEYDEL([<cOrder> | <nPosition>],
            [<cIndexFile>],
            [<expKeyValue>]) --> lSuccess

ORDKEYGOTO()

Move to a record specified by its logical record number

ORDKEYGOTO(<nKeyNo>) --> lSuccess

ORDKEYNO()

 Get the logical record number of the current record

         ORDKEYNO([<cOrder> | <nPosition>],
             [<cIndexFile>]) --> nKeyNo

 ORDKEYVAL()

Get key value of the current record from controlling order

ORDKEYVAL() --> xKeyValue

 

ORDLISTADD() :

Add Order Bag contents or single Order to the Order List

ORDLISTADD(<cOrderBagName>
    [, <cOrderName>]) --> NIL

ORDLISTCLEAR() :

Clear the current Order List

ORDLISTCLEAR() --> NIL

ORDLISTREBUILD() :

Rebuild all Orders in the Order List of the current work area

ORDLISTREBUILD() --> NIL

ORDNAME() :

Return the name of an Order in the work area

ORDNAME(<nOrder>[,<cOrderBagName>])
    --> cOrderName

ORDNUMBER() :

Return the position of an Order in the current Order List

ORDNUMBER(<cOrderName>[, <cOrderBagName>]) --> nOrderNo

 ORDSCOPE()

Set or clear the boundaries for scoping key values

ORDSCOPE(<nScope>, [<expNewValue>]) --> uCurrentValue

ORDSETFOCUS() :

Set focus to an Order in an Order List

ORDSETFOCUS([<cOrderName> | <nOrder>]
    [,<cOrderBagName>]) --> cPrevOrderNameInFocus

ORDSETRELAT()

Relate a specified work area to the current work area

    ORDSETRELATION(<nArea> | <cAlias>,<bKey>, [<cKey>])

             --> NIL

ORDSKIPUNIQUE()

Move record pointer to the next or previous unique key

ORDSKIPUNIQUE([<nDirection>]) –> lSuccess