home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TBTREE.ZIP / TBTREE13.DOC < prev    next >
Encoding:
Text File  |  1988-07-31  |  76.0 KB  |  1,453 lines

  1.         
  2.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  3.         
  4.         
  5.         
  6.         
  7.         
  8.         
  9.         
  10.         
  11.         
  12.         
  13.         
  14.         
  15.         
  16.         
  17.         
  18.         
  19.                                       TBTREE13
  20.         
  21.                              ( Turbo BTree version 1.3 )
  22.         
  23.         
  24.         
  25.               Yet another implementation of BTrees for Turbo Pascal 4.0
  26.         
  27.         
  28.                       Copyright (c)  1988    Dean H. Farwell II
  29.         
  30.         
  31.         
  32.         All source code and documentation are considered to be shareware and
  33.         are copyrighted.  The following rules of engagement apply to all
  34.         documentation and code which make up TBTREE13:
  35.         
  36.         All users can and are encouraged to distribute this software freely.
  37.         This includes the uploading of this software onto applicable Bulletin
  38.         Boards etc.  The entire TBTREE13 product must be distributed as a
  39.         complete product.  Pieces can not be distributed individually.  The
  40.         documentation must be distributed with the source code.  No copyright
  41.         statements may be modified.
  42.         
  43.         All users can and are encouraged to use these utilities to develop
  44.         and/or enhance their private, shareware, or commercial software
  45.         applications.
  46.         
  47.         All users are encouraged to suggest enhancements, make suggestions and
  48.         generally lead to the development of a better product to the benefit
  49.         of all.  Users may change the code and documentation as desired for
  50.         their own use but may not then distribute those changes.
  51.         
  52.         Users may distribute these routines as part of another SHAREWARE
  53.         package.  For instance, a user could develop a DBMS using this as a
  54.         basis and can freely distribute the source code provided that:
  55.         
  56.              1.  None of this documentation or code is changed
  57.              2.  ALL code and documentation is distributed (not just parts)
  58.              3.  The user is not selling or distributing this for profit
  59.              4.  The user be registered.
  60.         
  61.         The restriction that the code and documentation not be changed is to
  62.         ensure that I can maintain some control over version releases.  I do
  63.         
  64.                                         1
  65.         
  66.         
  67.         
  68.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  69.         
  70.         
  71.         not want several versions running around that I had nothing to do
  72.         with.
  73.         
  74.         The bottom line is that you can not sell this or distribute it for
  75.         profit (except for a small fee not to exceed $10 to cover cost of
  76.         mailing, duplication and handling).  A user developing a commercial
  77.         application can not distribute the SOURCE code or documentation but a
  78.         user can use these routines to compile a commercial application.
  79.         
  80.         Users are encouraged to register their copy of this software.  The
  81.         registration fee is a very nominal $15.  The registration is not going
  82.         to make me rich but will let me know if anybody out there is at all
  83.         interested in this.  I intend to support this product and add many
  84.         capabilities.  I am looking for registered owners to provide feedback
  85.         which will help me prioritize enhancements.  If few people register
  86.         then I will assume that there is not wide spread interest in this
  87.         product.
  88.         
  89.         Anyone using this software to develop a commercial application must
  90.         register and state their intentions to use it in a commercial
  91.         application.  I will not charge royalties (except for the registration
  92.         fee).  I just want to know what people are doing with it.  Also, if
  93.         someone is distributing it as part of a shareware product, the same
  94.         restrictions apply.
  95.         
  96.         Most of all I want any feedback that you have the time and desire to
  97.         submit.  Suggestions, complaints, etc are welcome.  I especially want
  98.         feedback on errors.  I do not know of any bugs (or I'd fix them) but I
  99.         probably missed an item or two.  Send me notice immediately so that I
  100.         can distribute a fix if required. Since you have the source code, do
  101.         your best to isolate the problem. I'll try to take it from there.
  102.         
  103.         To reach me use Compuserve ID - 73240,3335 or drop me a line at:
  104.         
  105.                                 1834 Windsor Downs Ct
  106.                                 Montgomery AL  36117
  107.         
  108.         My phone number is:
  109.         
  110.                                     205-279-9552
  111.         
  112.         For hopefully obvious reasons, I will not accept collect calls.
  113.         Otherwise, feel free to call.
  114.         
  115.         As a final motivation to register, all registered users will receive
  116.         one upgrade free (via mail - no postage due or anything!) when it
  117.         becomes available.  I will mail these well before I put the version
  118.         out on CompuServe or anywhere else.  The registered users will, in
  119.         effect, become beta testers to make sure that all is well before I
  120.         release to the world.  After the first upgrade, the user can request
  121.         to receive the next upgrade for a nominal $5 to cover postage , etc.
  122.         This fee will ensure that you always have the latest version and is
  123.         probably less than the cost to download off of a bulletin board.  I
  124.         will do my best to not release trivial changes but only significant
  125.         upgrades.
  126.         
  127.         Liability:
  128.         
  129.         
  130.                                         2
  131.         
  132.         
  133.         
  134.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  135.         
  136.         
  137.         This software is not warranted.  There are no warranties expressed or
  138.         implied as to the quality, correctness, or applicability of this
  139.         software.  The author is not responsible for any loss or damages due
  140.         to the use of any software or documentation distributed as TBTREE13.
  141.         
  142.                                  Product Description
  143.         
  144.         TBTREE13 is version 1.1 of a shareware btree and database product for
  145.         use with Turbo Pascal 4.0.  It is intended to give a user the
  146.         capabilities to develop pascal applications for the creation and
  147.         manipulation of databases.  This product is extremely powerful and
  148.         FAST!!!  However, it is not the easiest thing to get a grasp on.  If
  149.         you understand the concept of btrees or at least indexing then this
  150.         will not be complicated to use.  I guarantee that it is the best
  151.         product of its type for the money and maybe the best period.  If you
  152.         have any feedback on how I can take the mystery out of using this
  153.         please let me know.
  154.         
  155.         I am presently working on a second product which will be called TBASE
  156.         and will use these routines as the database engine but will have a
  157.         much easier to understand interface for code developers. It will use
  158.         SQL like calls instead of those used in this product.  All registered
  159.         users of TBTREE13 will be shipped a beta version of TBASE as soon as
  160.         one becomes available and will get the first whack at using it.  This
  161.         in itself is worth the $15.
  162.         
  163.         Although this product provides many of the same general database
  164.         capabilities as Borland's Turbo Pascal Database Toolbox it is not
  165.         intended to be compatible.  There are several reasons for this. First,
  166.         I do not want to create any impression of any type of copyright
  167.         infringement.  Secondly, I needed to implement things differently than
  168.         they were implemented in Borland's product to be able to do the
  169.         enhancements I am planning.  Thirdly, I wanted to implement things
  170.         that Borland does not.  For instance, I support data types in my
  171.         indexes.  Other differences will be more apparent as you read through
  172.         this documentation.  Lastly, I did not have a copy of Borland's
  173.         product when I was doing this.  This really started out as more of an
  174.         academic exercise than something that I was going to release for
  175.         others.  This turned out to be a more extensive job than I thought
  176.         (big surprise there, huh?).  I figured that I might as well make it
  177.         available for others.
  178.         
  179.         This product has been greatly enhanced since version 1.0 was released.
  180.         As it presently stands, it has the following features:
  181.         
  182.         1. The ability to create data files and indexes for those files.
  183.         
  184.         2. Any number of indexes can be used for a single data file.
  185.         
  186.         3. Any number of data files can be used.
  187.         
  188.         4. All data files and index files use a virtual memory scheme in which
  189.         the most recently used pages are kept in memory using the heap.  This
  190.         is different than many other implementations which use a buffer or
  191.         stack only for index pages.  The buffer is shared by all files.  In
  192.         this way separate space does not need to be set aside for different
  193.         files.  Space utilization is maximized and performance is enhanced.
  194.         
  195.         
  196.                                         3
  197.         
  198.         
  199.         
  200.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  201.         
  202.         
  203.         5. All management of pages in memory is automatically controlled
  204.         although the user can exercise limited control if desired.
  205.         
  206.         6. Routines are provided to dump the page buffer to the printer to
  207.         facilitate viewing pages if a user is curious or masochistic.
  208.         
  209.         7. The size of the buffer is determined by the user and can be changed
  210.         dynamically as the program runs.  For example a 128K buffer could be
  211.         used initially.  If a user had a large heap requirement the buffer
  212.         size could be reduced.  The buffer size could later be increased if
  213.         desired.  This can all be done while the application is running.
  214.         
  215.         8. Problems related to keeping track of numbers of open files are
  216.         alleviated.  The user initially specifies the maximum number of files
  217.         allowed to be open at once and never has to address it again.
  218.         Routines are provided to manage the opening and closing of files
  219.         dynamically. This increases performance because files do not have to
  220.         be continually opened and closed unnecessarily.
  221.         
  222.         9. All data types supported by Turbo Pascal are explicitly supported.
  223.         In other words, values do not have to be converted to strings.  This
  224.         is a great improvement over previous systems (MY UNBIASED OPINION).
  225.         For example an index can be set up for type Byte, another for type
  226.         ShortInt, another of type String and even for type Real (but wait you
  227.         say .. Reals in an index?).  See next note!
  228.         
  229.         10. Indexes can be searched for equality, inequality, greater than,
  230.         greater than or equal to, less than, less than or equal to, and
  231.         existence.  In other words you can ask for a list of all records for
  232.         which some field of type real is LE (less than or equal to) XXX where
  233.         XXX is a var of type real and XXX := 3.141592 etc.  An index can also
  234.         searched on a range of values.  For instance an index of type byte can
  235.         be checked for a range >= 10 and < 20 etc.  Indexes containing strings
  236.         can be searched for partial string matches.  Partial string matches
  237.         can be done three ways: find a string which is at the beginning of a
  238.         string, anywhere in the string, or at the end of a string.
  239.         
  240.         11.  As physical records are deleted space is reused automatically on
  241.         future inserts.  Files should never have to be reorganized to recover
  242.         space (unless a large number of deletes were performed without any
  243.         inserts and even in this case there is not really a good reason to
  244.         reorganize unless your disk is filling up).
  245.         
  246.         12.  Included with the package is a very crude but effective source
  247.         code printing routine which can be used to dump the code in a more
  248.         usable format.  Specifically, it handles page breaks and prints a
  249.         header of useful information.
  250.         
  251.         13.  The user does not need to perform any calculations or make any
  252.         estimates prior to data file or index creation.
  253.         
  254.         14.  Code was designed using an Object Oriented Design approach to a
  255.         large extent (Turbo 4.0 lends itself to this approach much more than
  256.         Turbo Pascal 3.0 did).  This is one reason that there are so many
  257.         units.  Much of the code is reusable for other applications.
  258.         
  259.         15.  Added to the product is a sorting capability.  Sorts can be
  260.         accomplished using any number of fields in any order of precedence as
  261.         
  262.                                         4
  263.         
  264.         
  265.         
  266.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  267.         
  268.         
  269.         determined by you.  A Quicksort algorithm is used to give high
  270.         performance.  Sort fields can be any type supported (Byte, Real,
  271.         Integer, String etc).
  272.         
  273.         16.  Added the following set operations: Union, Intersection and
  274.         Difference.  These allow easy queries on multiple fields.  For
  275.         example, retrieving all personnel who have a last name starting with
  276.         'N' and who's job is 'MANAGER', etc is greatly simplified.  This
  277.         enhancement is a definite plus and not available in many other
  278.         products.
  279.         
  280.                                     List Of Files
  281.         
  282.         The following files are provided as part of the TBTREE13 product:
  283.         
  284.              Units - Source Code For All Units
  285.         
  286.                   BTREE.PAS - This unit contains the interface and
  287.                   implementation for the btrees themselves.  Although the
  288.                   implementation is fairly complex, only a few routines are
  289.                   visible to the user and give the user all the functionality
  290.                   required.  The actual working of the btree unit itself is
  291.                   not critical to the user.  The user is provided with
  292.                   routines to add an entry to an index, delete one entry from
  293.                   an index, delete all entries with a matching key value from
  294.                   an index and also retrieve record numbers which match some
  295.                   selection criterion.  The ability to create an index is also
  296.                   provided.  To delete an index just delete the file using a
  297.                   routine provided in FILES.PAS.  The BTREE unit is different
  298.                   than any other unit in the product in that it consists of
  299.                   not one but three source files.  See entry for BTREE1.INC
  300.                   and BTREE2.INC.
  301.         
  302.                   BTREE1.INC and BTREE2.INC - These are additional source
  303.                   files needed for the BTREE unit.  I split up the source code
  304.                   for the unit because the source code ended up greater than
  305.                   64K bytes.  The two additional files are include files and
  306.                   will automatically be compiled when BTREE.PAS is compiled.
  307.         
  308.                   COMPARE.PAS - This unit contains no inherent object although
  309.                   a couple of types are declared and put in the interface.  It
  310.                   is primarily made of one routine which will give the
  311.                   capability of comparing two values of the same type using
  312.                   one routine regardless of that type.  The address of the two
  313.                   values and the type of the values are passed in at run time.
  314.                   This routine alleviates the need for the user to develop a
  315.                   routine which can be used for comparisons.  All Turbo Pascal
  316.                   4.0 scaler types are handled.  Strings are the only
  317.                   structured (composite) type handled.  Several other routines
  318.                   were added to facilitate partial string searches.
  319.         
  320.                   FILEBUFF.PAS - This unit contains the interface and
  321.                   implementation for a files open list.  This list will
  322.                   contain information on all files opened (using this unit).
  323.                   A user can specify how many files can be on the list at once
  324.                   (how many the unit can allow to be open).  The unit takes it
  325.                   from there.  From then on all requests to use a file must be
  326.                   preceded by a call to the unit.  The unit will determine if
  327.         
  328.                                         5
  329.         
  330.         
  331.         
  332.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  333.         
  334.         
  335.                   the file is open and will open it if it is not. The routine
  336.                   is exceptionally useful for alleviating the need to open and
  337.                   close files for every operation.  Continually opening and
  338.                   closing files causes unacceptable performance problems. The
  339.                   file types handled are only Untyped files and Text files.
  340.                   Typed files are not currently handled.  This is due to the
  341.                   fact that strong type checking precludes the use of typed
  342.                   files (or at least I couldn't break the code and figure out
  343.                   how to make it work.  If anyone can figure out how to make
  344.                   it work, it would make this even more useful).
  345.         
  346.                   FILEDECS.PAS - This unit is nothing more than a collection
  347.                   of declarations required to support several of the other
  348.                   units. There is no code in the implementation section.
  349.         
  350.                   FILES.PAS - This unit contains the interface and
  351.                   implementation for the manipulation of files.  This fulfills
  352.                   the role of file manager (mid level management of files as
  353.                   opposed to the low level management found in FILEBUFF.PAS).
  354.                   It is the place where the different file types required in
  355.                   TBTREE13 are created, deleted, and names are adjusted
  356.                   (extensions are attached).  Additionally, there are several
  357.                   routines to set records to used and to check the status of
  358.                   records and to determine what the last record in use is.
  359.                   This is the only place where Bitmap files are manipulated
  360.                   (created, referenced, updated and deleted).
  361.         
  362.                   HEX.PAS - This unit contains the interface and
  363.                   implementation for dealing with a hex array which is a 2
  364.                   byte array used for storing a hex character (such as 7F).  A
  365.                   couple of routines are provided for converting bytes and
  366.                   bits to hex array representations.
  367.         
  368.                   LOGICAL.PAS - This unit contains the interface and
  369.                   implementation for dealing with the conversion of logical
  370.                   data records to physical records.  In TBTREE13 all physical
  371.                   records (records stored on disk) are the same size (512
  372.                   bytes).  This is how all files can share the same page
  373.                   buffer (See PAGE.PAS).  However, the logical records (data
  374.                   records in the data files) can be any size from one byte up
  375.                   to 65520 (although they will not be that large in practice).
  376.                   This unit takes the users data records stored in a variable
  377.                   and puts them in the number of physical records required.
  378.                   It also takes the appropriate data from physical record(s)
  379.                   and puts it in the variable of the users choice. A great
  380.                   deal of flexibility is available here.  One caution however!
  381.                   TBTREE13 uses FIXED LENGTH LOGICAL RECORDS.  All data
  382.                   records (within one data file) must be of the same size
  383.                   (obviously each data file can have a different logical
  384.                   record size).  If variable length data is required then the
  385.                   size of the logical record is the largest number of bytes
  386.                   required as determined by the user.  A good example of this
  387.                   is a record containing a string declared as String[20].  The
  388.                   logical record size is 21 bytes (one byte for the length).
  389.                   21 bytes should be stored and retrieved even though a string
  390.                   such as 'howdy' is stored (howdy uses 6 bytes).  Most
  391.                   products of this nature work in the same way.
  392.         
  393.         
  394.                                         6
  395.         
  396.         
  397.         
  398.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  399.         
  400.         
  401.                   LRECLIST.PAS - This unit contains the interface and
  402.                   implemetation to handle logical record lists.  A logical
  403.                   record list is a concept which is different than you will
  404.                   find in most other implementations of btrees.  When a query
  405.                   is done on an index, most btrees set a cursor to the node
  406.                   where the first matching value is found (equality).  This is
  407.                   very efficient but does not lead to the flexibility of my
  408.                   system. In TBTREE13 I build a list of logical record numbers
  409.                   corresponding to the logical records which meet the criteria
  410.                   of the query.  I can handle all boolean operations such as
  411.                   equality, inequality, greater than, greater than or equal
  412.                   to, etc.  Therefore, I could get a list of all logical
  413.                   records which meet some criteria and deal with that list
  414.                   independently of the btree.  Once I have the list I can
  415.                   compare it to other lists and do intersections, unions,
  416.                   joins, etc.  This gives the user some of the power of a real
  417.                   database management system. A user can relate a file to
  418.                   itself or to other files.  This system is the basis of my
  419.                   future work to bring true relational capabilities to
  420.                   programs written in Turbo Pascal. It gives the capability to
  421.                   do set at a time processing.  Unfortunately, nothing is
  422.                   free.  A query on a database of 10000 logical records on
  423.                   existence will give a list of 10000 logical records (40000
  424.                   bytes required to store the list).  Lists like this take
  425.                   time to build.  A fact of life is that it takes time to
  426.                   process a lot of data in a large database. The user is
  427.                   cautioned to structure queries in such a way that lists are
  428.                   not huge.  Queries on equality are not normally a problem
  429.                   (unless the index provides little selectivity).  Queries on
  430.                   inequality will be faster if a range is used.  No matter
  431.                   what type of query is used, the page buffer alleviates a
  432.                   great deal of performance problems.
  433.         
  434.                   MATH.PAS - This unit contains the interface and
  435.                   implementation to manipulate bytes at the bit level.  Only
  436.                   three routines are visible as that is all that I required in
  437.                   TBTREE13.  This unit has been redone in assembly language to
  438.                   enhance performance.  See the source listing for further
  439.                   details.
  440.         
  441.                   MYPRINT.PAS - This routine is a collection of printer codes
  442.                   and routines to print the codes.  This is sufficient for my
  443.                   purposes and is included only because I needed a couple of
  444.                   routines for TP4PRINT.PAS and PAGE.PAS.  This unit is not
  445.                   very elegant and will need to be modified if it does not
  446.                   support your printer.
  447.         
  448.                   NUMBERS.PAS - This unit contains no code in the
  449.                   implementation. It is simply a repository for often used
  450.                   types which are not part of the original Turbo Pascal 4.0
  451.                   product.
  452.         
  453.                   PAGE.PAS - This unit contains the interface and
  454.                   implementation to manipulate the page buffer.  The page
  455.                   buffer is stored internally (heap) in an area set aside to
  456.                   hold physical records. This buffer greatly enhances
  457.                   performance of the overall product. To function the buffer
  458.                   can be set to as small as one page (512 bytes).  However,
  459.         
  460.                                         7
  461.         
  462.         
  463.         
  464.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  465.         
  466.         
  467.                   performance is going to be dismal. The amount of buffer
  468.                   space is dependent on many factors and the size needs to be
  469.                   played with to see what works.  One rule stands though ..
  470.                   bigger is better!  One interesting note - routines are
  471.                   provided to change the size (both increase and decrease)
  472.                   dynamically as often as desired.  There are other routines
  473.                   available as well.  The user has the option to force a page
  474.                   to be written to disk immediately when it is changed (stored
  475.                   in the buffer) as opposed to waiting until it gets swapped
  476.                   out or all pages are written to disk.  Immediately writing
  477.                   to disk ensures that nothing gets lost on a system or
  478.                   program crash but it has severe performance implications.
  479.                   Use of this is not normally required, but the option is
  480.                   there and usable.
  481.         
  482.                   SETOPS.PAS - This unit contains routines that support set
  483.                   operations.  They facilitate queries using multiple fields
  484.                   from one data file.  This greatly reduces the workload on
  485.                   the programmer.
  486.         
  487.                   SORT.PAS - This unit contains three procedures for sorting.
  488.                   This unit was was created in version 1.2 and adds greatly to
  489.                   the overall product.  It uses a quicksort algorithm to
  490.                   provide good performance.  Just as importantly, it supports
  491.                   all data types supported by TBTREE13 and is extremely easy
  492.                   to use.
  493.         
  494.                   STRINGS.PAS - This unit contains routines to manipulate
  495.                   strings.  Only two routines are provided.  There is great
  496.                   room for expansion of this unit if required.
  497.         
  498.                   TIME.PAS - This unit contains the implementation and
  499.                   interface to manipulate time arrays.  A time array stores a
  500.                   four byte time value retrieved directly from RAM.  It is
  501.                   probably not the best way to do this particular function,
  502.                   but it works and is fast. It is essentially only used in
  503.                   conjunction with least recently used routines (in PAGE.PAS
  504.                   and FILEBUFF.PAS). If anyone experiences compatibility
  505.                   problems let me know.
  506.         
  507.              Programs - Source Code For All Programs
  508.         
  509.                   TP4PRINT.PAS - This program is provided merely to permit my
  510.                   source code to be printed out in a better format than
  511.                   provided by the DOS Print command.  It looks for page
  512.                   control codes imbedded in my source (control codes are
  513.                   comments to the compiler) and controls paging.  It puts a
  514.                   header which includes file name, page and print time.  It
  515.                   provides top and bottom margins as well.  Give it a try by
  516.                   printing out one of the source code files to see if you want
  517.                   to use it or another source code printer. Syntax is :
  518.         
  519.                         TP4PRINT  filename   where filename includes path if
  520.                                              source is not in the current
  521.                                              directory
  522.         
  523.                   BUILDTPU.PAS - When this program is compiled, all units
  524.                   associated with TBTREE13 will also be compiled. This simply
  525.         
  526.                                         8
  527.         
  528.         
  529.         
  530.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  531.         
  532.         
  533.                   provides a convenient way to build all the units at once
  534.                   without compiling them individually.
  535.         
  536.                   EXAM1.PAS - This example program demonstrates how to create
  537.                   a data file and a couple of indexes.  It then demonstrates
  538.                   how to insert data into the data file and the indexes.
  539.                   Several other routines are demonstrated as well.  Important
  540.                   to note is that this routine has been changed from version
  541.                   1.2 and prior.  It now uses StoreNewLogicalRecord to store
  542.                   the record as opposed to using StoreALocicalRecord.  Look at
  543.                   the source and this may make sense.
  544.         
  545.                   EXAM2.PAS - This program shows how to perform retrievals.
  546.                   The files created in EXAM1.PAS are used.
  547.         
  548.                   EXAM3.PAS - This program shows how to do deletes and
  549.                   updates.  The files created in EXAM1.PAS are used.
  550.         
  551.                   EXAM4.PAS - This program shows how to use routines in
  552.                   FILEBUFF.PAS with text files.
  553.         
  554.                   EXAM5.PAS - This program shows how to use the retrieval on
  555.                   range routine.  The files created in EXAM1.PAS are used.
  556.         
  557.                   EXAM6.PAS - This program shows how to use the retrieval on
  558.                   partial string match routine.  The files created in
  559.                   EXAM1.PAS are used.
  560.         
  561.                   EXAM7.PAS - This program shows how to build/rebuild indexes
  562.                   from an existing data file.  The files created in EXAM1.PAS
  563.                   are used.
  564.         
  565.                   EXAM8.PAS - This program shows use of routine to delete
  566.                   entries from a logical records list.  The files created in
  567.                   EXAM1.PAS are used.
  568.         
  569.                   EXAM9.PAS - This program shows an example of sorting using
  570.                   the SORT unit.   The files created in EXAM1.PAS are used.
  571.         
  572.                   EXAM10.PAS - This program shows an example of using one of
  573.                   the set operations found in the SETOPS unit.  The files
  574.                   created in EXAM1.PAS are used.
  575.         
  576.                            Instructions For Use of TBTREE13
  577.         
  578.         The following is a short set of instructions for performing the more
  579.         common database type operations using TBree11.
  580.         
  581.              Uses Statements - All of the units were compiled with the
  582.              appropriate uses statement included.  Therefore, the user does
  583.              not need to be concerned about order when specifying units in the
  584.              uses statements in the user's programs.  As you can see in my
  585.              examples, I put the units in alphabetical order.  The user only
  586.              needs to put the units which have either type statements or
  587.              routine calls or both which must be visible within the user's
  588.              program.  My example programs demonstrate which ones are probably
  589.              required.  One method which actually works is to not include any
  590.              initially and let the compiler find the syntax errors.  When an
  591.         
  592.                                         9
  593.         
  594.         
  595.         
  596.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  597.         
  598.         
  599.              error is found because a type or routine is not found then see
  600.              which unit it's in and put that unit in the uses statement.  It's
  601.              not a great way to do it, but it works.
  602.         
  603.              Setting Initial Parameters - Several parameters should be set by
  604.              the user although they have defaults if a value is not set by the
  605.              user.  All of the parameters are only accessible by calling
  606.              routines supplied to check and set values.  The variables
  607.              themselves are not visible to the user.  The following parameters
  608.              can be set by the user:
  609.         
  610.                   Open Files Allowed - Contained in FILEBUFF.PAS.  Determines
  611.                   number of open files allowed.  See FILEBUFF.PAS for
  612.                   details.  To set the parameter to a value of 5 do the
  613.                   following:
  614.         
  615.                        SetMaxOpenFiles(5);
  616.         
  617.                   Maximum Buffer Pages Allowed - Contained in PAGE.PAS.
  618.                   Determines the maximum number of 512 byte pages to keep in
  619.                   memory at one time.  Set this to something that makes sense
  620.                   for your machine (memory size available).  Since this is set
  621.                   at run time, you can set this after you determine how much
  622.                   memory is available.  To set this parameter to 50 pages (25K
  623.                   bytes) use the following:
  624.         
  625.                        SetMaxBufferPages(50);
  626.         
  627.                   One note is that the buffer is initialized to 128K bytes
  628.                   which may be too large for your application.  You should
  629.                   reset the default to whatever you want.
  630.         
  631.         
  632.                   Immediate Disk Write - This parameter if set to TRUE will
  633.                   force a write of a page to disk immediately after it is
  634.                   stored in the page buffer.  Otherwise, the page will only be
  635.                   written when it gets swapped out or is explicitly written by
  636.                   the user (all pages for a file or all pages).  To set this
  637.                   value to TRUE use:
  638.         
  639.                        SetImmediateDiskWrite(TRUE);
  640.         
  641.              Creating Data Files - One of the first things we would want to do
  642.              is create data files to hold our data.  This is extremely simple.
  643.              We only need to make one call for each data file.  The following
  644.              statements would create a data file:
  645.         
  646.                   var
  647.                       xxx : FnString;   (* holds name of data file *)
  648.         
  649.                   begin
  650.                   xxx := 'MYFILE';      (* name of file WITHOUT extension *)
  651.                   Createfile(xxx,DATA); (* create the file and append the
  652.                                            extension ('.dat') for a DATA
  653.                                            file *)
  654.                   end;
  655.         
  656.              Notice that the xxx is not a file type but an 80 character string
  657.         
  658.                                         10
  659.         
  660.         
  661.         
  662.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  663.         
  664.         
  665.              type which holds the name of the file.  The file name assigned
  666.              does not initially have an extension.  The extension is appended
  667.              automatically when CreateFile is called.  Notice that the type of
  668.              file created is a DATA file.  This is absolutely the only type of
  669.              file that the user should ever create using the CreateFile
  670.              routine.  INDEX files are created a different way.  BITMAP files
  671.              and LLIST files are only created by routines internally.  These
  672.              two are also deleted internally.  Do not fool with these last two
  673.              file types explicitly.
  674.         
  675.              Creating Index Files - The next step is to create one or more
  676.              index files for each data file.  You will not normally have a
  677.              data file with no indexes (although for small files, you may want
  678.              to).  To create an index file the user must know the type and
  679.              size of the key (item to be stored in the index).  The following
  680.              statements will create an index file for the data file created
  681.              above.  The index will hold Byte values (values from 0 - 255).
  682.         
  683.                   var
  684.                       yyy : FnString;
  685.         
  686.                   begin
  687.                   yyy := 'Index1';             (* notice no extension *)
  688.                   CreateIndex(yyy,SizeOf(Byte),xxx,BYTEVALUE);
  689.         
  690.              Notice that the data file name is also passed in.  This is stored
  691.              in the header of the index file.  I do not presently use it for
  692.              anything, but I think I'm going to need it later.  I did not want
  693.              to have to change the parameters needed in later releases.  Also
  694.              notice use of the SizeOf routine to pass in the size of the item
  695.              to be stored in the index.  This is usually more accurate than
  696.              passing in a constant value.  This will especially help avoid
  697.              errors when using strings.  Remember, strings use one extra byte
  698.              for the length.
  699.         
  700.              Inserting Data - Once files and indexes exist we can insert data.
  701.              Inserting data consists of two separate steps.  The first step is
  702.              to insert the data into the data file. The second step is to
  703.              insert the applicable data into each index which is associated
  704.              with that data file.  To insert data we first need to have the
  705.              data record stored in memory somewhere.  The most logical place
  706.              to have the data record is in a variable which is of type record
  707.              of some kind.  For example, the following is an example of a
  708.              variable declaration which would work:
  709.         
  710.              type
  711.                  MyRecord = record
  712.                             field1 : Byte;       (* for this example this
  713.                                                     is the only field
  714.                                                     indexed (Index1) although
  715.                                                     you could index all fields
  716.                                                     if desired.             *)
  717.                             field2 : Word;
  718.                             field3 : String[10];
  719.                             end;
  720.         
  721.              var
  722.                  thisRec : MyRecord;
  723.         
  724.                                         11
  725.         
  726.         
  727.         
  728.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  729.         
  730.         
  731.                  lrNum : LrNumber;
  732.         
  733.              We could use the following sequence to insert a record in the
  734.              data file and the index associated with this data file:
  735.         
  736.                   thisRec.field1 := 20;
  737.                   thisRec.field2 := 60000;
  738.                   thisRec.field3 := 'Hi Mom';
  739.         
  740.                   lrNum := StoreNewLogicalRecord(xxx,thisRec,SizeOf(thisRec));
  741.         
  742.                   InsertValueInBTree(yyy,lrNum,thisRec.field1);
  743.         
  744.              Notice that StoreNewLogicalRecord was used because it will find
  745.              an unused logical record number and assign it to this new record.
  746.              This logical record number is the one inserted (along with the
  747.              associated value) into the BTree.  This is a change form versions
  748.              prior to version 1.3.  This simplifies things and makes stroring
  749.              much more straightforward.
  750.         
  751.              Retrieving Data - Retrieving data consists of making a query to
  752.              an index.  The query is a procedure call which will build and
  753.              return a list of logical records which match the selection
  754.              criteria.  The query conditions are defined in NUMBERS.PAS and
  755.              are of type Condition.  Once the list is retrieved, the user can
  756.              step through the list starting at either end and going in either
  757.              direction.  The logical record numbers are stored in the index in
  758.              such a way that their corresponding key values (values in the
  759.              index) are in ascending order.  A logical record list created
  760.              using an index will reflect this order.  If there are multiple
  761.              occurences of the same key then the last one added is in the
  762.              front.  As previously noted, the list can be traversed front to
  763.              back (ascending) or back to front (descending).  A cursor is kept
  764.              internally in the list to keep track of where the user is in the
  765.              list.  The user can not get to the cursor but can set it to the
  766.              front or back and move it forward or backward (by retrieving
  767.              values from the list).  Normally, to traverse the list, set the
  768.              cursor to the front of the list and then set up a loop which will
  769.              traverse the list and terminate when a logical record number of 0
  770.              is returned.  The list is not disturbed as you move through it.
  771.              It will exist until you destroy it or until the program ends.
  772.              If the program ends before the list is destroyed explicitly by
  773.              the user then there may be a file on disk with an extension of
  774.              '.lrl'.  If you terminate and find any of this type of file
  775.              laying around then you did not destroy it prior to ending the
  776.              program.  You should fix this as leaving a list hanging around
  777.              just takes up space and does nothing productive.  There is a
  778.              limit of 99 lists which can coexist. This is such an
  779.              exceptionally large number that if you ever exceed it there is an
  780.              error somewhere.  Therefore, I did not leave provisions to
  781.              terminate gracefully if this is exceeded.  An example of a call
  782.              to retrieve data follows:
  783.         
  784.                   var
  785.                       key : Byte;
  786.                       lrLst : LrList;
  787.                       lrNum : LRNumber;
  788.         
  789.         
  790.                                         12
  791.         
  792.         
  793.         
  794.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  795.         
  796.         
  797.                   begin
  798.                   key := 20;
  799.                   GetValuesFromBTree(yyy,key,LE,lrLst);
  800.                   (* lrLst is the newly created list *)
  801.                   lrNum := GetFirstLr(lrLst);       (* set cursor to front *)
  802.                   while lrNum <> 0 do                    (* traversal loop *)
  803.                       begin
  804.                       GetALogicalRecord(xxx,lrNum,thisRec,SizeOf(thisRec));
  805.                       (* we can not do whatever with the record *)
  806.                                           .
  807.                                           .
  808.                                           .
  809.                       lrNum := GetNextLr(lrLst);
  810.                       end;                  (* this will continue until end of list *)
  811.         
  812.              Versions 1.1 and later have the added capability to retrieve
  813.              records for a range of values and retrieve records on a partial
  814.              string match. An example of each follows:
  815.         
  816.                   var
  817.                       key1,
  818.                       key2 : Byte;
  819.                       lrLst : LrList;
  820.                       lrNum : LRNumber;
  821.         
  822.                   begin
  823.                   key1 := 10;
  824.                   key2 := 75;
  825.                   GetRangeFromBTree(yyy,key1,GE,key2,LE,lrLst);
  826.                                                           (* build list of logical
  827.                                                              record numbers which
  828.                                                              are between 10 and 75  *)
  829.         
  830.                   (* list is in lrLst *)
  831.                   lrNum := GetFirstLr(lrLst);
  832.                   while lrNum <> 0 do
  833.                       begin
  834.                       GetALogicalRecord(xxx,lrNum,thisRec,SizeOf(thisRec));
  835.                       (* we can not do whatever with the record *)
  836.                                           .
  837.                                           .
  838.                                           .
  839.                       lrNum := GetNextLr(lrLst);
  840.                       end;                  (* this will continue until end of list *)
  841.         
  842.                  ------------------------------
  843.         
  844.                   var
  845.                       keyString : String[10];
  846.                       lrLst : LrList;
  847.                       lrNum : LRNumber;
  848.         
  849.                   begin
  850.                   keyString := 'C';
  851.                   (* assume zzz is index holding values of type STRINGVALUE *)
  852.                   GetSubstringFromBTree(zzz,keyString,ST,lrLst);
  853.                                                           (* build list of logical
  854.                                                              record which begin with
  855.         
  856.                                         13
  857.         
  858.         
  859.         
  860.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  861.         
  862.         
  863.                                                              'C'                    *)
  864.                   (* list is in lrLst *)
  865.                   lrNum := GetFirstLr(lrLst);
  866.                   while lrNum <> 0 do
  867.                       begin
  868.                       GetALogicalRecord(xxx,lrNum,thisRec,SizeOf(thisRec));
  869.                       (* we can not do whatever with the record *)
  870.                                           .
  871.                                           .
  872.                                           .
  873.                       lrNum := GetNextLr(lrLst);
  874.                       end;                  (* this will continue until end of list *)
  875.         
  876.         
  877.              Deleting Data - Deleting data is the inverse of inserting data.
  878.              There are two steps involved.  The first step is to retrieve the
  879.              record.  This is only required if we do not know the values for
  880.              all fields which have a corresponding index.  Once we have the
  881.              record we can delete the entries from the index(es).  The second
  882.              step is to delete the logical record from the data file.  For the
  883.              following example assume that the same definitions used above
  884.              apply but that field2 also has an index with the file name
  885.              residing in a variable zzz.  Also assume that we know that we
  886.              want to delete logical record number 24:
  887.         
  888.                   GetALogicalrecord(xxx,24,thisRec,SizeOf(thisRec));
  889.         
  890.                   DeleteValueFromBTree(yyy,24,thisRec.field1);
  891.                   DeleteValueFromBTree(zzz,24,thisRec.field2);
  892.         
  893.                   DeleteRecord(xxx,24);    (* delete value from data record *)
  894.         
  895.              Updating Data - There are no separate commands to update data.
  896.              Updating is again a two step process.   The first step is to
  897.              fetch the appropriate data record(s).  Once this is accomplished,
  898.              the appropriate fields can be updated and the data file can be
  899.              stored.  A third step may be required.  If any indexed fields
  900.              (fields which have an index associated with them) are changed
  901.              then the old value will have to be deleted and then the new value
  902.              will have to be inserted into the index.  Rather than show an
  903.              example here, I refer you to EXAMPLE3.PAS.  I noticed that in
  904.              that example, I store the updated data record after updating the
  905.              index rather than before.  The order of these two operations is
  906.              not important.
  907.         
  908.              Deleting Files - The operation of deleting a file is not going to
  909.              be done very often but will be necessary from time to time.  It
  910.              is very important that the routine provided be used as opposed to
  911.              going to DOS and doing a delete.  The provided routine does some
  912.              necessary cleanup work.  Specifically, it gets rid of the
  913.              appropriate BITMAP.  The following is an example:
  914.         
  915.                   DeleteFile(yyy);
  916.         
  917.              Notice that this routine is used by the user to delete both index
  918.              and data files.  Deleting a data file will not automatically
  919.              delete the associated index files.
  920.         
  921.         
  922.                                         14
  923.         
  924.         
  925.         
  926.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  927.         
  928.         
  929.              Sorting - Sorting can be done on any number of fields as you
  930.              desire.  Sorting requires two steps.  The first is to build a
  931.              sort field list, a list containing information on each of the
  932.              fields to sort on.  The second step is to use this sort field
  933.              list to sort a logical records list.  After sorting is completed,
  934.              the user should destroy the sort field list using the provided
  935.              routine unless the list will be required later.  An example
  936.              follows:
  937.         
  938.              type
  939.                  MyRecord = record
  940.                             field1 : Byte;       (* for this example this
  941.                                                     is the only field
  942.                                                     indexed (Index1) although
  943.                                                     you could index all fields
  944.                                                     if desired.             *)
  945.                             field2 : Word;
  946.                             field3 : String[10];
  947.                             end;
  948.         
  949.              var
  950.                  lrLst : LrList;
  951.                  sPtr : SortFieldList;
  952.         
  953.                  begin
  954.                  GetValidLogicalRecords(xxx,lrLst);   (* list of all records *)
  955.         
  956.                  sPtr := NIL;  (* EXTREMELY CRITICAL !!! - you must pass in a
  957.                                   pointer variable whose value is NIL.  If
  958.                                   you forget this little step all kinds of
  959.                                   bad things will probably happen!!!         *)
  960.         
  961.                  AddFieldToSortList(sPtr,4,STRINGVALUE);
  962.                  AddFiledToSortList(sPtr,2,WORDVALUE);
  963.                  SortList(lrLst,xxx,sPtr,SizeOf(MyRecord));
  964.                  DestroySortList(sPtr);           (* retrieve the heap space *)
  965.                  end;
  966.         
  967.              Notice that the second parameter is the BYTE position of the sort
  968.              field within the data record.  It is not the field number.  This
  969.              is extremely important!!  See SORT.PAS for details.
  970.         
  971.              Building/Rebuilding Indexes - Once in awhile you may manage to
  972.              wipe out an index or in some other way cause it to be out of
  973.              whack with your data file.  Or, you may want to add an index to a
  974.              field which previously did not have an index.  This can easily be
  975.              accomplished using a routine added in version 1.1.  Rather than
  976.              repeating the example here, please refer to EXAMPLE7.PAS which
  977.              will show how to build a list of existing records and rebuild an
  978.              index from that list.  The added routine will also allow you to
  979.              build a list of all logical records associated with a data file
  980.              without using an index.
  981.         
  982.              Viewing Status Information - I have included several routines for
  983.              checking on the values of certain parameters and for allowing the
  984.              user to delve into the depths if desired.  The first routine to
  985.              discuss is one which allows you to find out how many entries are
  986.              in a logical record list once it has been created.  To accomplish
  987.         
  988.                                         15
  989.         
  990.         
  991.         
  992.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  993.         
  994.         
  995.              this the following call is used:
  996.         
  997.                   cnt := GetCountLr(lrLst);   (* lrLst is your variable where
  998.                                                  the list resides *)
  999.         
  1000.              A second valuable utility is a routine which will return the
  1001.              number of files which are presently open using the FILEBUFF unit.
  1002.              In other words this returns the number of files which are on the
  1003.              files open list.  This is not necessarily the number of files
  1004.              which DOS thinks is open.  Only files opened using the create
  1005.              file or open file routines provided in FILEBUFF.PAS will be
  1006.              included in this number.  Not included will be other files opened
  1007.              by the user and the files such as standard input and output etc.
  1008.              An example of a call is below:
  1009.         
  1010.                   cnt := GetNumberOpenFiles;
  1011.         
  1012.              Several routines are provided in FILES.PAS which have not been
  1013.              discussed yet.  The first is RecordUsed.  This function will
  1014.              check to see if a given record is used.  It is probably only
  1015.              useful to a user for checking to see if a logical record is in
  1016.              use (data record).  Using it will not cause any problems, but see
  1017.              FILES.PAS to be sure that you understand what this routine is
  1018.              telling you.  The other routine of interest in FILES.PAS is
  1019.              FixFileName.  This is very important for appending the correct
  1020.              file extension to the file name.  Remember, when a file is
  1021.              created, the correct extension is appended to the name
  1022.              automatically.  If a program does not create a file but uses one
  1023.              that already exists then the file name residing in the users
  1024.              variable (of type FnString) must have the correct extension.
  1025.              Instead of leaving that to you I have included FixFileName.  When
  1026.              you start up a program, call FixFileName for each data file and
  1027.              index file you will use.  This will ensure that there will not be
  1028.              problems with the wrong extension.  An example is below:
  1029.         
  1030.                   var
  1031.                       xxx : FnString;
  1032.         
  1033.                   begin
  1034.                   xxx := 'MyFile';
  1035.                   FixFileName(xxx,DATA);
  1036.         
  1037.              The largest number of utilities lies in PAGE.PAS.  The first
  1038.              routines of interest are the ones for writing part or all of the
  1039.              buffer to disk.  The demand paging used in the PAGE.PAS unit is
  1040.              critical to the performance of TBTREE13.  Since a large number
  1041.              of pages are in the memory buffer, the need to constantly go out
  1042.              to disk is reduced.  Disk seeks (head movement) is what slows
  1043.              down most database operations.  The secret is to do everything
  1044.              you can to alleviate the need to go out to disk.  Memory is many
  1045.              times faster than external storage.  However, if changes are made
  1046.              to pages in the buffer we want to ensure that they do not get
  1047.              lost.  We need to write them to disk at some point.  Normally, a
  1048.              page will stay in memory until another page needs the space. The
  1049.              unit uses a least recently used algorithm which in nothing earth
  1050.              shattering (but it works).  When a page needs to be swapped out,
  1051.              a check is made to see if it is dirty (changes have been made
  1052.              since it was read in or last written to disk).  If it is clean no
  1053.         
  1054.                                         16
  1055.         
  1056.         
  1057.         
  1058.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  1059.         
  1060.         
  1061.              problem.  If it is dirty it is written to disk prior to allowing
  1062.              the page to be reused.  The user can force pages to be written
  1063.              out at any time.  One method is to set a parameter which forces a
  1064.              write to disk anytime a page is written to in memory.
  1065.              Essentially, a page will never be dirty this way.  To accomplish
  1066.              this the SetImmediateDiskWrite routine is used.  The user can set
  1067.              this parameter to TRUE or FALSE.  FALSE is the default, but the
  1068.              user should probably make an explicit call anyway on
  1069.              initialization so there is no doubt or confusion.  If FALSE is
  1070.              set, the user may still want to periodically write pages to disk.
  1071.              The user can write all pages for a given file or all pages in the
  1072.              buffer.  For Example:
  1073.         
  1074.                   WriteEntireBufferToDisk;
  1075.         
  1076.                             or
  1077.         
  1078.                   WriteBufferToDisk(xxx);
  1079.         
  1080.              The user should always write all pages to disk prior to
  1081.              termination.  Otherwise, changes made to pages still in memory
  1082.              will be lost.  A handy way to do this is to call it from an exit
  1083.              procedure.  See EXAMPLE2.PAS for an example.
  1084.         
  1085.              A second set of routines are provided to get rid of (release)
  1086.              pages in the buffer.  The pages should be written to disk prior
  1087.              to release.  These routines can be dangerous.  I need them
  1088.              internally for operations such as changing the size of the buffer
  1089.              dynamically and also for deleting a file.  They are visible and
  1090.              free to use, but understand what you're doing first.  If you're
  1091.              looking for a convenient way to wreck havoc with your data these
  1092.              two are perfect candidates.  The only reason I can forsee why you
  1093.              would want to attempt to use these is to release some pages for
  1094.              files you won't need for a while to leave room for an operation
  1095.              which will need a lot of pages.  Before releasing write the
  1096.              affected pages to disk!!  There is not really a need to micro
  1097.              manage the resources like this and they can lead to problems if
  1098.              misused.  Accidentally, losing a node (page) in the middle of an
  1099.              index will leave it in an unrepairable state and will ruin your
  1100.              whole day.
  1101.         
  1102.              A third set of routines are much friendlier and I can stay off my
  1103.              soap box.  These routines manipulate and check the size of the
  1104.              buffer.  All values are in terms of pages.  A page is 512 bytes.
  1105.              To digress slightly, 512 worked well because a smaller number
  1106.              caused inefficiency in the least recently used page algorithm and
  1107.              also meant that index keys had to be smaller.  A larger number
  1108.              means that less pages can be in memory at once.  Do not try to
  1109.              change this constant as a lot of things are affected.  Just
  1110.              changing the constant will not work properly.  This is due to the
  1111.              fact that a constant declaration can not be declared using a
  1112.              simple expression.  For example:
  1113.         
  1114.                   const
  1115.                       xxx = 10;
  1116.                       yyy = xxx/2;  (* illegal *)
  1117.         
  1118.              Therefore, other constants that depend on xxx have to be set
  1119.         
  1120.                                         17
  1121.         
  1122.         
  1123.         
  1124.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  1125.         
  1126.         
  1127.              explicitly.  In the above, yyy would have to be set to 5.
  1128.              Anyway, back to the matters at hand.  To set the size of the
  1129.              buffer the following call should be made:
  1130.         
  1131.                   SetMaxBufferPages(50);  (* 25K bytes *)
  1132.         
  1133.              If a user does not set the page limit explicitly, the value will
  1134.              default to one page.  Everything still works, but doing this will
  1135.              pretty well define slow.  A minimum of 10 pages is required to
  1136.              have this work well at all.  One hundred or so pages is
  1137.              preferred.  A great deal depends on your application as well! A
  1138.              user can check this value at any time by doing the following:
  1139.         
  1140.                   cnt := CheckMaxBufferPages;
  1141.         
  1142.              The user can check the number actually in use by doing the
  1143.              following:
  1144.         
  1145.                   cnt := CheckPagesInUse;
  1146.         
  1147.              One routine not mentioned earlier is CheckImmediateDiskWrite which
  1148.              returns TRUE if dirty pages will be immediately written to disk,
  1149.              FALSE otherwise.
  1150.         
  1151.              One interesting routine is PrintPagebuffer.  This routine is one
  1152.              that I developed for my own debugging purposes and is included to
  1153.              allow you to see what the page buffer looks like.  One warning
  1154.              though, if the page buffer is large, the output will be quite
  1155.              lengthy.
  1156.         
  1157.              The last routine is more for curiosity's sake and for tuning the
  1158.              size of the buffer.  A call to PrintBufferStats will print the
  1159.              statistics for buffer use.  The number of pages in use, the
  1160.              maximum number of pages allowed, the number of requests for a
  1161.              page (fetches), the number of fetches in which the page was in
  1162.              the buffer (hits) and the ratio of hits to fetches will be
  1163.              output.  A hit ratio of much below 95% could signal a requirement
  1164.              to increase the buffer size.  You really need to keep this number
  1165.              in perspective though.  If you are walzing through a file in
  1166.              which none of the records are in the buffer, the hit ratio will
  1167.              be poor.  Other operations will have higher hit ratios.  At least
  1168.              it's there to use as desired.
  1169.         
  1170.              A recently added routine contained in the BTREE unit is
  1171.              NumberOfBTreeLevels which returns the number of levels currently
  1172.              in an index.  If that number gets above 10 you are doing
  1173.              something rather strange and may run into stack problems.  The
  1174.              cause of such an occurence is that you have a huge number of
  1175.              index entries (many thousands) or your index entries are large.
  1176.              The only entries over 4 bytes are strings.  These types of
  1177.              indexes should use strings as small as possible. Don't use first
  1178.              name, last name, and middle initial as all one indexed filed
  1179.              unless there is a really good reason to (doubtful).  Any string
  1180.              index entry over about 20 bytes is suspect.  Remember what an
  1181.              index is for .. to store something to allow quick retrievals.
  1182.              The index is not designed to be the data file.  A deep index will
  1183.              simply not be as fast as a shallow index.  The smaller the index
  1184.              entry size, the shallower the index.
  1185.         
  1186.                                         18
  1187.         
  1188.         
  1189.         
  1190.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  1191.         
  1192.         
  1193.         
  1194.              Other Routines - I discussed above the routines which are
  1195.              directly applicable to a user who wants to use the indexing and
  1196.              data manipulation capabilities of TBTREE13.  There are some lower
  1197.              level general routines such as those found in MATH.PAS and
  1198.              STRINGS.PAS which are used internally.  Since they are fairly
  1199.              general in nature,  they may have applicability for your other
  1200.              applications.  I won't go into details on their inner workings
  1201.              here, but you have the source code, so you can look in the units
  1202.              to see if there is anything else useful for whatever you happen
  1203.              to be doing.
  1204.         
  1205.         
  1206.                              Current Product Limitations
  1207.         
  1208.         
  1209.         The following limitations apply to TBTREE13.  Only limitations
  1210.         inherent to TBTREE13 are discussed.  DOS limits and practical limits
  1211.         like disk drive capacity are not discussed.  These limitations may
  1212.         change (become less restrictive) in future additions.
  1213.         
  1214.         
  1215.                 Number of Data Files - No Limit
  1216.         
  1217.                 Number of Index Files Per Data File - No Limit
  1218.         
  1219.                 Size of Data File - MAXLONGINT (2,147,483,647) Logical or
  1220.                                     Physical Records (whichever comes first)
  1221.                                     or disk space (the real limit!!)
  1222.         
  1223.                 Size of Index File - MAXLONGINT Physical Records. The real
  1224.                                      restriction is going to be stack size.  I
  1225.                                      use a recursive routine to traverse the
  1226.                                      BTrees.  Recursion is very efficient for
  1227.                                      this but has the problem that each level
  1228.                                      keeps a couple of thousand bytes on the
  1229.                                      stack.  It is very important to use a
  1230.                                      large stack size if indexes are going to
  1231.                                      be deep.  Most indexes will not be more
  1232.                                      than 4 or 5 levels deep unless a HUGE
  1233.                                      number of records are involved or the
  1234.                                      keys in the indexes are large.  Large is
  1235.                                      relative, but you need to try to keep
  1236.                                      entries below 20 bytes or so.  This
  1237.                                      really only affects strings presently.  I
  1238.                                      would like to know if anyone is running
  1239.                                      into problems with this as I can handle
  1240.                                      this iteratively rather than recursively
  1241.                                      which will make the problem disappear at
  1242.                                      the expense of some added coding
  1243.                                      complexity.  I recently did a test to see
  1244.                                      to see how critical this is.  I did a
  1245.                                      test using an index entry size of 100
  1246.                                      bytes (100 byte strings).  I entered over
  1247.                                      27000 records before running out of disk
  1248.                                      space (took over one day on my archaic
  1249.                                      4.77 MHz computer!).  I had somewhere in
  1250.                                      the area of 15 levels which is more than
  1251.         
  1252.                                         19
  1253.         
  1254.         
  1255.         
  1256.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  1257.         
  1258.         
  1259.                                      you should reasonably have.  I also used
  1260.                                      a 32K stack (64K being the maximum
  1261.                                      allowed).  Anyway, I couldn't blow it up
  1262.                                      so I don't think you will either!
  1263.         
  1264.                 Size of Page Buffer - Limited by heap space.  I have not used
  1265.                                       this with any type of heap extender or
  1266.                                       other program which uses other memory
  1267.                                       (extended, expanded) for the heap.  I
  1268.                                       would enjoy seeing feedback if anyone
  1269.                                       tries it.  If I need to do something to
  1270.                                       facilitate use of a heap extender let me
  1271.                                       know and I'll try to accomodate.
  1272.         
  1273.                 Number of Files Open At Once - Actual number set by user, but
  1274.                                                user does not have to worry
  1275.                                                about keeping track of files
  1276.                                                used by TBTREE13 since it opens
  1277.                                                and closes files as required.
  1278.         
  1279.                 Size of Key (Index Entry) - 494 bytes.  The present
  1280.                                             restriction is really 256 bytes
  1281.                                             since the only composite data type
  1282.                                             allowed in the indexes is the
  1283.                                             string type.  Realistically, you
  1284.                                             do not want to come close to this
  1285.                                             number of bytes per entry or your
  1286.                                             index will be much deeper than
  1287.                                             desired.
  1288.         
  1289.                 Size of Data Record - 65520 bytes since this is the limit
  1290.                                       for structured (composite) types in
  1291.                                       Turbo Pascal 4.0.
  1292.         
  1293.                 Max File Name Length - 80 characters including drive
  1294.                                        designator, path, file name and
  1295.                                        extension.
  1296.         
  1297.                 Logical List Limit - Presently, 99 lists can be exist at one
  1298.                 time.  This is probably about 95 more than ever required.
  1299.         
  1300.                 Number Of Sort Fields - Unlimited
  1301.         
  1302.                           Future Enhancements / Directions
  1303.         
  1304.         One of the advantages of using the shareware concept to distribute
  1305.         this software is that I can be very flexible and can tailor this
  1306.         product to the needs of users.  I am soliciting as much feedback as
  1307.         possible.  I need to know if there is interest in a product such as
  1308.         this and also need to know what is really important to users.  I hope
  1309.         to be able to accomplish the following in the future:
  1310.         
  1311.             I may change the BTREE.PAS unit to include a binary search routine
  1312.             internally to speed the finding of key matches. Presently I use a
  1313.             linear search within each node (index page). This will increase
  1314.             performance somewhat.  It will be totally transparent to users.
  1315.             So far, it is faster than everyone imagined, so I have gotten no
  1316.             negative feedback concering performance.
  1317.         
  1318.                                         20
  1319.         
  1320.         
  1321.         
  1322.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  1323.         
  1324.         
  1325.         
  1326.             I may change the delete routines in the BTREE.PAS unit to force
  1327.             combining of nodes when each is half full or less. Presently, a
  1328.             node is not deleted until the last entry is deleted. This will add
  1329.             a little bit of performance on queries and will reduce the size of
  1330.             the indexes if deletes are done often, but will otherwise be
  1331.             transparent.
  1332.         
  1333.             I may change the BTREE.PAS unit so that I do not use recursion to
  1334.             walk the tree.  As mentioned earlier, I have done a test to see if
  1335.             anyone will have problems, and I really don't foresee any.
  1336.         
  1337.             One area which may prove slow if a data file becomes very large is
  1338.             that of finding an unused record.  Since I want to reuse holes in
  1339.             the file prior to expanding the file I do a linear search to find
  1340.             holes.  I walk through the bitmap looking for a logical record
  1341.             marked unused.  I do the same for index files looking for unused
  1342.             physical records.  On a large file this takes a little time.  I
  1343.             may add the capability to make reuse optional.  In other rwords
  1344.             the user can turn it on and off.  Feedback in this area is
  1345.             appreciated.  So far, I have not received any negative feedback on
  1346.             this.
  1347.         
  1348.             The biggest change that I will probably implement in the future is
  1349.             a unit which traps errors and sets an error flag.
  1350.         
  1351.                                 Version Release Notes
  1352.         
  1353.         Version 1.1
  1354.         
  1355.         1.  Added capability to do a search of an index on a range of values.
  1356.         
  1357.         2.  Added capability to do partial string match searches (strings
  1358.         only).  Added one routine to the BTREE unit and several routines to
  1359.         the COMPARE unit and one type declaration to the NUMBERS unit to
  1360.         facilitate this change.
  1361.         
  1362.         3.  Corrected bug in BTREE unit.  Documentation stated that duplicate
  1363.         entries for a given logical record number and field value were
  1364.         prevented from being entered.  This was not previously the case
  1365.         although that is now true.
  1366.         
  1367.         4.  Added a routine (LOGICAL unit) to build a list of all current
  1368.         records for a file (all valid ie not deleted records).  This is
  1369.         essential for rebuilding indexes or accessing data without an index.
  1370.         In actuality, a user could have built this routine, but it was not
  1371.         intuitively obvious.
  1372.         
  1373.         5.  Added the capability to delete an entry from an existing logical
  1374.         record list.
  1375.         
  1376.         6.  Divided BTREE.PAS into BTREE.PAS and two include files :
  1377.         BTREE1.INC and BTREE2.INC.
  1378.         
  1379.         7.  Added several more examples.
  1380.         
  1381.         Version 1.2
  1382.         
  1383.         
  1384.                                         21
  1385.         
  1386.         
  1387.         
  1388.            TBTREE13             Copyright (c)  1988   Dean H. Farwell II
  1389.         
  1390.         
  1391.         1.  Added Sorting capabilities.
  1392.         
  1393.         2.  Added several routines to LRECLIST.PAS to facilitate sorting.  I
  1394.         also made a couple of internal cosmetic changes to LRECLIST.PAS.
  1395.         
  1396.         3.  Added one example.
  1397.         
  1398.         4.  Removed CalculateRecordSize and several unused data types from
  1399.         LOGICAL.PAS.  These were for future projects and now are now targeted
  1400.         for TBASE.
  1401.         
  1402.         Version 1.3
  1403.         
  1404.         1.  Added SETOPS.PAS which provides Intersection, Union and
  1405.         Difference.
  1406.         
  1407.         2.  Added one example.
  1408.         
  1409.         3.  MATH.PAS redone in assemble language.  See listing for details and
  1410.         credit to the author.
  1411.         
  1412.         4.  Added one routine (FindLrInList) to LRECLIST.PAS.
  1413.         
  1414.         5.  In LOGICAL.PAS changed MAXDATASIZE to 65520 since this is the
  1415.         maximum size for a structured type in Turbo Pascal 4.0.
  1416.         
  1417.         6.  TP4PRINT.PAS now prints the file creation date as part of the
  1418.         header.
  1419.         
  1420.         7.  Added NumberOfBTreeLevels routine to the BTREE unit.
  1421.         
  1422.         8.  Added StoreNewLogicalRecord routine to LOGICAL.PAS.  This makes it
  1423.             easier to store new records.  You no longer need to find the next
  1424.             available logical record number using the FirstUnUsedRecord
  1425.             routine located in FILES.PAS.  StoreNewLogicalRecord does this for
  1426.             you and returns the associated logical record number.
  1427.         
  1428.         
  1429.         
  1430.         Turbo Pascal is a registered trademard of Borland International
  1431.         CompuServe is a registered trademark of CompuServe Incorporated
  1432.         
  1433.         
  1434.         
  1435.         
  1436.         
  1437.         
  1438.         
  1439.         
  1440.         
  1441.         
  1442.         
  1443.         
  1444.         
  1445.         
  1446.         
  1447.         
  1448.         
  1449.         
  1450.                                         22
  1451.         
  1452.         
  1453.