Buffered Fetch Functions

DP4 provides block fetch functions which allow multiple records to be read from the database at a time. This gives improved performance over the normal scheme where records are requested from the DBMS one at a time. However, the block fetch functions are inconvenient to use, particularly in interactive routines like pick_record().

The performance advantage of using block functions is most significant over a network. DP4 network programs used to attempt to optimise searches automatically - but this was of limited benefit because in many situations a buffer must be discarded in case the buffered record is no longer correct.

The buffered fetch family of functions provide a convenient encapsulation of the block fetch functions, allowing you to write code which is almost as straight forward as using regular fetch functions, but with all the performance advantage of block fetches. All the buffered fetch functions are prefixed by bf_. To use them you must open a buffer with bf_open(), read records from it with bf_fetch(), and finally close it with bf_close(). Interactive programs may need to call bf_reset() to change their position within the buffer from time to time.

In application programs, you should replace code like this:

rec_fetch_main(FIRST,&customer.l);
while (there)
{
   rec_fetch_main(NEXT,&customer.l);
}

with:

buff_customer = bf_open(&customer.l,0,0,BF_SEQUENTIAL);
bf_fetch(buff_customer,FIRST,&customer.l,0,0);
while (there)
{
   bf_fetch(buff_customer,NEXT,&customer.l,0,0);
}
bf_close(buff_customer);

In a pick_record() situation you would replace:

boolean fetch_customer(direction)
{
   if (direction == EQUAL)
   {
      customer.cust_nr = wk.save_cust[0].cust_nr;
      return rec_fetch_main(EQUAL,&customer.l);
   }
   if (rec_fetch(direction,&customer.l,_INDEX_NAME,0))
   {
      wk.save_cust[0].cust_nr = customer.cust_nr;
      MOVE(wk.save_cust[0].name,customer.name);
   }
   return there;
}

with:

boolean fetch_customer(direction)
{
   if (direction == EQUAL)
   {
      customer.cust_nr = wk.save_cust[0].cust_nr;
      return bf_reset(buff_customer,&customer.l);
   }
   if (bf_fetch(buff_customer,direction,&customer.l,_INDEX_NAME,0))
   {
      wk.save_cust[0].cust_nr = customer.cust_nr;
      MOVE(wk.save_cust[0].name,customer.name);
   }
   return there;
}

In this case, you open the buffer before the call to pick_record() and close it afterwards. The call to bf_open() looks like this:

buff_customer= bf_open(&customer.l,sizeof(customer.cust_nr),0,
    BF_INTERACTIVE);

In interactive programs where the user may be be paging up and down a window of records, the bf_ functions need to be able to change their position within a buffer. This means that bf_open() has to know where the key is in a record.