Applies To:
  • CitectSCADA x.x

Summary:
Opening a device that is configured with an index causes device functions to operate differently than when operating on devices without an index configured. The DevFind, DevNext, DevPrev and DevFirst functions produce unexpected results.  

Solution:
Each example in this article is based on a database device with the following definition:

Name: Device_1
Format: {Category,2}{Type,1}
Header: {Category}
File Name: [Data]:Device_1.dbf
Type: dBase_DEV

Assume the table is populated with the following records. (ie in physical order):

Category Type
1 B
3 A
1 C
1 A
2 A
1 D
1 A

The records indexed on the Category field, as shown below in index order:

Category Type
1 B
1 C
1 A
1 D
1 A
2 A
3 A

Indexed Devices are accessed in one of two ways:

  • Indexed Mode and;
  • Keyed Index Mode.

The Indexed Mode and Keyed Index Mode are explained below.

If the device is opened in Indexed Mode, all the records in the device are accessed in sequence, ordered by the index field. After opening the device, the current record is set to the first record in index order. The DevFirst function returns the first record in the index order. Calls to the DevNext and DevPrev functions set the current record to the next or previous record respectively in the index order. The DevFind function does not work in Indexed Mode. This mode is useful where records have a unique index field value (Primary Key) and the index is used primarily to sort the records.

To open a device in Indexed Mode, set the open mode parameter of the DevOpen function to 2. For example, DevOpen("MyDevice", 2). As an example of using Indexed Mode, to read each record in the device in the index order:

! Open device in Indexed Mode
hDev = DevOpen("MyDevice", 2);

WHILE (NOT DevEOF(hDev)) DO
   category = DevGetField( hDev, "category");
   type = DevGetField( hDev, "type");
   TraceMsg("Category = " + category + " Type = " + type);
   DevNext(hDev);
END
DevClose(hDev);

The following records are returned:

1 B
1 C
1 A
1 D
1 A
2 A
3 A

If the device is not opened in indexed mode, the device records are accessed in Keyed Index order. This mode is useful where records do not have a Primary Key (unique index field value) and the index is used primarily to group the records. The Index Key must be set by calling the DevFind function with the preconfigured index field and a value specified. The Index Key remains in effect until a different index field value is set by calling the DevFind function again. In this mode only one Index Key is active at a time. Once the Index Key is set, the DevFirst, DevNext and DevPrev functions work on the group of records with an index field value equal to the Index Key. This group of records is referred to as the Index Key Group.

If the device is not opened in Indexed Mode, then Keyed Index Mode is used by default. As an example of using Keyed Index Mode, to read each record with a category of 1 (Index Key):

! Open device in Keyed Index mode Note that if the device is not opened in
! Indexed mode, then the default Keyed Index mode is used.
hDev = DevOpen("MyDevice", 0);

DevFind(hDev, "1", "category");
WHILE (NOT DevEOF(hDev)) DO
   category = DevGetField( hDev, "category");
   type = DevGetField( hDev, "type");
   TraceMsg("Category = " + category + " Type = " + type);
   DevNext(hDev);
END
DevClose(hDev);

The following records are returned:

Category Type
1 B
1 C
1 A
1 D
1 A

If the DevFind function is then called with a field name other than the index field, then only records in the current Index Key Group are searched. For example to search for a record of 'Type' A with a category of 1:

! Open device in Keyed Index mode. Note that if the device is not opened in
! Indexed mode, then the default Keyed Index mode is used.
hDev = DevOpen("MyDevice", 0);
DevFind(hDev, "1", "category"); ! defines the Index Key Group
DevFind(hDev, "A", "type"); ! finds the first record in the Index Key
! Group satisfying this search criterion.
! ie the first instance of "1 A"
DevFirst(hDev); ! finds the first record in the Index Key
! Group

The device is first opened in Keyed Index mode. The first call to the DevFind function sets the current Index Key to 1. Calling the DevFind function with 'Type' as the search field results in a search of only those records with a 'category' of 1 (see the results of the previous example). Note that the DevFirst function returns the first record in the Index Key Group ie (1,B).

Notes:

  • If a device is opened in Keyed Index mode (open mode is not equal to 2) and the DevFirst, DevNext or DevPrev function is called before the DevFind function, then an end of file error (294, File EOF) is returned.
  • You cannot create an index on multiple fields (ie a multi-level index).
  • An index field can be configured for existing databases (a database Citect has not created) by configuring the device in the usual manner but leaving the Format field empty. See the help topic index "Devices: Formatting dBASE and SQL Database Devices".
  • Refer to knowledge base articles Q1517, Q1933 and Q2084 for more information on devices and indexes.

Glossary:

Record Pointer A data structure used to remember the current record in the device. Data modification occurs on the current record and record movement function are relative to the current record.
Keyed Index A mode for indexed devices whereby all operations are relative to a group of records that are grouped by the current index key.
Index Key The index field value, set by the DevFind function, used to group records with a common index key for processing by device functions. Only one Index Key can be defined for a database device at a time.
Index Key Group A subset of records satisfying the Index Key Criterion.
Index Field The field name used to index the device. Configured in the header entry of the device form.
Index Order The order of records when sorted on the index field.

 

Keywords:
 

Attachments