/* $DOC$
   $TEMPLATE$
      Document
   $NAME$
      ADS Overview
   $CATEGORY$
      Document
   $ONELINER$
      Advantage Database Server RDD
   $DESCRIPTION$
      rddads is an RDD for the Advantage Database Server, an xBase data
      server by Extended Systems <www.advantagedatabase.com>.
      The RDD was written by Alexander Kresin <alex@belacy.belgorod.su>
      Additional code and documentation was added by
      Brian Hays <bhays@abacuslaw.com>.

      Your Harbour application can access a remote database server for a
      true client/server architecture, or it can use the "local server"
      for stand-alone or even small network installations.

      For using this RDD you need to have all required dynamic libraries
      installed on your system.

      For building executables don't forget to include rddads.hbc in your
      hbmk2 project.

      You also need to include in your prg file following lines:

      REQUEST ADS
      rddRegister( "ADS", 1 )
      rddSetDefault( "ADS" )

      By default rddads is tuned for remote server and cdx indexes. To
      change this you may use these commands defined in ads.ch:

      SET SERVER LOCAL
      SET SERVER REMOTE

      SET FILETYPE TO NTX
      SET FILETYPE TO ADT
      SET FILETYPE TO CDX

      or functions AdsSetServerType(), AdsSetFileType().
      See the header file ads.ch for details.

      Note that the default local server is useable for
      file sharing on a small network.  The default DLL is limited to
      5 users, but an unlimited version is available from Extended Systems.

      MAX OPEN TABLES: The server (even local) has its own setting for
      Max Tables allowed open.  For the Local Server, it can be set in
      adslocal.cfg.  The default is only 50!
      For the Windows Remote Servers, use the Configuration Utility, or
      increase the setting for the TABLES configuration value in the Advantage
      Database Server configuration registry key using the Registry Editor.
      For NetWare, edit the configuration file ads.cfg.

      See ace.hlp under adslocal.cfg, or the Advantage Error Guide for
      error 7005.

      SPEED AND PERFORMANCE ISSUES

      If you have sluggish browsers, one issue could be the scrollbar.
      If it's fast with the scrollbar disabled, the browse/scrolling logic
      may not be as optimized as it could be. Scrollbars should always use
      AdsGetRelKeyPos() and AdsSetRelKeyPos() instead of key counting functions.

      If filtered data seems slower than expected, check these things:
      First, optimization is not on by default, so at the top of the app
      call

         Set( _SET_OPTIMIZE, .T. )

      or its command equivalent.  rddads will use an AOF whenever
      dbSetFilter is called *if it can*.

      Second, make sure the filter is one ADS can understand. UDFs are out,
      as are references to public or private variables. It's also best to
      remove field aliases from the string. ADS cannot reference aliases for other
      related tables, so they're superfluous.
      You can call

         ? AdsIsExprValid( cFilter )

      to check.  If this returns False, neither the Local Server nor the
      Remote Server can process it, so optimization will never occur (but
      the Harbour RDD will process the filtering locally by eval'ing the
      codeblock and testing each record). The only way to speed it up is to
      fix the filter so ADS understands it.

      You can also use dbOrderInfo(DBOI_OPTLEVEL) to see if the current
      filter is optimized or not. COMIX users can use:

            FUNCTION rlOptLevel()
               RETURN dbOrderInfo( DBOI_OPTLEVEL )

      This returns the Clipper/COMIX values (not ADS-defined values) because
      this is an RDD call, not just a wrapper to the ADS call, which uses different numbers).

   $COMPLIANCE$
      Every attempt has been made to make the RDD compliant with the
      standard dbfcdx RDD at the .prg level.
      One important difference is the handling of structural indexes.
      ACE will <b>always</b> automatically open an index with the same
      name as the data file.  There is no way to turn this feature off.

      You can use the Set() function call as well as the equivalent
      commands for SET DEFAULT TO, DATEFORMAT, DELETE, and EPOCH.
      Harbour automatically makes the call to ADS to change its internal
      setting to match Harbour's.

      INDEXING and Progress Displays:
      Remote server does not support the EVAL/EVERY clauses. Remember, there
      is an external process doing the indexing that knows nothing of
      Harbour expressions or codeblocks. Even with Local Server it's the
      DLLs doing all the indexing. So to do progress meters
      you need to implement <b>AdsRegCallback( bEval )</b>.
      It lets you set a codeblock that is eval'ed every 2 seconds.
      A numeric value of the "percent completed" is passed to the
      codeblock by the ADS server.

       <table>
       #include "inkey.ch"
       PROCEDURE Main()
          ...
          AdsRegCallback( {| nPercent | outputstuff( nPercent ) }  )
          /* The above codeblock will be called approximately
             every 2 seconds while indexing.
             The codeblock can return .T. to abort. */
          INDEX ON FIRST + LAST + LABEL1 + LABEL2 TAG First
          AdsClrCallback()
          RETURN

       STATIC FUNCTION outputstuff( nPercent )  /* The "callback" function */
          ? "output stuff", nPercent
          RETURN hb_keyStd( Inkey() ) == K_ESC  /* If press ESC, returns .T. to abort. */
      </table>

      For programmers who are already familiar with the ACE engine,
      Harbour's compatibility with dbfcdx means there are some differences
      between the rddads in Harbour and the parallel ACE documentation:

      1) In ACE, skipping backwards to BOF goes to the phantom record and
      sets the record number to 0.  In rddads, the  record pointer stays at
      the Top record and only the BOF flag is set to True.

      2) In rddads, a filter expression can be used that may not be
      valid on the server (because of references to public variables or
      User-Defined Functions).
      In these cases, all data will come back from the server
      but will be filtered by the application running on the client.
      These situations lose the benefits of having a data server and should
      be avoided, but they will function as they would in a Clipper program.

      One problem with this scenario is that index key counting
      functions that are supposed to give an accurate count respecting
      the filter (e.g. dbOrderInfo( DBOI_KEYCOUNT ) will return the values the
      Server knows about, so the counts may be inaccurate.

      3) When setting a relation, the expression must be one that can be
      evaluated by the Advantage Expression Engine.  UDFs will fail.

   $END$
 */
