home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-07-15 | 77.9 KB | 1,501 lines |
- @PO 1
- @MT 4
- @HM 1
- @HE TBTREE16 Copyright (c) 1988,1989 Dean H. Farwell II
- @MB 4
- @FM 2
- @PC 40
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- TBTREE16
-
- ( Turbo BTree version 1.6 )
-
-
-
- Yet another implementation of BTrees for Turbo Pascal 4.0/5.0/5.5
-
-
- Copyright (c) 1988,1989 Dean H. Farwell II
-
-
-
- All source code and documentation are considered to be shareware and are
- copyrighted. The following rules of engagement apply to all documentation and
- code which make up TBTREE16:
-
- All users can and are encouraged to distribute this software freely. This
- includes the uploading of this software onto applicable Bulletin Boards etc.
- The entire TBTREE16 product must be distributed as a complete product. Pieces
- can not be distributed individually. The documentation must be distributed
- with the source code. No copyright statements may be modified.
-
- All users can and are encouraged to use these utilities to develop and/or
- enhance their private, shareware, or commercial software applications.
-
- All users are encouraged to suggest enhancements, make suggestions and
- generally lead to the development of a better product to the benefit of all.
- Users may change the code and documentation as desired for their own use but
- may not then distribute those changes.
-
- Users may distribute these routines as part of another SHAREWARE package. For
- instance, a user could develop a DBMS using this as a basis and can freely
- distribute the source code provided that:
-
- 1. None of this documentation or code is changed
- 2. ALL code and documentation is distributed (not just parts)
- 3. The user is not selling or distributing this for profit
- 4. The user be registered.
-
- The restriction that the code and documentation not be changed is to ensure
- that I can maintain some control over version releases. I do not want several
- versions running around that I had nothing to do with.
-
- The bottom line is that you can not sell this or distribute it for profit
- (except for a small fee not to exceed $10 to cover cost of mailing,
- duplication and handling). A user developing a commercial application can not
- distribute the SOURCE code or documentation but a user can use these routines
- to compile a commercial application.
-
- Users are encouraged to register their copy of this software. The
- registration fee is a very nominal $25. You may be aware that this is an
- increase in my earlier $15 fee. The justification I use is that the product
- has greatly matured and I honestly believe that you are getting a good bang
- for the buck. Also, for the $25 you will get all future upgrades mailed FREE.
- I am no longer charging a $5 shipping and handling fee for each upgrade.
-
- Anyone using this software to develop a commercial application must register
- and state their intentions to use it in a commercial application. I will not
- charge royalties (except for the registration fee). I just want to know what
- people are doing with it. Also, if someone is distributing it as part of a
- shareware product, the same restrictions apply.
-
- Most of all I want any feedback that you have the time and desire to submit.
- Suggestions, complaints, etc. are welcome. I especially want feedback on
- errors. I do not know of any bugs (or I'd fix them) but I probably missed an
- item or two. Send me notice immediately so that I can distribute a fix if
- required. Since you have the source code, do your best to isolate the
- problem. I'll try to take it from there.
-
- To reach me use CompuServe ID - 73240,3335 or drop me a line at:
-
- P.O. Box 4731
- San Bernardino, CA 92409
-
- (zip code is essential!!!!!)
-
- My phone number is:
-
- 714-887-9847
-
- For hopefully obvious reasons, I will not accept collect calls. Otherwise,
- feel free to call as I enjoy hearing from users.
-
- As a final motivation to register, all registered users will receive future
- upgrades free (via mail - no postage due or anything!). I will normally mail
- these well before I put the version out on CompuServe or anywhere else. The
- registered users will, in effect, become beta testers to make sure that all is
- well before I release to the world. By registering you will ensure that you
- always have the latest version and is probably less than the cost to download
- off of a bulletin board. I will do my best to not release trivial changes but
- only significant upgrades.
-
- Liability:
-
- This software is not warranted. There are no warranties expressed or implied
- as to the quality, correctness, or applicability of this software. The author
- is not responsible for any loss or damages due to the use of any software or
- documentation distributed as TBTREE16.
- @PA
- Product Description
-
- TBTREE16 is version 1.6 of a shareware btree and database product for use with
- Turbo Pascal 4.0, Turbo Pascal 5.0 and Turbo Pascal 5.5. It is intended to
- give a user the capabilities to develop pascal applications for the creation
- and manipulation of databases. This product is extremely powerful and FAST!!!
- However, it is not the easiest thing to get a grasp on. If you understand the
- concept of btrees or at least indexing then this will not be complicated to
- use. I can just about guarantee that it is the best product of its type for
- the money and maybe the best period. If you have any feedback on how I can
- take the mystery out of using this please let me know. I also solicit any
- feedback which will enhance the quality of the product.
-
- I am presently working on a second product (albeit at a much more leisurely
- pace than I had anticipated) which will be called TBASE and will use these
- routines as the database engine but will have a much easier to understand
- interface for code developers. It will use SQL like calls instead of those
- used in this product. All registered users of TBTREE16 will be shipped a beta
- version of TBASE as soon as one becomes available and will get the first whack
- at using it. This in itself is worth the $25.
-
- Although this product provides many of the same general database capabilities
- as Borland's Turbo Pascal Database Toolbox it is not intended to be
- compatible. There are several reasons for this. First, I do not want to
- create any impression of any type of copyright infringement. Secondly, I
- needed to implement things differently than they were implemented in Borland's
- product to be able to do the enhancements I am planning. Thirdly, I wanted to
- implement things that Borland does not. For instance, I support data types in
- my indexes. Other differences will be more apparent as you read through this
- documentation. Lastly, I did not have a copy of Borland's product when I was
- doing this. This really started out as more of an academic exercise than
- something that I was going to release for others. This turned out to be a
- more extensive job than I thought (big surprise there, huh?). I figured that
- I might as well make it available for others.
-
- This product has been greatly enhanced since version 1.0 was released. As it
- presently stands, it has the following features:
-
- 1. The ability to create data files and indexes for those files.
-
- 2. Any number of indexes can be used for a single data file.
-
- 3. Any number of data files can be used.
-
- 4. All data files and index files use a virtual memory scheme in which the
- most recently used pages are kept in memory using the heap. This is
- different than many other implementations which use a buffer or stack only
- for index pages. The buffer is shared by all files. In this way separate
- space does not need to be set aside for different files. Space utilization
- is maximized and performance is enhanced.
-
- 5. All management of pages in memory is automatically controlled although the
- user can exercise limited control if desired.
-
- 6. Routines are provided to dump the page buffer to the printer to facilitate
- viewing pages if a user is curious or masochistic.
-
- 7. The size of the buffer is determined by the user and can be changed
- dynamically as the program runs. For example a 128K buffer could be used
- initially. If a user had a large heap requirement the buffer size could be
- reduced. The buffer size could later be increased if desired. This can
- all be done while the application is running.
-
- 8. Problems related to keeping track of numbers of open files are alleviated.
- The user initially specifies the maximum number of files allowed to be open
- at once and never has to address it again. Routines are provided to manage
- the opening and closing of files dynamically. This increases performance
- because files do not have to be continually opened and closed
- unnecessarily.
-
- 9. All data types supported by Turbo Pascal are explicitly supported. In other
- words, values do not have to be converted to strings. This is a great
- improvement over previous systems (MY UNBIASED OPINION). For example an
- index can be set up for type Byte, another for type ShortInt, another of
- type String and even for type Real (but wait you say .. Reals in an
- index?). See next note!
-
- 10. Indexes can be searched for equality, inequality, greater than, greater
- than or equal to, less than, less than or equal to, and existence. In
- other words you can ask for a list of all records for which some field of
- type real is LE (less than or equal to) XXX where XXX is a var of type
- real and XXX := 3.141592 etc. An index can also searched on a range of
- values. For instance an index of type byte can be checked for a range >=
- 10 and < 20 etc. Indexes containing strings can be searched for partial
- string matches. Partial string matches can be done three ways: find a
- string which is at the beginning of a string, anywhere in the string, or
- at the end of a string.
-
- 11. As physical records are deleted space is reused automatically on future
- inserts. Files should never have to be reorganized to recover space
- (unless a large number of deletes were performed without any inserts and
- even in this case there is not really a good reason to reorganize unless
- your disk is filling up).
-
- 12. Included with the package is a very crude but effective source code
- printing routine which can be used to dump the code in a more usable
- format. Specifically, it handles page breaks and prints a header of
- useful information. It will also only print out the interface section if
- you instruct it to do so.
-
- 13. The user does not need to perform any calculations or make any estimates
- prior to data file or index creation.
-
- 14. Code was designed using an Object Oriented Design approach to a large
- extent (Turbo 4.0 and Turbo 5.0 lend themselves to this approach much
- more than Turbo Pascal 3.0 did). This is one reason that there are so
- many units. Much of the code is reusable for other applications.
-
- 15. Sorts can be accomplished using any number of fields in any order of
- precedence as determined by you. A Quicksort algorithm is used to give
- high performance. Sort fields can be any type supported (Byte, Real,
- Integer, String etc.).
-
- 16. Added the following set operations: Union, Intersection and Difference.
- These allow easy queries on multiple fields. For example, retrieving all
- personnel who have a last name starting with 'N' and who's job is
- 'MANAGER', etc. is greatly simplified. This enhancement is a definite
- plus and not available in many other products.
-
- 17. Error handling added for trapping I/O errors
-
- 18. Capability to handle files with fixed size records and files with
- variable sized records
-
- List Of Files
-
- The following files are provided as part of the TBTREE16 product:
-
- Units - Source Code For All Units
-
- BTREE.PAS - This unit contains the interface and implementation for
- the btrees themselves. Although the implementation is fairly
- complex, only a few routines are visible to the user and give the
- user all the functionality required. The actual working of the
- btree unit itself is not critical to the user. The user is provided
- with routines to add an entry to an index, delete one entry from an
- index, delete all entries with a matching key value from an index
- and retrieve record numbers which match some selection criterion.
- The ability to create an index is also provided. To delete an index
- just delete the file using a routine provided in BTREE.PAS. The
- BTREE unit is different than any other unit in the product in that
- it consists of not one but four source files. See entry for
- BTREE1.INC, BTREE2.INC and BTREE3.INC.
-
- BTREE1.INC, BTREE2.INC and BTREE3.INC - These are additional source
- files needed for the BTREE unit. I split up the source code for the
- unit because the source code ended up greater than 64K bytes. The
- three additional files are include files and will automatically be
- compiled when BTREE.PAS is compiled.
-
- BYTEDATA.PAS - This unit was added to version 1.4 for use with a
- future product. It can be used to create concatenated indexes,
- although I am still working on the specifics.
-
- COMPARE.PAS - This unit contains no inherent object although a
- couple of types are declared and put in the interface. It is made
- of several routines which give the capability of comparing two
- values of the same type or searching for a substring within a
- string. This routine alleviates the need for the user to develop a
- routine which can be used for comparisons. All Turbo Pascal 4.0
- scaler types are handled. Strings and ByteArrays are the only
- structured (composite) types handled. Several routines are used to
- handle partial string searches.
-
- FILEBUFF.PAS - This unit contains the interface and implementation
- for a files open list. This list will contain information on all
- files opened (using this unit). A user can specify how many files
- can be on the list at once (how many the unit can allow to be open).
- The unit takes it from there. From then on all requests to use a
- file must be preceded by a call to the unit. The unit will
- determine if the file is open and will open it if it is not. The
- routine is exceptionally useful for alleviating the need to open and
- close files for every operation. Continually opening and closing
- files causes unacceptable performance problems. The file types
- handled are only Untyped files and Text files. Typed files are not
- currently handled. This is due to the fact that strong type
- checking precludes the use of typed files (or at least I couldn't
- break the code and figure out how to make it work. If anyone can
- figure out how to make it work, it would make this even more
- useful).
-
- FILEDECS.PAS - This unit is nothing more than a collection of
- declarations required to support several of the other units. There
- is no code in the implementation section.
-
- FILES.PAS - This unit contains the interface and implementation for
- the manipulation of files. This fulfills the role of file manager
- (mid level management of files as opposed to the low level
- management found in FILEBUFF.PAS). It is the place where files are
- created, deleted and where the existence of a file is checked. Most
- of the routines are for internal use only. There are several
- exceptions, however. See the unit documentation for details.
-
- HEX.PAS - This unit contains the interface and implementation for
- dealing with a hex array which is a 2 byte array used for storing a
- hex character (such as 7F). A couple of routines are provided for
- converting bytes and bits to hex array representations. It is
- intended for internal use, but may prove useful for your specific
- application, as well.
-
- LOGICAL.PAS - This unit contains the interface and implementation
- for dealing with logical (data) files and records. It also handles
- the conversion between logical and physical records. In TBTREE16
- all physical records (records stored on disk) are the same size (512
- bytes). This is how all files can share the same page buffer (See
- PAGE.PAS). However, the logical records (data records in the data
- files) can be any size from one byte up to 65520 (although they will
- not be that large in practice). This unit takes the user's data
- records stored in a variable and puts them in the number of physical
- records required. It also takes the appropriate data from physical
- record(s) and puts it in the variable of the users choice. A great
- deal of flexibility is available here. One caution however!
- This unit only handles FIXED LENGTH LOGICAL RECORDS. All data
- records (within one data file) must be of the same size (obviously
- each data file can have a different logical record size). If
- variable length data is required then the size of the logical record
- is the largest number of bytes required as determined by the user.
- A good example of this is a record containing a string declared as
- String[20]. The logical record size is 21 bytes (one byte for the
- length). 21 bytes should be stored and retrieved even though a
- string such as 'howdy' is stored (howdy uses 6 bytes). Most products
- of this nature work in the same way. This unit handles the creation
- and deletion of data files as well. See unit for details. See also
- the VLOGICAL unit information below. VLOGICAL is the other unit
- which handles data records. It is an alternative to this unit and
- is designed specifically for records of varying size.
-
- LRECLIST.PAS - This unit contains the interface and implementation
- to handle logical record lists. A logical record list is a concept
- which is different than you will find in most other implementations
- of btrees. When a query is done on an index, most btrees set a
- cursor to the node where the first matching value is found
- (equality). This is very efficient but does not lead to the
- flexibility of my system. TBTREE16 builds a list of logical record
- numbers corresponding to the logical records which meet the criteria
- of the query. TBTREE16 can handle all boolean operations such as
- equality, inequality, greater than, greater than or equal to, etc.
- Therefore, you can get a list of all logical records which meet some
- criteria and deal with that list independently of the btree. Once
- you have the list you can compare it to other lists and do
- intersections, unions, joins, etc. This gives you some of the power
- of a real database management system. You can relate a file to
- itself or to other files. This system is the basis of my future
- work to bring true relational capabilities to programs written in
- Turbo Pascal. It gives the capability to do set at a time
- processing. Unfortunately, nothing is free. A query on a database
- of 10000 logical records on existence will give a list of 10000
- logical records numbers (40000 bytes required to store the list).
- Lists like this take time to build. A fact of life is that it takes
- time to process a lot of data in a large database. The user is
- cautioned to structure queries in such a way that lists are not
- huge. Queries on equality are not normally a problem (unless the
- index provides little selectivity). Queries on inequality will be
- faster if a range is used. No matter what type of query is used,
- the page buffer alleviates a great deal of performance problems. An
- alternative to using these logical record lists can be found in
- BTREE3.INC.
-
- MATH.PAS - This unit contains the interface and implementation to
- manipulate bytes at the bit level. Only two routines are visible as
- that is all that is required in TBTREE16. This unit has been redone
- in assembly language to enhance performance. See the source listing
- for further details.
-
- MYPRINT.PAS - This routine is a collection of printer codes and
- routines to print the codes. This is sufficient for my purposes and
- is included only because I needed a couple of routines for
- TP4PRINT.PAS and PAGE.PAS. This unit is not very elegant and will
- need to be modified if it does not support your printer.
-
- NUMBERS.PAS - This unit contains no code in the implementation. It
- is simply a repository for often used types which are not part of
- the original Turbo Pascal product.
-
- PAGE.PAS - This unit contains the interface and implementation to
- manipulate the page buffer. The page buffer is stored internally
- on the heap and is used to temporarily hold physical records. The
- buffer greatly enhances up the performance of the product. As the
- program runs, physical records are created or are read in from disk.
- As this happens, they are stored in the buffer. Therefore, the
- buffer grows and shrinks as the demand for pages grows. You can set
- the maximum size of the buffer. By doing this, you can ensure that
- the buffer does not eat up all of the heap and leave nothing for you
- own needs. To function the buffer can be set to as small as one
- page (512 bytes). However, performance is going to be dismal. The
- amount of buffer space to allocate is dependent on many factors and
- the size needs to be played with to see what works best. One rule
- stands though .. bigger is better! One interesting note - routines
- are provided to change the size (both increase and decrease)
- dynamically as often as desired. There are other routines available
- as well. For example, a routine is provided to allow the user to
- force a page to be written to disk immediately when it is changed
- (stored in the buffer) as opposed to waiting until it gets swapped
- out or all pages are written to disk. Immediately writing to disk
- ensures that nothing gets lost on a system or program crash but it
- has severe performance implications. Use of this is not normally
- required, but the option is there and usable.
-
- SETOPS.PAS - This unit contains routines that support set
- operations. They facilitate queries using multiple fields from one
- data file. This greatly reduces the workload on the programmer.
-
- SORT.PAS - This unit contains three procedures for sorting. This
- unit was was created in version 1.2 and completely reworked in
- version 1.5. It uses a quicksort algorithm to provide good
- performance. Just as importantly, it supports all data types
- supported by TBTREE16 and is extremely easy to use.
-
- STRINGS.PAS - This unit contains routines to manipulate strings.
- They are for internal use, but may prove useful for your specific
- applications, as well.
-
- TIME.PAS - This unit contains the implementation and interface to
- manipulate a time counter which will keep track of a sequence of
- events. It is really intended for internal use only, although you
- can use it if you find a need.
-
- VLOGICAL.PAS - This unit is much the same as the LOGICAL unit except
- that it is designed to handle variable length record files. In
- other words, each record can have a different number of bytes
- associated with it.
-
- Programs - Source Code For All Programs
-
- TP4PRINT.PAS - This program is provided merely to permit my source
- code to be printed out in a better format than provided by the DOS
- Print command. It looks for page control codes embedded in my
- source (my control codes are comments to the compiler) and controls
- paging. It puts a header which includes file name, page, print time
- and file creation time. It provides top and bottom margins as well.
- Give it a try by printing out one of the source code files to see if
- you want to use it or another source code printer. Syntax is :
-
- TP4PRINT filename where filename includes path if source is
- not in the current directory
-
- After the file name, a an optional parameter can be used. Only a
- small i or capital I will be recognized. If this is present, only
- the opening comments and the entire interface section will be
- printed. The implementation section will not be printed. This
- allows you to look at what you need without printing out everything.
- An example of this follows:
-
- TP4Print logical.pas I
-
-
- IFACE.BAT - A batch file which will print out the comments and
- interface section of every unit in TBTREE16. This is the easiest
- way to print out what you need from the code without printing out
- stuff you probably don't need (implementation sections). One word
- of warning though, over 80 pages will be printed. Of course, you
- can go in an modify the batch file to only print the ones you want.
-
- BUILDTPU.PAS - When this program is compiled, all units associated
- with TBTREE16 will also be compiled. This simply provides a
- convenient way to build all the units at once without compiling them
- individually.
-
- EXAM0.PAS - This is really a unit that is used a global section for
- the other examples. It contains the record declaration for the test
- record used for all examples.
-
- EXAM1.PAS thru EXAM3.PAS and EXAM5.PAS thru EXAM11.PAS
- demonstrate the capabilities of TBTREE16 to handle fixed
- length data records
-
- EXAM4.PAS has nothing to do with data records and is
- explained below
-
- EXAM51.PAS thru EXAM54.PAS demonstrate the capabilities of
- TBTREE16 to handle variable length records
-
- EXAM1.PAS - This example program demonstrates how to create a data
- file and a couple of indexes. It then demonstrates how to insert
- data into the data file and the indexes. Several other routines are
- demonstrated as well. Important to note is that this program has
- been changed from version 1.2 and prior. It now uses
- StoreNewLogicalRecord to store the record as opposed to using
- StoreALocicalRecord. Look at the source and this may make sense.
-
- EXAM2.PAS - This program shows how to perform retrievals using both
- the logical record lists and the internal cursor. The files created
- in EXAM1.PAS are used.
-
- EXAM3.PAS - This program shows how to do deletes and updates. The
- files created in EXAM1.PAS are used.
-
- EXAM4.PAS - This program shows how to use routines in FILEBUFF.PAS
- with text files.
-
- EXAM5.PAS - This program shows how to use the retrieval on range
- routine. The files created in EXAM1.PAS are used.
-
- EXAM6.PAS - This program shows how to use the retrieval on partial
- string match routine. The files created in EXAM1.PAS are used.
-
- EXAM7.PAS - This program shows how to build/rebuild indexes from an
- existing data file. The files created in EXAM1.PAS are used.
-
- EXAM8.PAS - This program shows use of routines to delete entries
- from a logical records list. The files created in EXAM1.PAS are
- used.
-
- EXAM9.PAS - This program shows an example of sorting using the SORT
- unit. The files created in EXAM1.PAS are used.
-
- EXAM10.PAS - This program shows an example of using one of the set
- operations found in the SETOPS unit. The files created in EXAM1.PAS
- are used.
-
- EXAM11.PAS - This program shows an example of the use of the
- internal cursor. Of note is the fact that the cursor keeps track of
- its position in the index even after inserts and deletes have been
- done in the index. The files created in EXAM1.PAS are used.
-
- EXAM51.PAS - This routine is the direct counterpart to EXAM1.PAS
- except that it creates variable length records.
-
- EXAM52.PAS - This shows how to do retrievals using the variable
- length records. Notice that the use of indexes is the same as in
- EXAM2.PAS. I did not use the cursor in this example, but they work
- the same as in EXAM2.PAS.
-
- EXAM53.PAS - This is an example of doing a delete using variable
- length records. Notice that it is not really very fast. I am
- working on improving the speed of deletes for variable length
- records.
-
- EXAM54.PAS - This is a direct counterpart to EXAM9.PAS except that
- it sorts variable length records.
- @PA
- Instructions For Use of TBTREE16
-
- The only way to truly understand how TBTREE works is to look through the
- Interface sections of the various units. As noted above, I have supplied a
- batch file which can be used to print all of the Interface sections at once.
- The first two units to try to figure out are the LOGICAL unit and the BTREE
- unit. These really are the heart of TBTREE16. Then look over the PAGE unit
- (concentrate on the few routines which are used to set parameters such as
- buffer size etc. Also try to understand the buffer and why it is important to
- TBTREE16. Then glance over the FILEDECS unit. You will need to use a couple of the
- routines in the FILEBUFF unit as well. Once you grasp these units, you are
- well on your way to understanding TBTREE16. The following provides a short
- set of instructions for performing the more common database type operations
- using TBTREE16. The Quick Reference guide, which is provided in a separate
- file, will also prove helpful.
-
- Uses Statements - All of the units were compiled with the appropriate
- uses statement included. Therefore, the user does not need to be
- concerned about order when specifying units in the uses statements in the
- user's programs. As you can see in my examples, I put the units in
- alphabetical order. The user only needs to put the units which have
- type statements and/or routine calls which must be visible within the
- user's program. My example programs demonstrate which ones are probably
- required. One method which actually works is to not include any
- initially and let the compiler find the syntax errors. When an error is
- found because a type or routine is not found then see which unit it's in
- and put that unit in the uses statement. It's not a great way to do it,
- but it works.
-
- Setting Initial Parameters - Several parameters should be set by the user
- although they have defaults if a value is not set by the user. All of
- the parameters are only accessible by calling routines supplied to check
- and set values. The variables themselves are not global, so they are not
- visible to the user. The following parameters can be set by the user:
-
- Open Files Allowed - Contained in FILEBUFF.PAS. Determines number
- of open files allowed exclusively for use within TBTREE16. TBTREE16
- will never have more that this number of files open at a time.
- However, if TBTREE16 needs to deal with more files than this, it
- will open and close its files and function properly. See
- FILEBUFF.PAS for details. To set the parameter to a value of 5 do
- the following:
-
- SetMaxOpenFiles(5);
-
- Maximum Buffer Pages Allowed - Contained in PAGE.PAS. Determines
- the maximum number of 512 byte pages to keep in memory at one time.
- Set this to something that makes sense for your machine (memory size
- available). Since this is set at run time, you can set this after
- you determine how much memory is available. You can reset this at
- any time to a higher or lower value, and it will handle it properly.
- To set this parameter to 50 pages (25K bytes) use the following:
-
- SetMaxBufferPages(50);
-
- One note is that the buffer is initialized to 128K bytes which may
- be too large for your application. You should reset the default to
- whatever you want.
-
- Immediate Disk Write - This parameter if set to TRUE will force a
- write of a page to disk immediately after it is stored in the page
- buffer. Otherwise, the page will only be written when it gets
- swapped out or is explicitly forced out by the user (all pages for a
- file or all pages). To set this value to TRUE use:
-
- SetImmediateDiskWrite(TRUE);
-
- Creating Data Files - One of the first things we would want to do is
- create data files to hold our data. This is extremely simple. We only
- need to make one call for each data file. The following statements would
- create a data file with fixed length records (LOGICAL unit). Using the
- VLOGICAL unit is very similar.
-
- type
- MyRecord = record
- field1 : Byte; (* for this example this
- is the only field
- indexed (Index1) although
- you could index all fields
- if desired. *)
- field2 : Word;
- field3 : String[10];
- end;
-
- var
- xxx : FnString; (* holds name of data file *)
-
- begin
- xxx := 'MYFILE'; (* name of file *)
- CreateDataFile(xxx,SizeOf(MyRecord)); (* create the file *)
- end;
-
- Notice that the xxx is not a file type but an 80 character string type
- which holds the name of the file including path (if desired).
-
- Creating Index Files - The next step is to create one or more index files
- for each data file. You will not normally have a data file with no
- indexes (although for small files, you may want to). To create an index
- file the user must know the type and size of the key (item to be stored
- in the index). The following statements will create an index file for
- the data file created above. The index will hold Byte values (values
- from 0 - 255).
-
- var
- yyy : FnString;
-
- begin
- yyy := 'Index1';
- CreateIndexFile(yyy,SizeOf(Byte),BYTEVALUE);
- end;
-
- Notice use of the SizeOf routine to pass in the size of the item to be
- stored in the index. This is usually more accurate than passing in a
- constant value. This will especially help avoid errors when using
- strings. Remember, strings use one extra byte for the length.
-
- Inserting Data - Once files and indexes exist we can insert data.
- Inserting data consists of two separate steps. The first step is to
- insert the data into the data file. The second step is to insert the
- applicable data into each index which is associated with that data file.
- To insert data we first need to have the data record stored in memory
- somewhere. The most logical place to have the data record is in a
- variable which is of type record of some kind. For example, the
- declaration of a data record (MyRecord) as defined above will suffice.
-
- var
- thisRec : MyRecord;
- lrNum : LrNumber;
-
- We could use the following sequence to insert a record in the data file
- and the index associated with this data file:
-
- thisRec.field1 := 20;
- thisRec.field2 := 60000;
- thisRec.field3 := 'Hi Mom';
-
- lrNum := StoreNewLogicalRecord(xxx,thisRec);
-
- InsertValueInBTree(yyy,lrNum,thisRec.field1);
-
- Notice that StoreNewLogicalRecord was used because it will find an unused
- logical record number and assign it to this new record. This logical
- record number is the one inserted (along with the associated value) into
- the BTree. This is a change from versions prior to version 1.3. This
- simplifies things and makes storing much more straightforward. Hopefully,
- it is obvious that data records are not stored sequentially or in any
- other ordered manner. In other words, there is not a relationship
- between logical record 1 and logical record 2. To ensure order, you can
- either retrieve using the indexes or create a logical record list and
- sort it.
-
- Retrieving Data - Retrieving consists of getting the data for one or more
- logical records from a data file. To determine which logical records are
- needed, one or more indexes are normally used. TBTREE supports two
- different methods for performing a retrieval using an index. The first
- and most powerful is to build a logical record list and the traverse that
- list. Routines to do the retrieval are found in the file BTREE2.INC
- (part of the BTREE unit). The routines to traverse the list are found in
- the FILEBUFF unit. The second method is to use a cursor which is built
- into each index. This method is more traditional and has the advantage of
- being dynamic but is not as powerful/flexible. Saying that the second
- method is dynamic refers to the fact that as index entries are inserted
- and deleted, the cursor continues to point to the same entry, unless that
- entry is deleted. The routines to support this type of retrieval are
- found in the BTREE3.INC file. Both methods are discussed further below:
-
- Method 1 - Using the logical record lists - Retrieving data consists of
- making a query to an index. The query is a procedure call which will
- build and return a list of logical records which match the selection
- criteria. The query conditions are defined in NUMBERS.PAS and are of
- type Condition. Once the list is retrieved, the user can step through the
- list starting at either end and going in either direction. The logical
- record numbers are stored in the index in such a way that their
- corresponding key values (values in the index) are in ascending order. A
- logical record list created using an index will reflect this order. If
- there are multiple occurrences of the same key then the last one added is
- in the front. The list can be traversed front to back (ascending) or
- back to front (descending). A cursor is kept internally in the list (not
- to be confused with the cursor used in the other method) to keep track of
- where the user is in the list. The user can not get to the cursor but
- can set it to the front or back and move it forward or backward (by
- retrieving values from the list). Normally, to traverse the list, set
- the cursor to the front of the list and then set up a loop which will
- traverse the list and terminate when a logical record number of 0 is
- returned. The list is not disturbed as you move through it. It will
- exist until you destroy it or until the program ends. If the program ends
- before the list is destroyed explicitly by the user then there may or may
- not be a file on disk with an extension of '.lrl'. If you terminate and
- find any of this type of file laying around then you did not destroy it
- prior to ending the program (shame on you). You should fix this since
- leaving a list hanging around just takes up space and does nothing
- productive. If you find files with this extension ('lrl') hanging around
- after your program terminates, you can delete them. An example of a data
- retrieval follows:
-
- var
- key : Byte;
- lrLst : LrList;
- lrNum : LRNumber;
-
- begin
- key := 20;
- GetValuesFromBTree(yyy,key,LE,lrLst); (* retrieve all record
- numbers for records
- having an index entry less
- than or equal to 20. *)
-
- (* lrLst is the newly created list *)
- lrNum := GetFirstLr(lrLst); (* set cursor to front *)
- while lrNum <> 0 do (* traversal loop *)
- begin
- GetALogicalRecord(xxx,lrNum,thisRec,);
- (* we can do whatever with the record *)
- .
- .
- .
- lrNum := GetNextLr(lrLst);
- end; (* this will continue until end of list *)
-
- You can also do a retrieval for a range of values or retrieve records on
- a partial string match. An example of each follows:
-
- var
- key1,
- key2 : Byte;
- lrLst : LrList;
- lrNum : LRNumber;
-
- begin
- key1 := 10;
- key2 := 75;
- GetRangeFromBTree(yyy,key1,GE,key2,LE,lrLst);
- (* build list of logical
- record numbers which
- are between 10 and 75 *)
-
- (* list is in lrLst *)
- lrNum := GetFirstLr(lrLst);
- while lrNum <> 0 do
- begin
- GetALogicalRecord(xxx,lrNum,thisRec,);
- (* we can now print the record or look at it or whatever it is
- that you would want to do with it *)
- .
- .
- .
- lrNum := GetNextLr(lrLst);
- end; (* this will continue until end of list *)
-
- One note about the above example is in order. The first Condition must
- be either GE or GT and the second Condition must be LE or LT. If they
- are reversed, the retrieval will not work properly. Also, one of the
- conditions can not be NE or EQ or EX. This should make sense and is not
- really a restriction. This routine is designed to handle ranges, not all
- query types. If you have a query such as LE 10 and EQ 88 then you must
- do two queries and perform an Intersection. See the SETOPS unit for
- details.
-
- ------------------------------
-
- var
- keyString : String[10];
- lrLst : LrList;
- lrNum : LRNumber;
-
- begin
- keyString := 'C';
- (* assume zzz is an index holding values of type STRINGVALUE *)
- GetSubstringFromBTree(zzz,keyString,ST,lrLst);
- (* build list of logical
- record which start with
- 'C' *)
- (* list is in lrLst *)
- lrNum := GetFirstLr(lrLst);
- while lrNum <> 0 do
- begin
- GetALogicalRecord(xxx,lrNum,thisRec,);
- (* we can do whatever with the record *)
- .
- .
- .
- lrNum := GetNextLr(lrLst);
- end; (* this will continue until end of list *)
-
-
- Method 2 - Using the cursor internal to the index - Each index contains
- one internal cursor. The cursor can be set to the beginning or the end
- of the index. It can also be set to a specific place in the index (first
- occurrence of a value). Once the cursor is in place, it can be moved in
- either direction retrieving logical record numbers along the way.
- Although it is not nearly as powerful as the logical record list
- approach, it has the advantage of simplicity as well the fact that the
- cursor stays valid even after inserts and deletes are performed on the
- index. Rather than presenting the expanded discussion here, refer to the
- BTREE3.INC file.
-
- Retrieving Data Records - As noted in the examples above, once the
- logical record number for the desired logical record is determined, use
- the GetALogicalRecord routine found in the LOGICAL unit to perform the
- retrieval. It should be noted that you do not need to use and index to
- retrieve a data record. You can retrieve all records by building a
- logical record list of all valid record number. Use the
- GetValidLogicalRecords routine for this.
-
- Deleting Data - Deleting data is the inverse of inserting data. There
- are three steps involved. The first step is to retrieve the record.
- This is only required if you do not know the values for all fields which
- have a corresponding index. Once we have the record we can delete the
- entries from the index(es). The last step is to delete the logical
- record from the data file. For the following example assume that the
- same definitions used above apply but that field2 also has an index with
- the file name residing in a variable zzz. Also assume that we know that
- we want to delete logical record number 24:
-
- GetALogicalRecord(xxx,24,thisRec);
-
- DeleteValueFromBTree(yyy,24,thisRec.field1);
- DeleteValueFromBTree(zzz,24,thisRec.field2);
-
- DeleteDataRecord(xxx,24); (* delete value from data record *)
-
- Updating Data - There are no separate commands to update data. Updating
- is a two step process. The first step is to fetch the appropriate data
- record(s). Once this is accomplished, the appropriate fields can be
- updated and the data file can be stored. A third step may be required.
- If any indexed fields (fields which have an index associated with them)
- are changed then the old value will have to be deleted and then the new
- value will have to be inserted into the index. Rather than show an
- example here, I refer you to EXAMPLE3.PAS. You may notice that in that
- example, I store the updated data record after updating the index rather
- than before. The order of these two operations is not important.
-
- Deleting Files - The operation of deleting a file is not going to be done
- very often but will be necessary from time to time. The following is an
- example:
-
- DeleteDataFile(xxx);
- DeleteIndexFile(yyy);
-
- Notice that there is a separate routine for data and index files. Also,
- deleting a data file will not automatically delete the associated index
- files. You must do this explicitly as appropriate.
-
- Sorting - Sorting can be done on any number of fields as you desire.
- Sorting requires two steps. The first is to build a sort field list, a
- list containing information on each of the fields to sort on. The second
- step is to use this sort field list to sort a logical records list.
- After sorting is completed, the user should destroy the sort field list
- using the provided routine unless the list will be required later. An
- example follows:
-
- type
- MyRecord = record
- field1 : Byte;
- field2 : Word;
- field3 : String[10];
- end;
-
- var
- lrLst : LrList;
- sPtr : SortFieldList;
- success : Boolean;
-
- begin
- GetValidLogicalRecords(xxx,lrLst); (* list of all records *)
-
- sPtr := NIL; (* EXTREMELY CRITICAL !!! - you must pass in a
- pointer variable whose value is NIL. If
- you forget this little step all kinds of
- bad things will probably happen!!! *)
-
- AddFieldToSortList(sPtr,4,STRINGVALUE);
- AddFieldToSortList(sPtr,2,WORDVALUE);
- SortList(lrLst,xxx,sPtr,success);
- if not success then
- begin
- (* there was not enough heap space to facilitate the sort. Free
- up some space and try again if desired *)
- end;
- DestroySortList(sPtr); (* retrieve the heap space *)
- end;
-
- Notice that the second parameter is the BYTE position of the sort field
- within the data record. It is not the field number. This is extremely
- important!! See the SORT unit for details.
-
- Building/Rebuilding Indexes - Once in awhile you may manage to wipe out
- an index or in some other way cause it to be out of whack with your data
- file. Or, you may want to add an index to a field which previously did
- not have an index. This can easily be accomplished using a routine added
- in version 1.1. Rather than repeating the example here, please refer to
- EXAMPLE7.PAS which will show how to build a list of existing records and
- rebuild an index from that list. The added routine will also allow you
- to build a list of all logical records associated with a data file
- without using an index. To check out an index to be sure that certain
- logical record numbers are in fact in the index, you can use the
- FindLrNumInBTree routine.
-
- Viewing Status Information - I have included several routines for
- checking on the values of certain parameters and for allowing the user to
- delve into the depths if desired. The first routine to discuss is one
- which allows you to find out how many entries are in a logical record
- list once it has been created. To accomplish this the following call is
- used:
-
- cnt := GetCountLr(lrLst); (* lrLst is your variable where
- the list resides *)
-
- A second valuable utility is a routine which will return the number of
- files which are presently open using the FILEBUFF unit. In other words
- this returns the number of files which are on the files open list. This
- is not necessarily the number of files which DOS thinks is open. Only
- files opened using the create file or open file routines provided in
- FILEBUFF.PAS will be included in this number. Not included will be other
- files opened by the user and the files such as standard input and output
- etc. An example of a call is below:
-
- cnt := GetNumberOpenFiles;
-
- Several routines are provided in FILES.PAS which have not been discussed
- yet. The first is FileExists which will determine the existence of any
- file. Another routine of use is SaveUserDataArray. This will store a
- 256 byte array in the parameter record for a data or index file. This
- can be used to store whatever the user desires. FetchUserDataArray will
- retrieve the 256 byte array for the user. Another routine of use is
- FetchFileVersion which will return a 6 character string which determines
- which version was used to create the index or data file.
-
- The largest number of utilities lies in PAGE.PAS. The first routines of
- interest are the ones for writing part or all of the buffer to disk. The
- demand paging used in the PAGE.PAS unit is critical to the performance of
- TBTREE16. Since a large number of pages are in the memory buffer, the
- need to constantly go out to disk is reduced. Disk seeks (head movement)
- is what slows down most database operations. The secret is to do
- everything you can to alleviate the need to go out to disk. Memory is
- many times faster than external storage. However, if changes are made to
- pages in the buffer we want to ensure that they do not get lost. We need
- to write them to disk at some point. Normally, a page will stay in
- memory until another page needs the space. The unit uses a least recently
- used algorithm which in nothing earth shattering (but it works). When a
- page needs to be swapped out, a check is made to see if it is dirty
- (changes have been made since it was read in or last written to disk).
- If it is clean no problem. If it is dirty it is written to disk prior to
- allowing the page to be reused. The user can force pages to be written
- out at any time. One method is to set a parameter which forces a write
- to disk anytime a page is written to in memory. Essentially, a page will
- never be dirty this way. To accomplish this the SetImmediateDiskWrite
- routine is used. The user can set this parameter to TRUE or FALSE.
- FALSE is the default, but the user should probably make an explicit call
- anyway on initialization so there is no doubt or confusion. If FALSE is
- set, the user may still want to periodically write pages to disk. The
- user can write all pages for a given file or all pages in the buffer.
- For example:
-
- WriteEntireBufferToDisk;
-
- or
-
- WriteBufferToDisk(xxx); where xxx is a file name
-
- The user should always write all pages to disk prior to termination.
- Otherwise, changes made to pages still in memory will be lost. A handy
- way to do this is to call it from an exit procedure. See EXAMPLE2.PAS
- for an example.
-
- A second set of routines are provided to get rid of (release) pages in
- the buffer. The pages should be written to disk prior to release. These
- routines can be dangerous. I need them internally for operations such as
- changing the size of the buffer dynamically and also for deleting a file.
- They are visible and free to use, but understand what you're doing first.
- If you're looking for a convenient way to wreck havoc with your data
- these two are perfect candidates. The only reason I can foresee why you
- would want to attempt to use these is to release some pages for files you
- won't need for a while in order to free up heap space (such as for a
- sort). Before releasing, write the affected pages to disk!! Except for
- freeing up heap space, there is not really a need to micro manage the
- resources like this and these routines can lead to problems if misused.
- Accidentally, losing a node (page) in the middle of an index will leave
- it in an unrepairable state and will ruin your whole day.
-
- A third set of routines are much friendlier and I can stay off my soap
- box. These routines manipulate and check the size of the buffer. All
- values are in terms of pages. A page is 512 bytes. To digress slightly,
- 512 worked well because a smaller number caused inefficiency in the least
- recently used page algorithm and also meant that index keys had to be
- smaller. A larger number means that less pages can be in memory at once.
- Do not try to change this constant as a lot of things are affected. Just
- changing the constant will not work properly. This is due to the fact
- that a constant declaration can not be declared using a simple
- expression (version 4.0). For example:
-
- const
- xxx = 10;
- yyy = xxx/2; (* illegal in Turbo Pascal version 4.0 *)
-
- Therefore, other constants that depend on xxx have to be set explicitly.
- In the above, yyy would have to be set to 5. Anyway, back to the matters
- at hand. To set the size of the buffer the following call should be
- made:
-
- SetMaxBufferPages(50); (* 25K bytes *)
-
- If a user does not set the page limit explicitly, the value will default
- to one page. Everything still works, but performance will be extremely
- poor. A minimum of 10 pages is required to have this work well at all.
- One hundred or so pages is preferred. A great deal depends on your
- application as well! A user can check this value at any time by doing
- the following:
-
- cnt := CheckMaxBufferPages;
-
- The user can check the number actually in use by doing the following:
-
- cnt := CheckPagesInUse;
-
- One routine not mentioned earlier is CheckImmediateDiskWrite which
- returns TRUE if dirty pages will be immediately written to disk, FALSE
- otherwise.
-
- One interesting routine is PrintPagebuffer. This routine is one that I
- developed for my own debugging purposes and is included to allow you to
- see what the page buffer looks like. One warning though, if the page
- buffer is large, the output will be quite lengthy.
-
- The PrintBufferStats routine is more for curiosity's sake and for tuning
- the size of the buffer. A call to this routine will print the statistics
- for buffer use. The number of pages in use, the maximum number of pages
- allowed, the number of requests for a page (fetches), the number of
- fetches in which the page was in the buffer (hits) and the ratio of hits
- to fetches will be output. A hit ratio of much below 95% could signal a
- requirement to increase the buffer size. You really need to keep this
- number in perspective though. If you are waltzing through a file in
- which none of the records are in the buffer, the hit ratio will be poor.
- Other operations will have higher hit ratios. At least it's there to use
- as desired.
-
- A recently added routine contained in the BTREE unit is
- NumberOfBTreeLevels which returns the number of levels currently in an
- index. If that number gets above 10 you are doing something rather
- strange and may run into stack problems. The cause of such an occurrence
- is that you have a huge number of index entries (many many thousands) or
- your index entries are large. The only entries over 4 bytes are strings
- or arrays of type ByteData. These types of indexes should use entries as
- small as possible. Don't use first name, last name, and middle initial
- as all one indexed filed unless there is a really good reason to
- (doubtful). Any string index entry over about 30 bytes is suspect.
- Remember what an index is for .. to store something to allow quick
- retrievals. The index is not designed to be the data file. A deep index
- will simply not be as fast as a shallow index. The smaller the index
- entry size, the shallower the index.
-
- Another new routine is the FindLrNumInBTree which can be used for
- debugging and checking the consistency of an index file.
-
- Other Routines - I discussed above the routines which are directly
- applicable to a user who wants to use the indexing and data manipulation
- capabilities of TBTREE16. There are some lower level general routines
- such as those found in FASTMOVE.PAS, MATH.PAS and STRINGS.PAS which are
- used internally. Since they are fairly general in nature, they may have
- applicability for your other applications. I won't go into details on
- their inner workings here, but you have the source code, so you can look
- in the units to see if there is anything else useful for whatever you
- happen to be doing. The quick reference will provide assistance as well.
-
- Error Handling - In version 1.5 I have added a unit (ERROR unit) which is
- designed to handle I/O errors. This unit handles only I/O errors and
- allows these errors to be trapped. TBTREE16 I/O is now accomplished with
- I/O checking off. If an I/O error occurs, the ERROR unit comes into
- play. A routine is called with pertinent information being passed to it.
- The routine should be modified by the user, as desired, to handle the
- error. As written, if an I/O error occurs, the program will terminate
- after an error message is written. This parallels what would happen in
- versions prior to TBTREE15. However, as stated above, you are encouraged
- to change the routine to handle the error as desired.
-
- @PA
- Inner Workings
-
- I am trying to avoid bogging you down with too much detail concerning the
- inner workings of this product. However, there are a few things which you may
- need to be aware of. One important area is how TBTREE16 manages the heap.
- Turbo Pascal has two different methods for heap management. TBTREE16 uses
- New, GetMem, FreeMem and Dispose exclusively. Mark and Release are not used
- and CAN NOT be used in your application if TBTREE16 is used. Mark and/or
- Release will cause a disaster!!! Also, TBTREE16 handles the heap well, but
- you need to provide it with a sufficient amount of heap to operate with. Heap
- is needed by the page buffer (PAGE unit), it is needed for sorting (SORT unit)
- and it greatly enhances the speed of set operations (SETOPS unit). If your
- application hogs all of the heap, sorts may be impossible and disk I/O caused
- by a small buffer will greatly reduce throughput. Also, set operations will
- slow down considerably. One more note - If the heap is almost full, an error
- can occur since there will not be room for the free list to expand when
- FreeMem is used (which is done extensively throughout TBTREE16). To preclude
- this from happening, you can set the freeMin variable (internal to TURBO
- PASCAL and has nothing to do with TBTREE) to a value which will reserve some
- number of bytes for the free list. Set freeMin to some multiple of 8 bytes to
- reserve space. The Turbo Pascal manual discusses this in depth in the section
- concerning the FREE LIST (p 198 of the version 5.0 manual). Again, this error
- has nothing to do with TBTREE (but it does affect it) and occurs in Turbo
- Pascal programs which use the whole heap and then try to dispose of space.
-
- You need to be aware of the tradeoff of using the LOGICAL unit versus the
- VLOGICAL unit. VLOGICAL obviously provides flexibility. However, there is a
- cost in performance and file size. There is an overhead of 10 bytes per
- logical record associated with variable record length files whereas there is
- an overhead of only one bit (not byte) for each record in a fixed length data
- file. The same holds true for records which have been deleted. This overhead
- is not as significant if the size of the records themselves is large. In the
- area of performance, you will find the variable length record routines to be a
- little slower. Which way to go is up to you. Remember, you can use both
- types in a single application, But once a file is declared to be of one type,
- you must not use the other type's routines with it. Doing that will cause
- problems.
-
- @PA
- Current Product Limitations
-
- The following limitations apply to TBTREE16. Only limitations inherent to
- TBTREE16 are discussed. DOS limits and practical limits like disk drive
- capacity are not discussed. These limitations may change (become less
- restrictive) in future additions.
-
-
- Number of Data Files - No Limit
-
- Number of Index Files Per Data File - No Limit
-
- Size of Data File - MAXLONGINT (2,147,483,647) Logical or Physical
- Records (whichever comes first) or disk space (the
- real limit!!)
-
- Size of Index File - MAXLONGINT Physical Records. The real restriction
- is going to be stack size. I use a recursive
- routine to traverse the BTrees. Recursion is
- very efficient for this but has the problem that
- each level keeps a couple of thousand bytes on
- the stack. It is very important to use a large
- stack size if indexes are going to be deep. Most
- indexes will not be more than 4 or 5 levels deep
- unless a HUGE number of records are involved or
- the keys in the indexes are large. Large is
- relative, but you need to try to keep entries
- below 30 bytes or so. This really only affects
- strings presently. I would like to know if
- anyone is running into problems with this as I
- can handle this iteratively rather than
- recursively which will make the problem disappear
- at the expense of some added coding complexity.
- I recently did a test to see to see how critical
- this is. I did a test using an index entry size
- of 100 bytes (100 byte strings). I entered over
- 27000 records before running out of disk space
- (took over one day on my archaic 4.77 MHz
- computer!). I had somewhere in the area of 15
- levels which is more than you should reasonably
- have. I also used a 32K stack (64K being the
- maximum allowed). Anyway, I couldn't blow it up
- so I don't think you will either!
-
- Size of Page Buffer - Limited by heap space. I have not used this
- with any type of heap extender or other program
- which uses other memory (extended, expanded) for
- the heap. I would enjoy seeing feedback if
- anyone tries it. If I need to do something to
- facilitate use of a heap extender let me know
- and I'll try to accommodate.
-
- Number of Files Open At Once - Actual number set by user, but user
- does not have to worry about keeping
- track of files used by TBTREE16 since
- it opens and closes files as required.
-
- Size of Key (Index Entry) - 245 bytes. Versions prior to 1.6 had a
- higher number. However, no version ever
- worked for values higher than 245. I
- apparently missed that during testing.
- 245 is still much higher than you can
- practically use anyway.
-
- Size of Data Record - 65520 bytes since this is the limit for
- structured (composite) types in Turbo Pascal.
-
- Max File Name Length - 80 characters including drive designator, path,
- file name and extension.
-
- Logical List Limit - Unlimited
-
- Number Of Sort Fields - Unlimited
-
- @PA
- Future Enhancements / Directions
-
- One of the advantages of using the shareware concept to distribute this
- software is that I can be very flexible and can tailor this product to the
- needs of users. I am soliciting as much feedback as possible. I need to know
- what is really important to users. I hope to be able to accomplish the
- following in the future:
-
- I may change the delete routines in the BTREE.PAS unit to force the
- combining of nodes when each is half full or less. Presently, a node is
- not deleted until the last entry is deleted. This will slightly increase
- performance on queries and will reduce the size of the indexes if deletes
- are done often, but will otherwise be transparent.
-
- I may pursue adding multitasking capabilities.
-
- The most significant change for the future will be an abandonment of Turbo
- Pascal 4.0 support. Version 5.0 has some nice features which I can not
- use yet because I wanted this version to support Turbo Pascal 4.0. If I
- do not get negative feedback, future versions will support only version 5
- (and later when there is one) of Turbo Pascal. I would like to get
- feedback concerning peoples feelings on this (registered and nonregistered
- alike). I also need feedback to determine if most people are moving to
- version 5.5. Mine is still in the mail, so I need to see what good
- things that will do for me before I make any determinations.
-
- Version Release Notes
-
- Version 1.1
-
- 1. Added capability to do a search of an index on a range of values.
-
- 2. Added capability to do partial string match searches (strings only).
- Added one routine to the BTREE unit and several routines to the COMPARE
- unit and one type declaration to the NUMBERS unit to facilitate this
- change.
-
- 3. Corrected bug in BTREE unit. Documentation stated that duplicate entries
- for a given logical record number and field value were prevented from
- being entered. This was not previously the case although that is now
- true.
-
- 4. Added a routine (LOGICAL unit) to build a list of all current records for
- a file (all valid ie not deleted records). This is essential for
- rebuilding indexes or accessing data without an index. In actuality, a
- user could have built this routine, but it was not intuitively obvious.
-
- 5. Added the capability to delete an entry from an existing logical record
- list.
-
- 6. Divided BTREE.PAS into BTREE.PAS and two include files : BTREE1.INC and
- BTREE2.INC.
-
- 7. Added several more examples.
-
- Version 1.2
-
- 1. Added Sorting capabilities.
-
- 2. Added several routines to LRECLIST.PAS to facilitate sorting. I also made
- a couple of internal cosmetic changes to LRECLIST.PAS.
-
- 3. Added one example.
-
- 4. Removed CalculateRecordSize and several unused data types from
- LOGICAL.PAS. These were for future projects and now are now targeted for
- TBASE.
-
- Version 1.3
-
- 1. Added SETOPS unit which provides Intersection, Union and Difference.
-
- 2. Added one example.
-
- 3. MATH.PAS redone in assemble language. See listing for details and credit
- to the author.
-
- 4. Added one routine (FindLrInList) to LRECLIST.PAS.
-
- 5. In LOGICAL.PAS changed MAXDATASIZE to 65520 since this is the maximum size
- for a structured type in Turbo Pascal 4.0.
-
- 6. TP4PRINT.PAS now prints the file creation date as part of the header.
-
- 7. Added NumberOfBTreeLevels routine to the BTREE unit.
-
- 8. Added StoreNewLogicalRecord routine to LOGICAL.PAS. This makes it easier
- to store new records. You no longer need to find the next available
- logical record number using the FirstUnUsedRecord routine located in
- FILES.PAS. StoreNewLogicalRecord does this for you and returns the
- associated logical record number.
-
-
- Version 1.4
-
- 1. Biggest change is a redesign of the data and index files. Both file types
- have a parameter record (previously only the index files did). There is
- more information contained in the parameter records, including a place for
- you to store 256 bytes of user data for your own requirements. I also did
- away with the bitmap files. Bitmaps are contained in the individual
- files. Adds some speed and cuts in half the number of files floating
- around. However, all files that were created using previous versions will
- not work with this new version of software. You will need to rebuild all
- data and index files. I realize that this will cause some problems. The
- index files will be easy, as EXAM7.PAS shows you how. However, the data
- files will be tough. The easiest method will be to write a small
- application using the old software and dump the data to to a flat file.
- Then you can create an application with the new version and read in the
- old data to the new files. Make sure you have a backup of your old files
- before doing anything!!!
-
- 2. Many routine calls have been changed because of the above changes.
- Specifically, stores and retrievals of logical records no longer require
- the size of the data record to be passed in. However, the size is needed
- when the file is created. Specific routines were developed for creating
- and deleting the data files and other routines were developed for creating
- and deleting the index files.
-
- 3. The ByteData unit was added, although at this point it is of limited
- value. It is really for work I am doing on TBASE. It is available for
- your use, however.
-
- 4. Corrected several errors. Specifically, logical record sizes > 512 bytes
- did not work properly and the previous size limit for an index entry was
- really 255. This has been corrected. The limit is now 494 bytes as
- specified in the documentation.
-
- 5. Added a second way to perform retrievals of logical record numbers from an
- index. See the BTREE unit for details.
-
- 6. Added GetSubstringAtPosition routine.
-
- 7. GetSubstringFromBTree routine did not work as advertised because of an
- error in the COMPARE unit which has been fixed.
-
- 8. Added ByteData unit
-
- 9. Moved ValueType to NUMBERS unit and added BYTEARRAYVALUE
-
- 10. Corrected EndsWithSubstring routine
-
- 11. Added ContainsSubstringAtPosition routine
-
- 12. Now use {$IFOPT N+} conditional compilation directive to handle 8087 types
-
- 13. All INDEX and DATA files now contain the version used to create the file.
- This is contained in the index.
-
- 14. Changed definition for RecordNumber and FileTypes type
-
- 15. Added UserDataArray type
-
- 16. Added FileExists routine
-
- 17. Redesigned entire FILES unit. See unit for details.
-
- 18. Many changes to LOGICAL unit. See unit for details.
-
- 19. Deleted PowerInt from MATH unit.
-
- 20. Changed SortList procedure call so that size is no longer required.
-
- 21. Added MAXSTRINGLENGTH constant and StringLengthRange type to STRINGS unit
-
- 22. Redesigned TIME unit. See unit for details.
-
- 23. Many changes in BTREE unit. See unit for details.
-
- 24. Updated the examples to implement the changes. One note - I had an error
- in the MyExit routine in the examples. I forgot to to reinstall the value
- of ExitProc which essentially broke the chain for calling exit routines.
- Examples are now correct.
-
- Version 1.5
-
- 1. Fixed documentation errors in the examples.
-
- 2. Cleared up documentation in the FILEBUFF unit.
-
- 3. Added FASTMOVE unit to speed up moves.
-
- 4. Made internal changes to use Inc and Dec to increase performance
-
- 5. Completely reworked the SORT unit. Performance has increased threefold.
-
- 6. Added ERROR unit to trap I/O errors. See error unit for details.
-
- 7. Changed the PAGE unit and FILEBUFF units to keep heap allocation errors
- from ever occurring. Units now reserve a minimum amount of space during
- initialization to ensure that there is always at least some minimum amount
- of space available. See units for details.
-
- 8. Added FindLrNumInBTree and UsingCursorAndGEValueGetLr routine to BTREE
- unit.
-
- 9. Changed way records are added as data and index files grow. As files grow
- larger, the number of records added at one time increases. This will
- speed up the insert process.
-
- 10. Reworked FILEBUFF unit to handle Text files better.
-
- 11. Changed problems in LOGICAL unit associated with calling routines with
- logical record number equal to 0. See LOGICAL unit for details.
-
- 12. Added LastDataRecord to LOGICAL unit.
-
- 13. Added CopyLrList routine to LRECLIST unit.
-
- 14. Changed definition of SortList routine. See SORT unit for details.
-
- 15. Added Asciiz2Str routine to STRINGS unit.
-
- 16. Rewrote TotalString routine to increase performance.
-
- 17. Parts of TIME unit redone using INLINE statements to increase performance.
-
- 18. Fixed error in GetEqualsFromBTree routine which would cause random
- failures on queries where the Condition was EQ
-
- 19. Fixed error in GetRangeFromBTree routine which caused problems when the
- upper range and lower range were the same
-
- Version 1.6
-
- 1. Fixed an error which caused the wrong entries to be deleted from an index
- when using DeleteValueFromBTree
-
- 2. Changed the value of MAXVALSIZE to 245 which is the correct limit on the
- maximum size of an index entry
-
- 3. Added VLRDATA to the FileTypes enumerated type
-
- 4. Added FetchFileType routine
-
- 5. Corrected error in LOGICAL unit which caused an error when dealing with
- records larger than 512 bytes
-
- 6. Added VLOGICAL unit. This unit is an alternative to the LOGICAL unit and
- it handles variable length records
-
- 7. Fixed error in the SORT unit which would lead to an infinite loop when the
- heap became full and memory was being allocated for a sort
-
- 8. Changed SORT unit to facilitate sorting variable length record data files
-
- 9. Fixed an error in the SORT unit which caused the sort field list to be
- modified upon completion of the sort. The sort field list is now returned
- unmodified which allows it to be used again to sort on the same fields
-
- 10. Fixed a major error in the SORT unit which caused logical record numbers
- to be lost from a logical record list when that list was sorted
-
-
-
-
-
- Turbo Pascal is a registered trademark of Borland International
- CompuServe is a registered trademark of CompuServe Incorporated