829.TXT
     =====================================================================
     Automating Database Backup
     =====================================================================
     PRODUCT:   R:BASE                  VERSION:      4.5++ or Higher
     =====================================================================
     CATALOG:   General Information     AREA   :      General Information
     =====================================================================
 
 
     One of the most difficult tasks of an application developer is getting
     users to do regular backups of their database. All too often, when
     the time comes to restore a backup, there is not a current backup or
     it is faulty. The following procedure comes from Tom Grimshaw of Just
     For You Software in Sydney, Australia. The procedure is compatible
     with R:BASE 4.5 and higher.
 
     Tom developed a routine that encourages his clients to backup their
     database regularly, and can be used by any client as the database
     name is not hard coded into the backup procedures.
 
     Here are Tom's step-by-step procedures:
 
     1. I entered the following two lines in the main application file to
     set variables to the database name and the name I designated as the
     old database name. The database names are different for each
     application. The backup and restore procedures use the variables
     instead of hard coding the database name into the procedure.
 
     SET VAR vdbname TEXT = 'DBNAME'
     SET VAR voldname TEXT = 'DB_OLD'
 
     Note: you could use the CVAL function to return the database name to
     a variable:
 
     SET VAR vdbname TEXT = (CVAL('DATABASE'))
     SET VAR vdbname TEXT = (CVAL('DBPATH'))
 
     The keyword "DATABASE" returns the database name, for example,
     concomp. The keyword "DBPATH" returns the full path name of the
     database, for example, c:\rbwin\concomp. 
 
     2. I create a table in my application databases to store information
     about the last backup. The users cannot modify the data in this table
     from within the application.
 
     CREATE TABLE backups_done +
     (bu_date DATE  , +
      bu_numb INTEGER , +
      bu_drive TEXT (1) )
 
     3. I wrote a routine to determine the number of days since the last
     backup to diskette and prevent access to the database until a backup
     has been done to diskette if none found in the backups_done table
     within the last seven days.
 
     SELECT MAX(bu_date) +
      INTO vlastbudate +
      FROM backups_done +
      WHERE bu_drive <> 'C'
 
     IF vlastbudate < (.#DATE - 7) THEN
      DISPLAY screen2 IN application_name.APX
      PAUSE 1
      RUN bu_now IN application_name.APX
     ENDIF
 
     If users should backup to diskette more frequently than every week,
     simply change the IF statement to (#DATE - 1), for example, to
     require backups every other day.
 
     4. Then I realized there was nothing to stop a person from exiting
     the backup program without doing a backup and resuming from the
     place they left off in the main application so I wrote the
     following to go immediately under the code in step 3 to check for
     the above circumstance and force an exit from the application in
     that case.
 
     SELECT MAX(bu_date) +
      INTO vdatelastbudone +
      FROM backups_done +
      WHERE bu_drive <> 'C'
 
     IF vdatelastbudone < (.#DATE - 7) THEN
      WRITE 'No backup recorded, please restart and do backup.'
     AT 15,12
      PAUSE 1
      GOTO lend1
     ENDIF
 
     5. I obviously needed the following to call the backup to diskette
     routine in the backup application file from the main application.
 
     $COMMAND
     bu_now
     RUN disketbu IN dbcopybu.apx
     RETURN
 
     6. In the CLEANUP command block of the main application file I called
     the backup application to remind operators to do a backup on the way
     out of the application.
 
     $COMMAND
     CLEANUP
     RUN dbcopybu IN dbcopybu.apx
     RETURN
 
     Following is Tom's complete application file. Tom's procedures are
     designed for a single-user database application. Changes must be made
     for multi-user applications as some of the processes, such as copying
     or packing a database, cannot be done except in a single-user mode.
     Also, you need to modify the code to reflect the database residing on
     a file server other than the C drive.
 
     $COMMAND
     DBCOPYBU
     DISCONNECT
     LABEL LBEGBU
     NEWPAGE
     SET VAR SAVE_MESSAGES = (CVAL('MESSAGES'))
     SET VAR SAVE_ERROR = (CVAL('ERROR'))
     SET MESSAGES ON
     SET ERROR MESSAGES ON
     SET ECHO ON
     SET COLOR WHITE ON BLUE
     CONNECT &vdbname
     SET VAR varerror = .SQLCODE
     IF varerror <> 0 THEN
      CLS FROM 1,1 TO 25,80
      WRITE 'Could not connect to database.' AT 4,20
      WRITE 'Recommend you do a restore from the latest backup.'
     AT 6,20
      PAUSE 1
      RUN restr_bu IN dbcopybu.apx
     ELSE
      SELECT MAX(bu_numb) +
       INTO vlastnumb +
       FROM backups_done +
      WHERE bu_date = .#DATE
      IF vlastnumb IS NULL THEN
      SET VAR vlastnumb INTEGER = 0
      CLS FROM 1,1 TO 25,80
      DISPLAY screen1 IN DBCOPYBU.APX
      PAUSE 1
      ENDIF
     ENDIF
 
     CHOOSE PICK5 FROM utilmenu IN dbcopybu.apx AT 6 21 BLACK ON
     GRAY
     IF PICK5 = '[ESC]' THEN
      GOTO LENDBU
     ENDIF
     SWITCH (.PICK5)
     CASE 'Backup to diskette'
      RUN disketbu IN dbcopybu.apx
      BREAK
      CASE 'Backup to hard disk'
      RUN hddbu IN dbcopybu.apx
      BREAK
     CASE 'Copy Database'
      RUN cpymydb IN dbcopybu.apx
      BREAK
     CASE 'Pack In Place'
      RUN pckinplc IN dbcopybu.apx
      BREAK
     CASE 'Reload'
      RUN cpyrelod IN dbcopybu.apx
      BREAK
     CASE 'Restore Backup'
      RUN restr_bu IN dbcopybu.apx
      BREAK
     CASE 'Exit'
      GOTO LENDBU
      BREAK
     ENDSW
     GOTO LBEGBU
 
     LABEL LENDBU
     SET MESSAGES .SAVE_MESSAGES
     SET ERROR MESSAGES .SAVE_ERROR
     *(CLEAR VAR SAVE_MESSAGES, SAVE_ERROR, pick5, varerror,
     vlastnumb, +
      vrespons_rest, vendkey)
     NEWPAGE
     RETURN
 
     $MENU
     utilmenu
     POPUP |Back up and restore menu|
     |Backup to diskette|
     |Backup to hard disk|
     |Copy Database|
     |Pack In Place|
     |Reload|
     |Restore Backup|
     |Exit|
     ENDC
 
     $SCREEN
     screen1
 
 
      You have not done a backup today. It is most strongly recommended to
      do a backup to the hard disk after each hour's work and a backup to
      diskette minimally at the end of each day, or even half day if a lot
      of work is being entered into the database.
 
      As Clint Eastwood might ask you, 'Do you feel lucky?'
      The question to ask yourself is, 'How much work would I like
      to re-enter if the database crashed because of a power surge?'
      Your answer to that question determines how frequently you
      backup.
 
     $SCREEN
     warnmsge
 
 
             W A R N I N G ! ! !
             W A R N I N G ! ! !
 
         DO NOT INTERRUPT THIS PROCEDURE ONCE BEGUN.
        TO DO SO WOULD ALMOST CERTAINLY CORRUPT YOUR DATABASE
         AND YOU KNOW HOW MUCH WORK THAT WOULD MEAN!!!!
                ----
 
             W A R N I N G ! ! !
             W A R N I N G ! ! !
 
     $SCREEN
     userabor
 
 
          Discontinued procedure at user request.
          Returning control to keyboard.
 
     $COMMAND
     disketbu
     CLS FROM 1,1 TO 25,80
     WRITE 'This procedure will create a backup copy of the
     database' +
       AT 10,13
     WRITE 'on diskette(s).' AT 11,13
     WRITE 'Please insert a blank, formatted diskette in the+
     drive' AT 13,13
     WRITE 'to which you wish to back up and press any key when
     ready.' +
       AT 14,13
     PAUSE 1
     CLS FROM 1,1 TO 25,80
     SET VAR vnom_backupdr TEXT = 'A'
     DIALOG 'Enter drive to back up to - A or B etc.:' +
       vnom_backupdr = 1 vendkey 1 AT 16
     IF vendkey = '[Esc]' THEN
      BREAK
     ENDIF
     SET VAR vbackupdr = (SGET(.vnom_backupdr,1,1))
     SELECT MAX(bu_numb) +
      INTO vlastnumb +
      FROM backups_done +
      WHERE bu_date = .#DATE
     IF vlastnumb IS NULL THEN
      SET VAR vlastnumb INTEGER = 0
     ENDIF
     SET ESCAPE OFF
     CLS FROM 1,1 TO 25,80
     DISPLAY warnmsge IN dbcopybu.apx
     SET VAR vdrive TEXT = (.vbackupdr + ':\'), +
       viyear INTEGER = (IYR(.#DATE)), +
       vimon INTEGER = (IMON(.#DATE)), +
       viday INTEGER = (IDAY(.#DATE)), +
       vsuffix INTEGER = (.vlastnumb + 1)
     SET VAR viyear TEXT, +
       vtest1 INTEGER = .vimon, +
       vtest2 INTEGER = .viday, +
       vtest3 INTEGER = .vsuffix
     IF vtest1 < 10 THEN
      SET VAR vimon TEXT, vaddzero TEXT = '0'
      SET VAR v1 TEXT = (.vaddzero + .vimon)
     ELSE
      SET VAR vimon TEXT
      SET VAR v1 TEXT = .vimon
     ENDIF
     IF vtest2 < 10 THEN
      SET VAR viday TEXT, vaddzero TEXT = '0'
      SET VAR v2 TEXT = (.vaddzero + .viday)
     ELSE
      SET VAR viday TEXT
      SET VAR v2 TEXT = (.viday)
     ENDIF
     IF vtest3 < 10 THEN
      SET VAR vsuffix TEXT, vaddzero TEXT = '.00'
      SET VAR vsuffix2 TEXT = (.vaddzero + .vsuffix)
     ELSE
      IF vsuffix BETWEEN 10 AND 99 THEN
      SET VAR vsuffix TEXT, vaddzero TEXT = '.0'
      SET VAR vsuffix2 TEXT = (.vaddzero + .vsuffix)
      ELSE
      SET VAR vsuffix TEXT, vadddot TEXT = '.'
      SET VAR vsuffix2 TEXT = (.vadddot + .vsuffix)
      ENDIF
     ENDIF
     SET VAR vbackupname = (.vdrive + .viyear + .v1 + .v2 +
     .vsuffix2)
     INSERT INTO backups_done VALUES (.#DATE, .vsuffix,
     .vbackupdr)
     SET NULL -0-
     OUTPUT &vbackupname
     BACKUP ALL
     OUTPUT SCREEN
     *(CLEAR VAR vbackupname, v1, v2, vsuffix, vsuffix2, vimon,
     vlastnumb, +
      viyear, viday, vaddzero, vdrive, vbackupdr, vtest1, vtest2,
     vtest3, +
      vnom_backupdr)
     SET ESCAPE ON
     RETURN
 
     $COMMAND
     hddbu
     CLS FROM 1,1 TO 25,80
     SET VAR vtxtmsg_bu2 TEXT = (.vdbname + '.cpy')
     SET VAR vtxtmsg_bu3 TEXT = 'on the hard disk.'
     SET VAR vtxtmsg_bu4 TEXT = (.vtxtmsg_bu2 & .vtxtmsg_bu3)
     WRITE 'This procedure will backup your database to the file'
     AT 10,10
     WRITE .vtxtmsg_bu4 AT 12,10
     DIALOG 'YES to commence backup, NO to quit:' +
       vrespons_proc vendkey YES AT 18
     IF vendkey = '[ESC]' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
     ENDIF
     IF vrespons_proc = 'NO' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
     ENDIF
     IF vrespons_proc = 'YES' THEN
      CLS FROM 1,1 TO 25,80
      DIALOG 'Press [Enter] or amend file name & press [Enter]:'+
      vtxtmsg_bu2 vendkey 1 AT 16
      IF vendkey = '[Esc]' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
      ENDIF
      CLS FROM 1,1 TO 25,80
      SET ESCAPE OFF
      DISPLAY warnmsge IN dbcopybu.apx
      SET VAR vdriveload TEXT = 'C'
      SET VAR vdrive TEXT = (.vdriveload + ':\')
      SET VAR vdb_lob_file TEXT = (.vdbname + '.lob')
      SET VAR vlastnumb = (.vlastnumb + 1)
      INSERT INTO backups_done VALUES (.#DATE, .vlastnumb,
      .vdriveload)
      DELETE frthlast.cpy
      DELETE frthlast.lob
      RENAME thrdlast.cpy frthlast.cpy
      RENAME thrdlast.lob frthlast.lob
      RENAME scndlast.cpy thrdlast.cpy
      RENAME scndlast.lob thrdlast.lob
      RENAME &vtxtmsg_bu2 scndlast.cpy
      RENAME &vdb_lob_file scndlast.lob
      SET NULL -0-
      OUTPUT &vtxtmsg_bu2
      BACKUP ALL
      OUTPUT SCREEN
      SET ESCAPE ON
      CLS FROM 1,1 TO 25,80
      ELSE
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
     ENDIF
     RETURN
 
     $COMMAND
     cpymydb
     CLS FROM 1,1 TO 25,80
     SET VAR vtxtmsg_cpy1 TEXT = +
       'It must be different from the existing name of'
     SET VAR vtxtmsg_cpy2 TEXT = (.vtxtmsg_cpy1 & .vdbname)
     WRITE 'This procedure will copy your existing database
     files.' AT 10,13
     WRITE 'Please enter the new name to copy the database files
     to.'+
       AT 11,13
     WRITE .vtxtmsg_cpy2 AT 12,13
     WRITE 'and no more than eight characters long starting with a+
     letter.'+
     AT 13,13
     DIALOG 'Enter the new database name:' vresp_dbname = 8
     vendkey 1 AT 16
     IF vendkey = '[ESC]' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
     ENDIF
     SET VAR vrespons_name = (SGET(.vresp_dbname,8,1))
     IF vrespons_name IS NULL THEN
      CLS FROM 1,1 TO 25,80
      WRITE 'No filename specified to copy database to.' AT 8,12
      WRITE 'Procedure terminating and returning control to
     keyboard.' +
        AT 10,12
      PAUSE 1
      BREAK
     ELSE
      CLS FROM 1,1 TO 25,80
      SET ESCAPE OFF
      DISPLAY warnmsge IN dbcopybu.apx
      DISC
      SET VAR vexistfile1 TEXT = (.vdbname + '.rb1'), +
        vexistfile2 TEXT = (.vdbname + '.rb2'), +
        vexistfile3 TEXT = (.vdbname + '.rb3'), +
        vexistfile4 TEXT = (.vdbname + '.rb4')
      SET VAR vnewfile1 TEXT = (.vrespons_name + '.rb1'), +
        vnewfile2 TEXT = (.vrespons_name + '.rb2'), +
        vnewfile3 TEXT = (.vrespons_name + '.rb3'), +
        vnewfile4 TEXT = (.vrespons_name + '.rb4')
      IF vexistfile1 = .vnewfile1 THEN
      CLS FROM 1,1 TO 25,80
      WRITE 'Cannot copy database to the same name!' AT 10,13
      WRITE 'Procedure terminating and returning control to keyboard.' +
        AT 10,13
      BREAK
      ENDIF
      COPY &vexistfile1 &vnewfile1
      COPY &vexistfile2 &vnewfile2
      COPY &vexistfile3 &vnewfile3
      COPY &vexistfile4 &vnewfile4
      DISC
     ENDIF
     CONNECT &vdbname
     RETURN
 
     $COMMAND
     restr_bu
     CLS FROM 1,1 TO 25,80
     WRITE 'DO NOT PROCEED UNLESS YOU ARE CERTAIN OF WHAT YOU ARE DOING!' +
       AT 3,10
     WRITE 'This action will DELETE your existing database and replace' +
       AT 5,10
     WRITE 'it with a copy from a back up file.' AT 6,10
     WRITE 'Please be very certain of the full name and extension
     of the' +
       AT 7,10
     WRITE 'back up file and its drive and path before
     proceeding!' AT 8,10
     WRITE 'If you don't have a back up file and you proceed
     past' AT 9,10
     WRITE 'this point without quitting now, you will erase the
     existing' +
       AT 10,10
     WRITE 'copy of the database and lose all your data!' AT
     11,10
     WRITE 'If you are uncertain of any point either get advice
     from' +
       AT 12,10
     WRITE 'someone who is certain or at least exit this
     procedure now' +
       AT 13,10
     WRITE 'then rename the existing database files and write
     down the' +
      AT 14,10
     WRITE 'exact drive, path and file name of the backup file
     before +
      proceeding.' AT 15,10
     DIALOG 'YES to delete & restore from backup, NO to quit.' +
      vrespons_rest vendkey NO AT 16
     IF vendkey = '[Esc]' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
     ENDIF
     IF vrespons_rest = 'NO' THEN
     CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
      ENDIF
     IF vrespons_rest = 'YES' THEN
      CLS FROM 1,1 TO 25,80
      WRITE 'You need to enter the backup drive, path & file
     name.' AT 3,12
      WRITE 'From the hard disk on a non-networked computer it
      is' AT 5,12
      WRITE 'normally [C:\rb\db\dbname.cpy] where dbname is the'
      AT 6,12
      WRITE 'name of your database.' AT 7,12
      WRITE 'On a network the drive and directory may be
     different.' AT 9,12
      WRITE 'From a diskette it is normally [A:\19951012.001]' AT
      11,12
      WRITE 'being the year, month, day & number of the backup.'
     AT 12,12
      DIALOG 'Enter backup drive, path & filename & press
     [Enter]:' +
      vrespons_drive vendkey AT 16
      CLS FROM 1,1 TO 25,80
      IF vendkey = '[Esc]' THEN
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
      ENDIF
      IF vrespons_drive IS NULL THEN
      WRITE 'No drive specified to contain backup files.' AT 8,12
      WRITE 'Procedure terminating and returning control to
     keyboard.' +
       AT 10,12
      PAUSE 1
      BREAK
      ENDIF
      DISC
      DISPLAY warnmsge IN dbcopybu.apx
      SET VAR vnewfile1 TEXT = (.vdbname + '.rb1')
      SET VAR vnewfile2 TEXT = (.vdbname + '.rb2')
      SET VAR vnewfile3 TEXT = (.vdbname + '.rb3')
      SET VAR vnewfile4 TEXT = (.vdbname + '.rb4')
      ERASE &vnewfile1
      ERASE &vnewfile2
      ERASE &vnewfile3
      ERASE &vnewfile4
      CLS FROM 1,1 TO 25,80
      SET ESCAPE OFF
      DISC
      DISPLAY warnmsge IN dbcopybu.apx
      RESTORE &vrespons_drive
      SET ESCAPE ON
     ENDIF
     CONNECT &vdbname
     *(CLEAR VAR vrespons, vbackupfile, vbackupname,vrespons_drive, +
      vdrive, vdialogtext, vnewfile1, vnewfile2, vnewfile3,
     vnewfile4, +
      vrespons_rest)
     RETURN
 
     $COMMAND
     cpyrelod
     CLS FROM 1,1 TO 25,80
     WRITE 'This action will rename your existing database' AT 4,10
     WRITE 'and reload it back to the original name. In doing' AT 5,10
     WRITE 'this it recovers any space consumed by deleted' AT 6,10
     WRITE 'rows and collects the rows from each table into' AT 7,10
     WRITE 'the same disk area which can speed access times.' AT 8,10
     WRITE 'It is recommended that this procedure be done weekly.' AT 9,10
     WRITE 'AND ONLY IMMEDIATELY AFTER A BACKUP so if there is' AT 10,10
     WRITE 'any interruption and the database is destroyed you' AT 11,10
     WRITE 'can easily restore from a backup with no loss of data.' AT+
      12,10
     DIALOG 'YES to copy & reload, NO to quit.' +
       vrespons_copy vendkey NO AT 14
     IF vendkey = '[Esc]' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
     ENDIF
     IF vrespons_copy = 'NO' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
     ENDIF
     IF vrespons_copy = 'YES' THEN
      CLS FROM 1,1 TO 25,80
      DISCONNECT
      DISPLAY warnmsge IN dbcopybu.apx
      SET VAR voldfile1 TEXT = (.voldname + '.rb1')
      SET VAR voldfile2 TEXT = (.voldname + '.rb2')
      SET VAR voldfile3 TEXT = (.voldname + '.rb3')
      SET VAR voldfile4 TEXT = (.voldname + '.rb4')
      ERASE .voldfile1
      ERASE .voldfile2
      ERASE .voldfile3
      ERASE .voldfile4
      SET VAR vnewfile1 TEXT = (.vdbname + '.rb1')
      SET VAR vnewfile2 TEXT = (.vdbname + '.rb2')
      SET VAR vnewfile3 TEXT = (.vdbname + '.rb3')
      SET VAR vnewfile4 TEXT = (.vdbname + '.rb4')
      RENAME .vnewfile1 .voldfile1
      RENAME .vnewfile2 .voldfile2
      RENAME .vnewfile3 .voldfile3
      RENAME .vnewfile4 .voldfile4
      CONNECT &voldname
      RELOAD &vdbname
      DISCONNECT
      CONNECT &vdbname
     ENDIF
     *(CLEAR VAR vrespons_copy, voldfile1, voldfile2, voldfile3,
     voldfile4, +
      vnewfile1, vnewfile2, vnewfile3, vnewfile4)
     RETURN
 
     $COMMAND
     pckinplc
     CLS FROM 1,1 TO 25,80
     WRITE 'This action will pack your existing database in the
     same' AT 4,10
     WRITE 'location. In doing this it recovers any space
     consumed' AT 5,10
     WRITE 'by deleted rows which can speed access times but does
     not' AT 6,10
     WRITE 'collect the rows of a table to the same disk area. It
     is' AT 7,10
     WRITE 'recommended that this procedure be done weekly.' AT
     8,10
     WRITE 'AND ONLY IMMEDIATELY AFTER A BACKUP so if there is'
     AT 9,10
     WRITE 'any interruption and the database is destroyed you'
     AT 10,10
     WRITE 'can easily restore from a backup with no loss of
     data.' AT 11,10
     DIALOG 'YES to pack, NO to quit.' vrespons_pack vendkey NO
     AT 16
     IF vendkey = '[Esc]' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
     ENDIF
     IF vrespons_pack = 'NO' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY userabor IN dbcopybu.apx
      PAUSE 1
      BREAK
     ENDIF
     IF vrespons_pack = 'YES' THEN
      CLS FROM 1,1 TO 25,80
      DISPLAY warnmsge IN dbcopybu.apx
      CONNECT &vdbname
      PACK &vdbname ALL
      PAUSE 1
     ENDIF
     CLEAR VAR vrespons_pack
     RETURN