home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progbas / qbtree55.arj / XBTREE2.BAS < prev    next >
BASIC Source File  |  1991-07-31  |  14KB  |  410 lines

  1. DECLARE SUB MoveIn (rec$, vseg%, voff%)
  2. DECLARE FUNCTION MoveOut$ (vseg%, voff%, bytes%)
  3. DECLARE FUNCTION Prepare$ (vseg%, voff%, bytes%)
  4. DECLARE FUNCTION OpenXAppFiles% ()
  5. DECLARE FUNCTION BuildXAppFiles% ()
  6. DECLARE FUNCTION ShowXAppFiles% ()
  7. DECLARE FUNCTION CreateXAppFiles% ()
  8.  
  9. DEFINT A-Z
  10. REM $INCLUDE: 'qbtree.bi'
  11.  
  12. 'XBTREE2.BAS - an example application that exercises QBTree.
  13. '(C)1991 Cornel Huth
  14. '31-Jul-1991
  15. '
  16. '------------------------------- DESCRIPTION --------------------------------
  17. '
  18. ' A) Primary key in EMP.DAT is EMP#. For each employee there is one and only
  19. ' one EMP# and for each EMP# there is one and only one employee. Each
  20. ' employee is assigned to a department. EMP.DAT:DEPT#, the foreign key,
  21. ' contains the department number he is assigned to.
  22. '
  23. ' Given an employee number (in EMP.DAT) you can find which department he is
  24. ' assigned. You can also find the name of his manager.
  25. '
  26. '
  27. ' B) Primary key in DEP.DAT is DEPT#. For each department there is one and
  28. ' only one DEPT# and for each DEPT# there is one and only one department.
  29. ' DEP.DAT:MGR#, the foreign key, contains the employee number of that
  30. ' department's manager.
  31. '
  32. ' Given a department number (in DEP.DAT) you can find the name of the
  33. ' manager of that department.
  34. '
  35. '
  36. ' C) Primary key in DEPEMP.DAT is DEP#+EMP#. Since each DEP# is unique and
  37. ' each EMP# is unique, combining the two you get a unique key. The DEP#
  38. ' portion of the key groups all EMP#'s in DEP# together allowing you to get
  39. ' all EMP#'s in a particular DEP#.
  40. '
  41. ' Given a department number (in DEPEMP.DAT) you can find all employees in
  42. ' that department. To get a unique primary key, the employee number is
  43. ' combined with the department number. With QBTREE you can specify a
  44. ' partial key (in this case just DEPT# with an EMP# of 0) and QBTREE will
  45. ' return the first DEPT#+EMP#. Using GetNext() you continue processing
  46. ' this until the DEPT# portion changes.
  47. '
  48. '
  49. '  ====  Primary key (field used to index this file)
  50. '                                            
  51. '  ----  Foreign key (field used to connect to another file's primary key)
  52. '                                           
  53. '  ≡≡≡≡  Used as both primary and foreign key
  54. '
  55. '                                               C) DEPEMP.DAT RECORD*
  56. '                                                  ┌───────┬──────┐
  57. '   ┌────────────────────────────────────┐         │ DEPT# │ EMP# │
  58. '   │                                    │         │ ===== │ ≡≡≡≡ │
  59. '     A) EMP.DAT RECORD                 │         └───────┴──────┘
  60. '┌──────┬───────────────┬────────┬────┐  └────────────────────┘
  61. '│ EMP# │ EMPLOYEE NAME │ DEPT#  │ WG │
  62. '│ ==== │               │ -----  │    │     B) DEP.DAT RECORD
  63. '└──────┴───────────────┴────────┴────┘   ┌───────┬───────────┬──────┐
  64. '                          │             │ DEPT# │ DEPT NAME │ MGR# │
  65. '   │                       └─────────── │ ====  │           │ ---- │
  66. '   │                                     └───────┴───────────┴──────┘
  67. '   │                                                            │
  68. '   └────────────────────────────────────────────────────────────┘
  69. '
  70. ' Example datafile contents:
  71. '
  72. '            EMP.DAT                  DEP.DAT        DEPEMP.DAT*
  73. '  EMP# EMPLOYEE NAME   D# WG    D# DEPT NAME  MGR#    D# EMP#
  74. '  ---- --------------- -- --    -- ---------- ----    -- ----
  75. '  1001 Frank Haas      12 15    10 Purchasing 1002    10 1002
  76. '  1002 Wendy Gibson    10 15    11 Accounting 2173    11 2173
  77. '  1125 Willie McAffee  14  9    12 Legal      1001    12 1001
  78. '  1507 David Robinson  13  9    13 MIS        1507    13 1507
  79. '  2173 Jackie Stewart  11 17    14 Personnel  1125    14 1125
  80. '  ... and so on                 ... and so on         ... and so on
  81. '
  82. ' * DEPEMP.DAT carries no information other than the DEP# in DEP.DAT
  83. ' and the EMP# in EMP.DAT. This means we do not need to carry a data
  84. ' file for the DEPEMP information. What is listed in this description
  85. ' as DEPEMP.DAT will actually be the index file itself (DEPEMP.NDX).
  86. '----------------------------------------------------------------------------
  87. '
  88. ' This program will output to the screen two logical tables. Table 1, the
  89. ' BY EMPLOYEE table, will have the employee's number, name, wage grade,
  90. ' department, and manager. Table 2, the BY DEPARTMENT table, will have a list of
  91. ' employees in each department.
  92. '
  93. '============================================================================
  94.  
  95. ' QBTREE file number equates
  96. CONST EMPdf = 0         'EMP.DAT QBTREE data file number
  97. CONST DEPdf = 1         'DEP.DAT
  98. CONST MDF = 1           'max data files needed (last data file number)
  99.  
  100. CONST EMPif = 0         'EMP.NDX QBTREE index file number
  101. CONST DEPif = 1         'DEP.NDX
  102. CONST DEPEMPif = 2      'DEPEMP.NDX
  103. CONST MKF = 2           'max key files needed (last key file number)
  104.  
  105. CONST ASMODE = 2        'files opened in compatiblity mode
  106.  
  107. ' Employee data record type
  108. TYPE EmpDataTYPE
  109. Number AS STRING * 4
  110. zName AS STRING * 15
  111. DeptNo AS STRING * 2
  112. WG AS INTEGER
  113. END TYPE '23
  114. DIM SHARED EMP AS EmpDataTYPE
  115.  
  116. ' Department data record type
  117. TYPE DepDataTYPE
  118. Number AS STRING * 2
  119. zName AS STRING * 10
  120. MgrNo AS STRING * 4
  121. END TYPE '16
  122. DIM SHARED DEP AS DepDataTYPE
  123.  
  124. 'size FixedStr to largest TYPE structure used in QBTREE access
  125. DIM SHARED FixedStr AS STRING * 23
  126.  
  127. DIM SHARED XEmpData$
  128. DIM SHARED XDepData$
  129. DIM SHARED XEmpIndex$
  130. DIM SHARED XDepIndex$
  131. DIM SHARED XDepEmpIndex$
  132.  
  133. ' We'll create 3 key files and 2 data files using the info from the
  134. ' DATA statements below. Once built we'll show two tables based on the data
  135.  
  136. CLS
  137. stat = InitQBTREE(MKF, MDF)
  138. IF stat = 0 THEN
  139.    stat = CreateXAppFiles
  140.    IF stat = 0 THEN
  141.       stat = OpenXAppFiles
  142.       IF stat = 0 THEN
  143.          stat = BuildXAppFiles
  144.          IF stat = 0 THEN
  145.             stat = ShowXAppFiles
  146.             IF stat THEN
  147.                PRINT "Error"; stat; "from ShowXAppFiles"
  148.             END IF
  149.          ELSE
  150.             PRINT "Error"; stat; "from BuildXAppFiles"
  151.          END IF
  152.       ELSE
  153.          PRINT "Error"; stat; "from OpenXAppFiles"
  154.       END IF
  155.    ELSE
  156.       PRINT "Error"; stat; "from CreateXAppFiles"
  157.    END IF
  158. ELSE
  159.    PRINT "Error"; stat; "from InitQBTREE"
  160. END IF
  161. nul = ExitQBTREE
  162. END
  163.  
  164.  
  165. ' We'll use DATA statements to simplify getting the initial data
  166.  
  167. ' XApp employee data
  168. EmpData:
  169. DATA 11
  170. DATA 1001,Frank Hass,12,15
  171. DATA 1002,Wendy Gibson,10,15
  172. DATA 1125,Willie McAffee,14,9
  173. DATA 1507,David Robinson,13,9
  174. DATA 1173,Jackie Stewart,11,17
  175. DATA 4105,Beatrice South,10,5
  176. DATA 4288,Jim Davies,10,5
  177. DATA 4901,Tom Cassidy,14,4
  178. DATA 3149,Nancy Cannon,13,7
  179. DATA 3510,John Madison,12,12
  180. DATA 3685,Chris Ho,13,9
  181.  
  182. ' XApp department data
  183. DepData:
  184. DATA 5
  185. DATA 10,Purchasing,1002
  186. DATA 11,Accounting,1173
  187. DATA 12,Legal,1001
  188. DATA 13,MIS,1507
  189. DATA 14,Personnel,1125
  190.  
  191. FUNCTION BuildXAppFiles
  192.  
  193. 'using the info in the DATA statements build the XApp files
  194.  
  195. PRINT "Building employee data and index files...";
  196. RESTORE EmpData
  197. READ EmpRecs
  198. FOR i = 1 TO EmpRecs
  199.    READ EMP.Number, EMP.zName, EMP.DeptNo, EMP.WG
  200.    key$ = EMP.Number
  201.    rec$ = MoveOut$(VARSEG(EMP), VARPTR(EMP), LEN(EMP))
  202.    stat = AddKeyRecord(EMPif, EMPdf, key$, rec$)
  203.    IF stat THEN EXIT FOR
  204. NEXT
  205. IF stat = 0 THEN
  206.    PRINT "ok."
  207.    PRINT "Building department data and index files...";
  208.    RESTORE DepData
  209.    READ DepRecs
  210.    FOR i = 1 TO DepRecs
  211.       READ DEP.Number, DEP.zName, DEP.MgrNo
  212.       key$ = DEP.Number
  213.       rec$ = MoveOut$(VARSEG(DEP), VARPTR(DEP), LEN(DEP))
  214.       stat = AddKeyRecord(DEPif, DEPdf, key$, rec$)
  215.       IF stat THEN EXIT FOR
  216.    NEXT
  217.    IF stat = 0 THEN
  218.       PRINT "ok."
  219.       PRINT "Building department+employee index file...";
  220.  
  221.       ' to build this index file we use the employee file just built.
  222.       ' a shortcoming of this is that departments with no employees
  223.       ' (unlikely) assigned will not be represented in the index file.
  224.  
  225.       recno& = 0 'we won't be needing data record pointers for StoreKey()
  226.  
  227.       stat = GetFirst(EMPif, EMPdf, key$, rec$)
  228.       DO WHILE stat = 0
  229.  
  230.          'rec$ contains employee data record info, move it to EMP structure
  231.          MoveIn rec$, VARSEG(EMP), VARPTR(EMP)
  232.  
  233.          'EMP.DeptNo and EMP.Number are string so we can forego MoveOut$()
  234.          key$ = EMP.DeptNo + EMP.Number
  235.          
  236.          stat = StoreKey(DEPEMPif, key$, recno&)
  237.          IF stat = 0 THEN stat = GetNext(EMPif, EMPdf, key$, rec$)
  238.       LOOP
  239.       IF stat = 202 THEN stat = 0  'End of file is expected
  240.       IF stat = 0 THEN PRINT "ok."
  241.  
  242.    END IF
  243. END IF
  244. BuildXApp = stat
  245.  
  246. END FUNCTION
  247.  
  248. FUNCTION CreateXAppFiles
  249.  
  250. ' Create the XApp files. If they already exist delete them first.
  251.  
  252. PRINT "Creating XApp Files...";
  253.  
  254. XEmpData$ = "EMP.DAT"
  255. XDepData$ = "DEP.DAT"
  256. XEmpIndex$ = "EMP.NDX"
  257. XDepIndex$ = "DEP.NDX"
  258. XDepEmpIndex$ = "DEPEMP.NDX"
  259.  
  260. IF FileExists(XEmpData$) = -1 THEN KILL XEmpData$
  261. IF FileExists(XDepData$) = -1 THEN KILL XDepData$
  262. IF FileExists(XEmpIndex$) = -1 THEN KILL XEmpIndex$
  263. IF FileExists(XDepIndex$) = -1 THEN KILL XDepIndex$
  264. IF FileExists(XDepEmpIndex$) = -1 THEN KILL XDepEmpIndex$
  265.  
  266. stat = CreateDataFile(XEmpData$, LEN(EMP))
  267. IF stat = 0 THEN stat = CreateDataFile(XDepData$, LEN(DEP))
  268. IF stat = 0 THEN stat = CreateKeyFile(XEmpIndex$, LEN(EMP.Number))
  269. IF stat = 0 THEN stat = CreateKeyFile(XDepIndex$, LEN(DEP.Number))
  270. IF stat = 0 THEN stat = CreateKeyFile(XDepEmpIndex$, LEN(EMP.Number) + LEN(DEP.Number))
  271.  
  272. IF stat = 0 THEN PRINT "ok."
  273. CreateXAppFiles = stat
  274.  
  275. END FUNCTION
  276.  
  277. SUB MoveIn (rec$, vseg, voff)
  278.  
  279. ' copy the variable-length string data from rec$ (which may contain
  280. ' non-string data) to the TYPEd structure pointed to by vseg:voff.
  281. ' See MoveOut$() for more.
  282.  
  283. FixedStr = rec$
  284. MemCopy VARSEG(FixedStr), VARPTR(FixedStr), vseg, voff, LEN(rec$)
  285.  
  286. END SUB
  287.  
  288. FUNCTION MoveOut$ (vseg, voff, bytes)
  289.  
  290. ' copy the data from the TYPEd structure pointed to by vseg:voff
  291. ' to a fixed-length string. We use a fixed-length string so that
  292. ' we don't need to concern ourselves with being both QB4 and PDS /Fs
  293. ' compatible. Simple fixed-length strings are in DGROUP for both
  294. ' QB and QBX. Note: FixedStr needs to be sized to at least the largest
  295. ' TYPE structure size (23 bytes for XEmpData).
  296.  
  297. 'IF bytes > LEN(FixedStr) THEN STOP  'useful in debugging stage
  298.  
  299. MemCopy vseg, voff, VARSEG(FixedStr), VARPTR(FixedStr), bytes
  300. MoveOut$ = LEFT$(FixedStr, bytes)
  301.  
  302. END FUNCTION
  303.  
  304. FUNCTION OpenXAppFiles
  305.  
  306. PRINT "Opening XApp Files...";
  307.  
  308. stat = OpenDataFile(XEmpData$, EMPdf, ASMODE)
  309. IF stat = 0 THEN stat = OpenDataFile(XDepData$, DEPdf, ASMODE)
  310. IF stat = 0 THEN stat = OpenKeyFile(XEmpIndex$, EMPif, ASMODE)
  311. IF stat = 0 THEN stat = OpenKeyFile(XDepIndex$, DEPif, ASMODE)
  312. IF stat = 0 THEN stat = OpenKeyFile(XDepEmpIndex$, DEPEMPif, ASMODE)
  313.  
  314. IF stat = 0 THEN PRINT "ok."
  315. OpenXAppFiles = stat
  316.  
  317. END FUNCTION
  318.  
  319. FUNCTION ShowXAppFiles
  320.  
  321. CLS
  322. PRINT "****************** BY EMPLOYEE ********************"
  323. PRINT
  324. PRINT "EMP#     EMPLOYEE      GRADE  DEPARTMENT       MANAGER"
  325. PRINT "----  ---------------   ---   ----------   ---------------"
  326.  
  327. ' get the first employee's info
  328. stat = GetFirst(EMPif, EMPdf, key$, rec$)
  329. DO WHILE stat = 0
  330.  
  331.    ' move the employee record data to the EMP structure
  332.    MoveIn rec$, VARSEG(EMP), VARPTR(EMP)
  333.    LastKey$ = EMP.Number
  334.    PRINT EMP.Number;
  335.    LOCATE , 7: PRINT EMP.zName;
  336.    t$ = SPACE$(3)
  337.    RSET t$ = STR$(EMP.WG)       'right-align wage grade
  338.    LOCATE , 24: PRINT t$;
  339.  
  340.    ' go get the department info for this employee
  341.    stat = GetEqual(DEPif, DEPdf, EMP.DeptNo, rec$)
  342.    IF stat = 0 THEN
  343.  
  344.       ' move department record data to the DEP structure
  345.       MoveIn rec$, VARSEG(DEP), VARPTR(DEP)
  346.       LOCATE , 31: PRINT DEP.zName;
  347.  
  348.       ' go get the manager's name
  349.       stat = GetEqual(EMPif, EMPdf, DEP.MgrNo, rec$)
  350.       IF stat = 0 THEN
  351.          
  352.           ' move manager's record data to EMP structure (he is an employee)
  353.           MoveIn rec$, VARSEG(EMP), VARPTR(EMP)
  354.           LOCATE , 44: PRINT EMP.zName
  355.       END IF
  356.  
  357.       ' we need to reposition to the last employee (getting the manager's
  358.       ' name messed things up a bit) and then get the next employee
  359.       stat = GetEqual(EMPif, EMPdf, LastKey$, rec$)
  360.       IF stat = 0 THEN stat = GetNext(EMPif, EMPdf, key$, rec$)
  361.  
  362.    END IF
  363. LOOP
  364. IF stat = 202 THEN stat = 0
  365.  
  366. IF stat = 0 THEN
  367.    PRINT
  368.    PRINT "******************************** BY DEPARTMENT *******************************"
  369.    PRINT
  370.    PRINT "  Purchasing      Accounting         Legal           MIS          Personnel"
  371.    PRINT "--------------- --------------- --------------- -------------- ---------------"
  372.    p10 = CSRLIN: p11 = p10: p12 = p10: p13 = p10: p14 = p10
  373.  
  374.    stat = RetrieveFirst(DEPEMPif, key$, recno&)
  375.    DO WHILE stat = 0
  376.  
  377.       ' we know that the EMP# is bytes 3-6 of the key so
  378.       ' get the name of this EMP# (DEP# is bytes 1-2)
  379.       Dept$ = LEFT$(key$, 2)
  380.       Ekey$ = MID$(key$, 3, 4)
  381.       stat = GetEqual(EMPif, EMPdf, Ekey$, Erec$)
  382.       MoveIn Erec$, VARSEG(EMP), VARPTR(EMP)
  383.       
  384.       SELECT CASE Dept$
  385.       CASE "10"
  386.          LOCATE p10, 1
  387.          p10 = p10 + 1
  388.       CASE "11"
  389.          LOCATE p11, 17
  390.          p11 = p11 + 1
  391.       CASE "12"
  392.          LOCATE p12, 33
  393.          p12 = p12 + 1
  394.       CASE "13"
  395.          LOCATE p13, 49
  396.          p13 = p13 + 1
  397.       CASE "14"
  398.          LOCATE p14, 64
  399.          p14 = p14 + 1
  400.       CASE ELSE
  401.       END SELECT
  402.       PRINT EMP.zName
  403.  
  404.       stat = RetrieveNext(DEPEMPif, key$, recno&)
  405.    LOOP
  406. END IF
  407.  
  408. END FUNCTION
  409.  
  410.