Using an expression tree

<< Click to Display Table of Contents >>

Navigation:  Application development > Filtering records >

Using an expression tree

Previous pageReturn to chapter overviewNext page

An expression tree is a filter expression of type pBYTE cast as a pCANExpr. It is a three-part block of memory, consisting of:

Header A CANExpr structure defining size, number of nodes, and offsets.

Node Area A series of conditional (operator and operand) branches in the tree, "nodes," defining the filter's tree of conditions. Operand nodes point to offset locations of field names or constants stored in the literal pool area.

Literal Pool Area Used to store the field names pointed to by each field node and the constant values pointed to by each constant node.

Note that the header consists of a CANExpr structure 10 bytes in length, hence the Node Area begins at offset 10:

Header                                                Node Area                                Literal Pool Area

_bm1

The first node in the node area is the canBinary specifying the operand:  

canExpr.iFirstNode = 10 (where 10 is offset for entire expression tree)

canExpr.iLiteralStart = 48 (where 48 is offset for entire expression tree)

canBinary.Operand1 = 12 (where 12 is offset into Node Area)

canBinary.Operand2 = 24 (where 24 is offset into Node Area)

canField.iNameOffset = 0 (where 0 is offset into Literal Pool)

canConst.iOffset = strlen( <fieldName> )+1 -- (where the constant value appears just after the field name in the Literal Pool)

Example

Normally you would use an expression tree to tightly focus a view by using a tree of conditions that could be quite complex. For the sake of clarity, in this example, we want a simple filter to display only those records where "CUST_NO>1500". Our task is to create an expression tree CUST_NO > 1500.00 to pass to DbiAddFilter. The following chart represents this expression tree:

_bm2

The same expression tree is defined in C as a parameter to be passed to DbiAddFilter. The following example assumes that the compiler allocates consecutively declared variables in physically contiguous memory:

void
Filter (void)
{
   hDBIDb          hDb = 0;            // Handle to the database.
   hDBICur         hCur = 0;           // Handle to the table.
   DBIResult       rslt;               // Return value from IDAPI functions.
   pBYTE           pcanExpr;           // Structure containing filter info.
   hDBIFilter      hFilter;            // Filter handle.
   UINT16          uSizeNodes;         // Size of the nodes in the tree.
   UINT16          uSizeCanExpr;       // Size of the header information.
   UINT32          uSizeLiterals;      // Size of the literals.
   UINT32          uTotalSize;         // Total size of the filter expression.
   UINT32          uNumRecs = 10;      // Number of records to display.
   CANExpr         canExp;             // Contains the header information.
   struct {
       CANBinary BinaryNode;
       CANField  FieldNode;
       CANConst  ConstantNode;
   }
   Nodes = {                           // Nodes of the filter tree.
   {
       // Offset 0
       nodeBINARY,                     // canBinary.nodeClass
       canGT,                          // canBinary.canOp
       sizeof(Nodes.BinaryNode),       // canBinary.iOperand1
       sizeof(Nodes.BinaryNode) + sizeof(Nodes.FieldNode),
                                       // canBinary.iOperand2
                                       //   Offsets in the Nodes array
   },
   {
       // Offset sizeof(Nodes.BinaryNode)
       nodeFIELD,                      // canField.nodeClass
       canFIELD,                       // canField.canOp
       1,                              // canField.iFieldNum
       0,                              // canField.iNameOffset: szField is the
                                       //   literal at offset 0
   },
   {
       // Offset sizeof(Nodes.BinaryNode) + sizeof(Nodes.FieldNode)
       nodeCONST,                      // canConst.nodeClass
       canCONST,                       // canConst.canOp
       fldFLOAT,                       // canConst.iType
       sizeof(fConst),                 // canConst.iSize
       8,                              // canConst.iOffset: fconst is the
                                       // literal at offset strlen(szField) + 1
   }};
static const char szTblName[] = "cust";     // Name of the table
static const char szTblType[] = szDBASE;    // Type of table
static const char szField[]   = "CUST_NO";  // Name of the field for the
                                           //   third node of the tree.
static const DFLOAT fConst    = 1500.0;     // Value of the constant for
                                           //   the second node of the tree.