home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / lambda / soundpot / a / dbtips.lbr / DBPROG.TZP / DBPROG.TIP
Encoding:
Text File  |  1993-10-26  |  18.1 KB  |  464 lines

  1.  
  2.  
  3. dBASE II PROGRAMMING TIPS
  4.  
  5.  1 Database file structure
  6.  2 Command line limit
  7.  3 Changing the record count
  8.  4 Negative SKIP in RunTime
  9.  5 Num. fields & decimal places
  10.  6 Recreating a database header
  11.  7 Recovering Cross-linked files
  12.  8 Removing Duplicate Index Keys
  13.  9 Self-Cleaning Database Files
  14.  
  15. 1
  16.  
  17.  
  18.  The internal structure of a dBASE II database file is composed
  19. of a header and data records.  The header is a block of data
  20. which contains information about the structure of the data file,
  21. such as how many records it contains, and the date it was last
  22. updated.  The table below shows how this information is stored.
  23. dBASE II DATABASE FILE HEADER:
  24.  +---------+-------------------+---------------------------------+
  25.  |   BYTE  |    CONTENTS       |        MEANING                  |
  26.  +---------+-------------------+---------------------------------+
  27.  |  0      |  02H              | denotes dBASE II database file  |
  28.  +---------+-------------------+---------------------------------+
  29.  |  1-2    |  16 bit number    | number of records in data file  |
  30.  +---------+-------------------+---------------------------------+
  31.  |  3-5    |  3 bytes          | date of last update (MM DD YY)  |
  32.  +---------+-------------------+---------------------------------+
  33.  |  6-7    |  16 bit number    | size of the record              |
  34.  +---------+-------------------+---------------------------------+
  35.  |  8-519  |  32x16 byte array | Field descriptors terminated by | --+
  36.  |         |                   |   a carriage return (0DH)       |   |
  37.  +---------+-------------------+---------------------------------+   |
  38.  |  520    |  1 byte           | 0DH if all 32 fields present,   |   |
  39.  |         |                   |   otherwise a hex zero          |   |
  40.  +---------+-------------------+---------------------------------+   |
  41.                                                                      |
  42.                                                                      |
  43.  EACH FIELD DESCRIPTOR:        <-------------------------------------+
  44.  
  45. +---------+-------------------+---------------------------------+
  46.  |  BYTE   |     CONTENTS      |          MEANING                |
  47.  +---------+-------------------+---------------------------------+
  48.  |  0-10   |  11 bytes         | field name in ASCII, zero-filled|
  49.  +---------+-------------------+---------------------------------+
  50.  |  11     |  1 byte           | field type in ASCII (C N or L)  |
  51.  +---------+-------------------+---------------------------------+
  52.  |  12     |  1 byte           | field length in binary          |
  53.  +---------+-------------------+--------------------------------+
  54.  |  13-14  |  16 bit number    | field data address              |
  55.  |         |                   |  (address is set in memory)     |
  56.  +---------+-------------------+---------------------------------+
  57.  |  15     |  1 byte           | field decimal count in binary   |
  58.  +---------+-------------------+---------------------------------+
  59.  
  60. The data records are layed out as follows:
  61.   1. Data records are preceded by one byte that is a
  62.      space (20H) if the record is not deleted and an
  63.      asterisk (2AH) if it is deleted.
  64.   2. Data fields are packed into records without
  65.      separators or record terminators.
  66.   3. Data types are stored in ASCII format as follows:
  67.      DATA TYPE      DATA RECORD STORAGE
  68.      ---------      ------------------------------------------
  69.      Character      (ASCII characters)
  70.      Numeric        - . 0 1 2 3 4 5 6 7 8 9
  71.      Logical        Y y N n T t F f (20H when not initialized)
  72.  
  73.  
  74.  2 Command line limit
  75.  
  76.  
  77.  dBASE II uses a 254 byte buffer to interpret a command line.  If
  78. a command line reachs or exceeds the buffer limit (such as with a
  79. REPLACE command), dBASE II will give unpredictable results.  No
  80. error message is given.
  81.  
  82.  
  83.  3 Changing the record count
  84.  
  85.  
  86.  An incorrect record count in a dBASE II datafile header can
  87. result from one of the following:
  88.  
  89.  1. Turning off the computer before closing the
  90.     datafiles or QUITting dBASE.
  91.  2. Interrupting a PACK, SORT, APPEND, or COPY operation.
  92.  3. Power supply interruptions while processing data.
  93.  
  94.  Some known methods for correcting a faulty record count in a
  95. dBASE II database are listed below.
  96.  
  97.  Method 1:  Use the COPY command and make a new copy of the file
  98. under a different filename.  Since the COPY command keeps an
  99. internal counter, it will restore the correct record count to the
  100. header of the new file after completing the copy.
  101.  Enter dBASE and type the following:
  102.  
  103.      . USE <sickfile>
  104.      . COPY TO <newfile>
  105.  
  106. Method 2:  With this method you will need to create and run a
  107. BASIC program. This program will work with MicroSoft BASIC or PC-
  108. DOS BASICA.  You can write this program in dBASE II with MODIFY
  109. COMMAND.
  110.  
  111.  100 'Program.: FIXHEAD.BAS
  112.  110 'Author..: Luis A. Castro
  113.  115 'Date....: 12/19/84
  114.  120 'Notes...: To run this program, type the following:
  115.  125 '
  116.  130 '    A>MBASIC FIXHEAD    (MicroSoft BASIC)
  117.  140 '    A>BASICA FIXHEAD    (IBM-PC BASIC)
  118.  150 '
  119.  200 PRINT 'Change record count on header of DBF file"
  120.  210 PRINT
  121.  220 INPUT "Enter FILENAME.EXT ",FILENAME$   'Get the filename
  122.  230 OPEN "R", #1, FILENAME$, 3              'Open the file
  123.  240 FIELD #1, 1 AS DUMMY$, 2 AS OLDVAL$     'Field of 3 bytes
  124.  250 GET #1, 1                               'Get the first
  125. record
  126.  260 PRINT "Number of records ";CVI(OLDVAL$) 'Old record count
  127.  270 INPUT "        Change to  ",NEWVAL%     'Get new record
  128. count
  129.  280 LSET OLDVAL$=MKI$(NEWVAL%)              'Replace old with
  130. new
  131.  290 PUT #1, 1                               'Save the record
  132.  300 CLOS% W1                                'Close the file
  133.  400 OPEN "R", #1, FILENAME$, 1  'Open the file again
  134.  410 FIELD #1, 1 AS ONEBYTE$     'Field record to 1 byte
  135.  420 LSET ONEBYTE$=" "           'Replace field value with a
  136. blank
  137.  430 PUT #1, 522                 'Save the blank to byte 522
  138.  440 CLOSE #1                    'Close the file
  139.  450 SYSTEM                      'Exit to the operating system
  140.  
  141. Method 3:  Use DDT (CP/M-80) or DEBUG (PC/MS-DOS) to patch the
  142. two bytes in the datafile header containing the record count.
  143. This method assumes the entire datafile will fit into memory at
  144. one time and you should not use this method otherwise.  The new
  145. record count value must be converted to hexadecimal before it can
  146. be patched in.
  147.  
  148.     IF DDT IS AVAILABLE (CP/M-80):
  149.  
  150.      A>DDT Filename.DBF     (user input is underlined)
  151.        <DDT version information>
  152.      NEXT PC
  153.      yyxx 0100
  154.      -S101
  155.      0101  ll  aa   (where aa is low-order byte of new value)
  156.      0102  hh  bb   (where bb is high-order byte of new value)
  157.      0103  mm  .
  158.      -<Ctrl-C>
  159.      A>SAVE pp Filename.DBF  (where pp is the number of pages)
  160.  
  161.  In order to calculate the number of 256 byte blocks to write to
  162. disk, called "pages" and represented by "pp" in our example, do
  163. the following:
  164.  
  165.  1) Find the two four digit numbers just below NEXT PC
  166.     in the DDT header.  Forget about the right hand
  167.     number, 0100, DDT will always load your file beginning
  168.     at this address.
  169.  2) Select the yy portion of the first four digit number and
  170.     convert this hexadecimal number to decimal.  The decimal
  171.     number minus one is the number of pages (pp) to SAVE.
  172.  3) There is only one special case where step (2) will not
  173.     give the correct result.  If the last two digits of this
  174.     four digit number (xx in our example) is hexadecimal 80,
  175.     then do not subtract one from the decimal number.
  176.  
  177. IF DEBUG IS AVAILABLE (PC/MS-DOS):
  178.  
  179.     A>DEBUG Filename.DBF     (user input is underlined)
  180.      -E101
  181.      xxxx:0101  ll.aa <space> hh.bb <RETURN>
  182.           (where aa is the low-order and bb is the high-order
  183.            byte of the new record count value)
  184.      -W
  185.      -Q
  186.  
  187.     A>
  188.  
  189.  
  190.  4 Negative SKIP in RunTime
  191.  
  192.  SKIP-1 (with no spaces) works in dBASE II, but behaves
  193. differently when encrypted with RunTime's DBCODE version 2.4.  On
  194. all RunTime formats it will execute a SKIP to the next record.
  195. SKIP -1 (with a space) will correctly skip to the previous
  196. record.
  197.  
  198.  
  199.  5 Num. fields & decimal places
  200.  
  201.  Although not documented, dBASE II expects the user to allow for
  202. a leading digit and a decimal point on numeric fields containing
  203. decimal places.  For example, a numeric field of two decimal
  204. places should not be defined any smaller than four digits in
  205. length--one position for the leading digit, one position for the
  206. decimal point, and two positions for the two decimal places.
  207.  If the structure for a numeric field does not allow for a
  208. leading digit (such as, a width of three and two decimal places),
  209. input to the numeric field will always be stored as zero.  Also,
  210. if other numeric fields follow this field, they might
  211. automatically be zeroed out when numeric data is entered to the
  212. first field.
  213.  
  214.  
  215.  6 Recreating a database header
  216.  
  217.  To "recreate" a corrupted dBASE II datafile header, you will
  218. need to follow the two steps listed below.  You will also need to
  219. run a BASIC program.
  220.  First:  Use the CREATE command in dBASE II to construct a new
  221. dBASE II header.
  222.  Second:  Run the BASIC program listed below.  This program will
  223. work with MicroSoft BASIC or PC-DOS BASICA.  You can input this
  224. program in dBASE II using MODIFY COMMAND.
  225.  
  226.  100 'Program.: NEWHEAD.BAS
  227.  110 'Author..: Luis A. Castro
  228.  120 'Date....: 12/19/84
  229.  130 'Notes...: Run the program from CP/M or DOS as follows:
  230.  135 '
  231.  140 '    A>MBASIC NEWHEAD/S:522   (MicroSoft BASIC)
  232.  150 '    A>BASICA NEWHEAD/S:522   (IBM-PC BASIC)
  233.  160 '
  234.  200 PRINT "Inserting a new dBASE II header"
  235.  205 PRINT
  236.  210 INPUT "Enter old FILENAME.EXT  ",OLDFILE$
  237.  220 OPEN "R",#1,OLDFILE$,522
  238.  230 FIELD #1,1 AS OLDCODE$,2 AS OLDVAL$
  239.  240 FIELD #1,3 AS D$,245 AS OLD1$,240 AS OLD2$,33 AS OLD3$
  240.  250 FIELD #1,250 AS D1$,250 AS D2$,21 AS D3$,1 AS LASTBYTE$
  241.  300 INPUT "Enter new structure FILENAME.EXT ",NEWFILE$
  242.  310 OPEN "R",#2,NEWFILE$,522
  243.  320 FIELD #2,1 AS NEWCODE$,2 AS NEWVAL$
  244.  330 FIELD #2,3 AS D$,245 AS NEW1$,240 AS NEW2$,33 AS NEW3$
  245.  340 GET #2,1
  246.  400 PRINT "Number of records ";CVI(OLDVAL$)
  247.  410 INPUT "        Change to  ",NEWVAL%
  248.  420 LSET OLDCODE$=NEWCODE$
  249.  430 LSET OLDVAL$=MKI$(NEWVAL%)
  250.  450 LSET OLD1$=NEW1$
  251.  460 LSET OLD2$=NEW2$
  252.  470 LSET OLD3$=NEW3$
  253.  480 LSET LASTBYTE$=" "
  254.  490 PUT #1,1
  255.  500 SYSTEM
  256.  
  257.  
  258.  
  259.  7 Recovering Cross-linked files
  260.  
  261.  Cross-linking happens when data from one file is written into
  262. another file on disk.  This can occur with both the CP/M and MS-
  263. DOS operating systems.
  264.  Many factors may cause this.  Hardware and operating system
  265. malfunctions can cause data to be written to the disk
  266. incorrectly.  The chances of this happening are lessened if the
  267. files on disk are closed when the malfunction occurs.  Files may
  268. be cross-linked in dBASE II, but the situation is not unique to
  269. dBASE.  We are aware of only one instance in which dBASE II may
  270. contribute to a cross-link.
  271.  The problem occurs when an error condition arises during command
  272. file execution.  If there are database or index files open at the
  273. time an error is found, dBASE II does not close these files.  If
  274. the user returns to the dot prompt and issues MODIFY COMMAND to
  275. fix the program error, the operating system may assume that the
  276. disk space allocated to the database or index file is available
  277. space and may use it for the command file update.  The disk
  278. memory map has not been protected along with the open database or
  279. index files.  As a result, the command file instructions are
  280. written into the data fields of the database or index files while
  281. allocation is made for the command file.  This creates a crossing
  282. or linking of files on the disk.
  283.  To avoid this, issue a CLEAR command before using MODIFY
  284. COMMAND. This will ensure that the database or index files have
  285. been updated before any changes are made to the command files.
  286.  Cross-linking is much less likely to occur on a disk that has
  287. been recently formatted or is relatively empty.  It is more
  288. likely to occur on a disk that is nearly full, or which has been
  289. subject to much use, creation, and deletion of files.
  290.  If cross-linking has already occurred, COPY (in MS-DOS) or PIP
  291. (in CP/M) the files to new files and delete the old files.  The
  292. files can then be examined and any data corruption can be
  293. corrected at that time.  The process of reclaiming information
  294. lost on the disk can be very laborious and require considerable
  295. manipulation from within dBASE II as well as at the operating
  296. system level.
  297.  Cross-linking may have occurred if the application suddenly
  298. begins to take substantially longer to process data.  A CHKDSK or
  299. STAT (CP/M) command may reveal lost clusters on the disk.
  300.  An experience of cross-linking, whether in dBASE II, another
  301. application program, or interactively from the operating system,
  302. stresses the value of making frequent and comprehensive backups
  303. of your data and program disks. Reconstructing data from backups
  304. is almost always the easist way to recover from a cross-link.
  305.  
  306.  
  307.  
  308.  8 Removing Duplicate Index Keys
  309.  
  310.  There are several methods available to remove duplicate key
  311. entries from an INDEXed database file.  One way is to check for
  312. the duplicate when entering the record.  The advantage here is
  313. that the integrity of the database file is always constant.  The
  314. penalty is that the duplicate checking requires some programming
  315. gymnastics and the data-entry process is slowed to assess
  316. correctness and take action based on error.  The second way is to
  317. run a duplicate checking routine against the INDEXed database
  318. file after the data-entry process is complete.  The advantage
  319. here is that the data-entry process can be as fast as possible
  320. with no encumbrances.  The data-entry logic can be simple and
  321. straightforward.  The disadvantage is that the database file
  322. integrity is not maintained throughout the data-entry process.
  323. Duplicate key entry checking must be done against the entire
  324. database file after data-entry is complete.
  325.  With those considerations in mind, the following routine can be
  326. used to remove duplicate key entries from an INDEXed database
  327. file subsequent to data-entry. It could be run whenever duplicate
  328. key entries need to be removed from the database file.  Users of
  329. large mailing list systems might, for example, want to run this
  330. routine against their mailing list database files prior to mass
  331. mailings. This removes the burden of duplicate checking from the
  332. data-entry cycle entirely.
  333.  
  334.  
  335. * Program ...: Remove.PRG
  336. * Author ....: Your Name
  337. * Date ......: 6-1-85
  338. * Note(s) ...: Batch duplicate key deletion routine.
  339. *
  340. * Replace YourFile, YourNdx, Your:key with the
  341. * appropriate names that correspond to your
  342. * application.
  343. *
  344. SET TALK OFF
  345. USE YourFile INDEX YourNdx
  346. * ---Initialize mkey to an impossible value.
  347. STORE "XXXXXXXXXXXX" TO mkey
  348. DO WHILE .NOT. EOF
  349.    IF Your:key = mkey
  350. DELETE
  351.    ELSE
  352. STORE Your:key to mkey
  353.    ENDIF
  354.    SKIP
  355. ENDDO
  356. CLEAR
  357. RETURN
  358. * EOF Remove.PRG
  359.  
  360.  
  361.  9 Self-Cleaning Database Files
  362.  
  363.  In many dBASE II applications, there is a simple option
  364. available which obviates the need for the time-consuming and
  365. otherwise problematic use of the PACK command.  It is possible in
  366. fact to make your database file self-cleaning.
  367.  A self-cleaning database file is one that simply overwrites
  368. records marked for deletion rather than deleting them.  This
  369. would be easy to accomplish for small database files with the
  370. following commands:
  371.  
  372.     LOCATE FOR *
  373.      IF .NOT. EOF
  374.         RECALL
  375.      ELSE
  376.         APPEND BLANK
  377.      ENDIF
  378.  
  379. These few commands will look for a deleted record.  If one is
  380. found it will be RECALLed and then the new data can be entered in
  381. its place.  If a deleted record is not found then a new record is
  382. added.
  383.  If the database file is of any size at all, the use of LOCATE
  384. can take much too long for this direct approach to be useful.
  385. Taking advantage of INDEXes and the FIND command can speed up the
  386. process considerably and make the self-cleaning process of an
  387. application virtually transparent to the user.
  388.  To make use of INDEXing, add a status field to your database
  389. file.  After INDEXing on the status field, it is a simple matter
  390. to FIND any record flagged for deletion and put the new data in
  391. its place.
  392.  To exemplify, CREATE a database file with the following
  393. structure:
  394.  
  395.     STRUCTURE FOR FILE:  Phone.DBF
  396.      FLD     NAME        TYPE  WIDTH   DEC
  397.      001     Last         C    018
  398.      002     First        C    012
  399.      003     Phone        C    014
  400.      004     Delstat      C    001
  401.      ** TOTAL **             00046
  402.  
  403. Then set up an index file INDEXed on Status:
  404.  
  405.      USE Phone
  406.      INDEX ON Status TO Status
  407.  
  408. To DELETE a record in this database file:
  409.  
  410.      DELETE
  411.      REPLACE Delstat WITH "D"
  412.  
  413.  These commands tell dBASE II to DELETE the current record and
  414. also tells us that the record is marked for deletion by setting
  415. the Status field to "D."
  416.  The following program demonstrates the basic routine you can use
  417. to APPEND records to a database file using the status field as a
  418. flag for FINDing deleted records.  If a deleted record is found,
  419. the fields are blanked out and overwritten.
  420.  
  421.  * Program..: Add_rec.PRG
  422.  * Author...: Brian Evans
  423.  * Date.....: July 1, 1985
  424.  * Notes....: Demonstrates self-cleaning database files
  425.  *            by adding new records into deleted records.
  426.  SET TALK OFF
  427.  SET DELETED OFF
  428.  ERASE
  429.  USE Phone INDEX Status
  430.  * ---Search for a record where the status field indicates that
  431.  * it
  432.  * ---is marked for deletion.
  433.  STORE T TO is:true
  434.  DO WHILE is:true
  435.     FIND D
  436.     IF # <> 0
  437.        * ---If a deleted record is found.
  438.        RECALL
  439.        * ---Clean out the fields.
  440.        REPLACE Last WITH "                   "
  441.        REPLACE First WITH "             "
  442.        REPLACE Phone WITH "               "
  443.        REPLACE Delstat WITH " "
  444.     ELSE
  445.        APPEND BLANK
  446.     ENDIF
  447.     * ---Add the new record in a custom data-entry screen
  448.     ERASE
  449.     @ 10,20 SAY " Last Name" GET Last
  450.     @ 11,20 SAY "First Name" GET First
  451.     @ 13,20 SAY " Phone Num" GET Phone PICTURE "(999)999-9999"
  452.     READ
  453.     CLEAR GETS
  454.     STORE " " TO again
  455.     @ 20,10 SAY "Add another record (Y/N)? " GET again PICTURE "!"
  456.     READ
  457.     STORE ( again <> "N" ) TO  is:true
  458.  ENDDO
  459.  SET DELETED ON
  460.  SET TALK ON
  461.  CLEAR
  462.  * EOF Add_rec.PRG
  463.  
  464.