home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TP4DBFIX.ZIP / FIXDEL.PAS next >
Encoding:
Pascal/Delphi Source File  |  1988-10-14  |  5.9 KB  |  134 lines

  1. program FixDel;
  2.  
  3. {$I+}
  4.  
  5. { Fix the deleted record chain in a Database Toolbox data file.
  6.  
  7.   Scott Bussinger
  8.   Professional Practice Systems
  9.   110 South 131st Street
  10.   Tacoma, WA  98444
  11.   (206)531-8944
  12.   Compuserve 72247,2671
  13.  
  14.   Version 4.01 - 10/14/1988 - Refixed bug with reading one too many records
  15.           4.00 -  6/28/1988 - Converted for use with version 4
  16.           1.00 -  9/22/1987 - First release
  17.  
  18.     The Database Toolbox uses the first four bytes of a DataFile as a marker
  19.   that a record has been deleted.  By convention, if the first four bytes
  20.   (considered as an longint) are 0, then the record is in use.  Otherwise the
  21.   record is deleted.  AddRec will reuse deleted records before allocating new
  22.   records at the end of the DataFile.  This keeps the DataFile as small as
  23.   possible.
  24.     Normally this happens invisibly to your program as DeleteRec and AddRec
  25.   are called and you don't need to do anything except make the first field in
  26.   the data type for all of your DataFiles look like:
  27.                 DeletedRec: longint;
  28.     Internally, the Database Toolbox keeps two variables pertaining to the
  29.   deleted record chain.  The first is FirstFree and is the record number of
  30.   the next deleted record to be reused when AddRec is next called.  The other
  31.   variable is NumberFree and is the number of deleted records available in
  32.   the DataFile.  This value is used only in the calculations for UsedRecs so
  33.   that you can find out how many records are in use without actually scanning
  34.   the file.  When a record is deleted, current value in FirstFree is written
  35.   into the deleted record and FirstFree is set to deleted record's record
  36.   number.  This creates a chain of deleted records.
  37.     When AddRec is called, FirstFree is checked to see if there are any
  38.   deleted records to be reused.  If FirstFree is -1 then there are no deleted
  39.   records and the file is made larger.  Otherwise AddRec uses the value of
  40.   FirstFree as the record number, reads in that record and sets FirstFree to
  41.   the value saved in the deleted record.  This goes back down the deleted
  42.   record chain.
  43.     Everything works fine as long as nothing goes wrong.  If a DataFile gets
  44.   messed up though power failure, media problems or programming bugs, then
  45.   this deleted record chain can be trashed and all sorts of strange things
  46.   can happen.  For example, lets say that the header record in a file takes a
  47.   hit and FirstFree ends up pointing at a record that is really a record in
  48.   use.  In this case the next time AddRec is called, the previous contents
  49.   of the record are overwritten by the new record.  If you are using index
  50.   files, you will probably have two keys pointing at this record (one for the
  51.   record just added and one for the original record).  Even worse, FirstFree
  52.   takes its new value from that record and will be set to 0 (since the record
  53.   wasn't deleted).  Now, the next AddRec will write its record on top of the
  54.   header record!  At this point things get progressively worse and all kinds
  55.   of bizarre behaviour is common.
  56.     Just as it is good practice to reindex files occasionally, it is a good
  57.   idea to rebuild the deleted record chain of DataFiles.  This program will
  58.   rebuild the deleted record chain of any DataFile and can also serve as a
  59.   guideline for writing your own programs.
  60.     To use this program, compile it to disk with Turbo Pascal 4.  Then from
  61.   the DOS prompt, type
  62.                 FIXDEL filename recsize
  63.   where 'filename' is the name of a DataFile and 'recsize' is the number of
  64.   bytes in a record.  This record size is the same number passed to the
  65.   OpenFile routine. }
  66.  
  67.  
  68. type DBoxHeaderRec = record            { Layout the a header record }
  69.        FirstFree: longint;
  70.        NumberFree: longint;
  71.        Int1: longint;
  72.        RecLen: word
  73.        end;
  74.  
  75. var Buffer: ^longint;                  { Pointer to deleted record flag }
  76.     ErrorCode: integer;
  77.     Fyle: file;
  78.     Header: DBoxHeaderRec;
  79.     RecNum: longint;
  80.     RecSize: word;
  81.  
  82. begin
  83. case paramcount of
  84.   0: writeln('Usage: FIXDEL filename recsize');
  85.   1: writeln('Not enough parameters.');
  86.   2: begin
  87.      val(paramstr(2),RecSize,ErrorCode);
  88.      if (ErrorCode<>0) or (RecSize<14)
  89.       then
  90.        writeln('Record size out of range.'^G)
  91.       else
  92.        begin
  93.        getmem(Buffer,RecSize);         { Get enough memory to hold a record }
  94.        assign(Fyle,paramstr(1));
  95.        {$I-}
  96.        reset(Fyle,RecSize);            { Open the data file }
  97.        {$I+}
  98.        if ioresult <> 0
  99.         then
  100.          writeln(paramstr(1),' not found.'^G)
  101.         else
  102.          begin
  103.          blockread(Fyle,Buffer^,1);    { Get the header record }
  104.          move(Buffer^,Header,sizeof(Header));
  105.          with Header do
  106.            begin
  107.            FirstFree := -1;            { Initialize deleted record chain }
  108.            NumberFree := 0;            { Deleted record chain now empty }
  109.            Int1 := 0;                  { Zap the index root page }
  110.            RecLen := RecSize           { Reset the record length }
  111.            end;
  112.          for RecNum := 1 to filesize(Fyle)-1 do { Go through all records }
  113.            begin
  114.            seek(Fyle,RecNum);
  115.            blockread(Fyle,Buffer^,1);  { Get data record }
  116.            if Buffer^ <> 0 then        { Is this a deleted record? }
  117.              begin
  118.              Buffer^ := Header.FirstFree; { Put record in chain }
  119.              Header.FirstFree := RecNum;  { New head of list }
  120.              inc(Header.NumberFree);      { One more deleted }
  121.              seek(Fyle,RecNum);        { Put file position back }
  122.              blockwrite(Fyle,Buffer^,1){ Put deleted record back }
  123.              end
  124.            end;
  125.          seek(Fyle,0);                 { Put fixed header back in file }
  126.          blockwrite(Fyle,Header,1);
  127.          close(Fyle)                   { We're done }
  128.          end
  129.        end
  130.      end
  131.   else writeln('Too many parameters.')
  132.   end
  133. end.
  134.