UNIX and VMS--The Professor-Student Mixed Form Application
This EQUEL/FORMS application lets the user browse and update information about graduate students who report to a specific professor. The program is structured in a master/detail fashion, with the professor being the master entry, and the students the detail entries. The application uses two forms--one to contain general professor information and another for detailed student information.
The application uses the following objects:
The program uses the masterfrm as the general-level master entry, in which data can only be retrieved and browsed, and the studentfrm as the detailed screen, in which specific student information can be updated.
The runtime user enters a name in the pname (professor name) field and then selects the Students menu operation. The operation fills the displayed and hidden columns of the studenttbl table field with detailed information of the students reporting to the named professor. The user may then browse the table field (in read mode), which displays only the names and ages of the students. More information about a specific student may be requested by selecting the Zoom menu operation. This operation displays the studentfrm form. The fields of studentfrm are filled with values stored in the hidden columns of studenttbl. The user may make changes to three fields (sgpa, scomment, and sadvisor). If validated, these changes will be written back to the database table (based on the unique student id), and to the table field's data set. This process can be repeated for different professor names.
For readability, all EQUEL reserved words are in uppercase.
UNIX: The following two create statements describe the Professor and Student database tables:
## CREATE student /* Graduate student table */
## (sname = c25, /* Name */
## sage = i1, /* Age */
## sbdate = c25, /* Birth date */
## sgpa = f4, /* Grade point average */
## sidno = i4, /* Unique student number */
## scomment = text(200), /* General comments */
## sadvisor = c25) /* Advisor's name */
## CREATE professor /* Professor table */
## (pname = c25, /* Professor's name */
## pdept = c10) /* Department */
IDENTIFICATION DIVISION.
PROGRAM-ID. STUDENT-ADMINISTRATOR.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
## DECLARE
* Global grad student record maps to database table
## 01 GRAD.
## 02 SNAME PIC X(25).
## 02 SAGE PIC S9(4) USAGE COMP.
## 02 SBDATE PIC X(25).
## 02 SGPA PIC S9(3)V9(2) USAGE COMP.
## 02 SIDNO PIC S9(9) USAGE COMP.
## 02 SCOMMENT PIC X(200).
## 02 SADVISOR PIC X(25).
* Professor info maps to database table
## 01 PROF.
## 02 PNAME PIC X(25).
## 02 PDEPT PIC X(10).
* Row number of last row in student table field
## 01 LASTROW PIC S9(9) USAGE COMP.
* Is user on a table field?
## 01 ISTABLE PIC S9 USAGE COMP.
* Were changes made to data in student form?
## 01 CHANGED-DATA PIC S9 USAGE COMP.
* Did user enter a valid advisor name?
## 01 VALID-ADVISOR PIC S9 USAGE COMP.
* Studentfrm loaded?
## 01 LOADFORM PIC S9 USAGE COMP VALUE IS 0.
* Local utility buffers
## 01 MSGBUF PIC X(100).
## 01 RESPBUF PIC X.
## 01 OLD-ADVISOR PIC X(25).
* Compiled forms are not yet accepted as EXTERNAL due
* to restrictions noted in the chapter that
* describes how to link the RTS with compiled forms.
* Consequently the declarations of external form
* objects and the corresponding ADDFORM statement
* have been commented out and replaced by a CALL
* "add_formname" statement.
* ## 01 masterfrm PIC S9(9) USAGE COMP-5 IS EXTERNAL.
* ## 01 studentfrm PIC S9(9) USAGE COMP-5 IS EXTERNAL.
**
* Procedure Division: STUDENT-ADMINISTRATOR
*
* Start up program, Ingres, and the FORMS system and * call Master driver.
**
PROCEDURE DIVISION.
EXAMPLE SECTION.
XBEGIN.
## FORMS
## MESSAGE "Initializing Student Administrator . . ."
## INGRES "personnel"
## RANGE OF p IS professor, s IS student
PERFORM MASTER THROUGH END-MASTER.
## CLEAR SCREEN
## ENDFORMS
## EXIT
STOP RUN.
**
* Paragraph: MASTER
*
* Drive the application, by running "masterfrm", and
* allowing the user to "zoom" into a selected student.
**
MASTER.
* ## ADDFORM masterfrm
CALL "add_masterfrm".
* Initialize "studenttbl" with a data set in READ mode.
* Declare hidden columns for all the extra fields that
* the program will display when more information is
* requested about a student.
* Columns "sname" and "sage" are displayed, all other
* columns are hidden, to be used in the student
* information form.
## INITTABLE #masterfrm studenttbl READ
## (#SBDATE = CHAR(25),
## #SGPA = FLOAT,
## #SIDNO = INTEGER,
## #SCOMMENT = CHAR(200),
## #SADVISOR = CHAR(20))
## DISPLAY #masterfrm UPDATE
## INITIALIZE
## {
## MESSAGE "Enter an Advisor name . . ."
## SLEEP 2
## }
## ACTIVATE MENUITEM "Students", FIELD "pname"
## {
* Load the students of the specified professor
## GETFORM (PNAME = #pname)
* If no professor name is given then resume
IF PNAME = SPACES THEN
## RESUME FIELD #pname
END-IF.
* Verify the professor exists. Local error handling just
* prints the message, and continues. We assume that each
* professor has exactly one department.
MOVE SPACES TO PDEPT.
## RETRIEVE (PDEPT = p.#pdept, PNAME = p.#pname)
## WHERE p.#pname = PNAME
IF PDEPT = SPACES THEN
MOVE SPACES TO MSGBUF
STRING "No professor with name """
DELIMITED BY SIZE,
PNAME DELIMITED BY " ",
""" [RETURN]" DELIMITED BY SIZE
INTO MSGBUF
## PROMPT NOECHO (MSGBUF, RESPBUF)
## RESUME FIELD #pname
END-IF.
* Fill the department field and load students
## PUTFORM (#pdept = PDEPT, #pname = PNAME)
* Refresh for query
## REDISPLAY
PERFORM LOAD-STUDENTS THROUGH END-LOAD.
## RESUME FIELD studenttbl
## }
## ACTIVATE MENUITEM "Zoom"
## {
* Confirm that user is on "studenttbl", and that the
* table field is not empty. Collect data from the
* row and zoom for browsing and updating.
## INQUIRE_FRS FIELD #masterfrm (ISTABLE = table)
IF ISTABLE = 0 THEN
## PROMPT NOECHO
## ("Select from the student table [RETURN]",
## RESPBUF)
## RESUME FIELD studenttbl
END-IF.
## INQUIRE_FRS TABLE #masterfrm (LASTROW = lastrow)
IF LASTROW = 0 THEN
## PROMPT NOECHO ("There are no students [RETURN]",
## RESPBUF)
## RESUME FIELD #pname
END-IF.
* Collect all data on student into global record
## GETROW #masterfrm studenttbl
## (SNAME = #sname,
## SAGE = #sage,
## SBDATE = #sbdate,
## SGPA = #sgpa,
## SIDNO = #sidno,
## SCOMMENT = #scomment,
## SADVISOR = #sadvisor)
* Display "studentfrm", and if any changes were made make
* the updates to the local table field row. Only make
* updates to the columns corresponding to writable fields
* in "studentfrm". If the student changed advisors, then
* delete this row from the display.
MOVE SADVISOR TO OLD-ADVISOR.
PERFORM STUDENT-INFO-CHANGED THROUGH END-STUDENT.
IF CHANGED-DATA = 1 THEN
IF OLD-ADVISOR NOT = SADVISOR THEN
## DELETEROW #masterfrm studenttbl
ELSE
## PUTROW #masterfrm studenttbl
## (#sgpa = SGPA,
## #scomment = SCOMMENT,
## #sadvisor = SADVISOR)
END-IF
END-IF.
## }
## ACTIVATE MENUITEM "Quit", FRSKEY2
## {
## BREAKDISPLAY
## }
## FINALIZE
END-MASTER.
EXIT.
**
* Paragraph: LOAD-STUDENTS
*
* For the current professor name, this paragraph loads
* into the "studenttbl" table field all the students
* whose advisor is the professor with that name.
**
LOAD-STUDENTS.
## MESSAGE "Retrieving Student Information . . ."
## CLEAR FIELD studenttbl
## RETRIEVE (SNAME = s.#sname,
## SAGE = s.#sage,
## SBDATE = s.#sbdate,
## SGPA = s.#sgpa,
## SIDNO = s.#sidno,
## SCOMMENT = s.#scomment,
## SADVISOR = s.#sadvisor)
## WHERE s.#sadvisor = PNAME
## {
## LOADTABLE #masterfrm studenttbl
## (#sname = SNAME,
## #sage = SAGE,
## #sbdate = SBDATE,
## #sgpa = SGPA,
## #sidno = SIDNO,
## #scomment = SCOMMENT,
## #sadvisor = SADVISOR)
## }
END-LOAD.
EXIT.
**
* Paragraph: STUDENT-INFO-CHANGED
*
* Allow the user to zoom into the details of a selected
* student. Some of the data can be updated by the user.
* If any updates were made, then reflect these back into
* the database table. The paragraph records whether or not
* changes were made via the CHANGED-DATA variable. **
STUDENT-INFO-CHANGED.
* Control ADDFORM to only initialize once
IF LOADFORM = 0 THEN
## MESSAGE "Loading Student form . . ."
* ## ADDFORM studentfrm
CALL "add_studentfrm"
MOVE 1 TO LOADFORM
END-IF.
## DISPLAY #studentfrm FILL
## INITIALIZE (#sname = SNAME,
## #sage = SAGE,
## #sbdate = SBDATE,
## #sgpa = SGPA,
## #sidno = SIDNO,
## #scomment = SCOMMENT,
## #sadvisor = SADVISOR)
## ACTIVATE MENUITEM "Write", FRSKEY4
## {
* If changes were made then update the database table.
* Only bother with the fields that are not read-only.
## INQUIRE_FRS form (CHANGED-DATA = change)
IF CHANGED-DATA = 0 THEN
## BREAKDISPLAY
END-IF.
## VALIDATE
## MESSAGE "Writing changes to database. . ."
## GETFORM (SGPA = #sgpa,
## SCOMMENT = #scomment,
## SADVISOR = #sadvisor)
* Enforce integrity of professor name.
MOVE 0 TO VALID-ADVISOR
## RETRIEVE (VALID-ADVISOR = 1)
## WHERE p.#pname = SADVISOR
IF VALID-ADVISOR = 0 THEN
## MESSAGE "Not a valid advisor name"
## SLEEP 2
## RESUME FIELD #sadvisor
ELSE
## REPLACE s (#sgpa = SGPA, #scomment = SCOMMENT,
## #sadvisor = SADVISOR)
## WHERE s.#sidno = SIDNO
## BREAKDISPLAY
END-IF.
## }
## ACTIVATE MENUITEM "End", FRSKEY3
## {
* Quit without submitting changes
MOVE 0 TO CHANGED-DATA.
## BREAKDISPLAY
## }
## FINALIZE
END-STUDENT.
EXIT.
VMS: The following two create statements describe the Professor and Student database tables.
## CREATE student /* Graduate student table */
## (sname = c25, /* Name */
## sage = i1, /* Age */
## sbdate = c25, /* Birth date */
## sgpa = f4, /* Grade point average */
## sidno = i4, /* Unique student number */
## scomment = text(200), /* General comments */
## sadvisor = c25) /* Advisor's name */
## CREATE professor /* Professor table */
## (pname = c25, /* Professor's name */
## pdept = c10) /* Department */
IDENTIFICATION DIVISION.
PROGRAM-ID. STUDENT-ADMINISTRATOR.
ENVIRONMENT DIVISION.
DATA DIVISION.
WORKING-STORAGE SECTION.
## DECLARE
* Global grad student record maps to database table
## 01 GRAD.
## 02 SNAME PIC X(25).
## 02 SAGE PIC S9(4) USAGE COMP.
## 02 SBDATE PIC X(25).
## 02 SGPA USAGE COMP-1.
## 02 SIDNO PIC S9(9) USAGE COMP.
## 02 SCOMMENT PIC X(200).
## 02 SADVISOR PIC X(25).
* Professor info maps to database table
## 01 PROF.
## 02 PNAME PIC X(25).
## 02 PDEPT PIC X(10).
* Row number of last row in student table field
## 01 LASTROW PIC S9(9) USAGE COMP.
* Is user on a table field?
## 01 ISTABLE PIC S9 USAGE COMP.
* Were changes made to data in student form?
## 01 CHANGED PIC S9 USAGE COMP.
* Did user enter a valid advisor name?
## 01 VALID-ADVISOR PIC S9 USAGE COMP.
* Studentfrm loaded?
## 01 LOADFORM PIC S9 USAGE COMP VALUE IS 0.
* Local utility buffers
## 01 MSGBUF PIC X(100).
## 01 RESPBUF PIC X.
## 01 OLD-ADVISOR PIC X(25).
* Externally compiled forms
## 01 MASTERF PIC S9(9) USAGE COMP VALUE EXTERNAL Masterfrm.
## 01 STUDENTF PIC S9(9) USAGE COMP VALUE EXTERNAL Studentfrm.
**
* Procedure Division: STUDENT-ADMINISTRATOR
*
* Start up program, Ingres, and the FORMS system and
* call Master driver.
**
PROCEDURE DIVISION.
SBEGIN.
## FORMS
## MESSAGE "Initializing Student Administrator . . ."
## INGRES "personnel"
## RANGE OF p IS professor, s IS student
PERFORM MASTER THROUGH END-MASTER.
## CLEAR SCREEN
## ENDFORMS
## EXIT
STOP RUN.
**
* Paragraph: MASTER
*
* Drive the application, by running "masterfrm", and
* allowing the user to "zoom" into a selected student.
**
MASTER.
## ADDFORM MASTERF
* Initialize "studenttbl" with a data set in READ mode.
* Declare hidden columns for all the extra fields that the
* program will display when more information is requested about
* a student. Columns "sname" and "sage" are displayed, all
* other columns are hidden, to be used in the student information
* form.
## INITTABLE #masterfrm studenttbl READ
## (#SBDATE = CHAR(25),
## #SGPA = FLOAT,
## #SIDNO = INTEGER,
## #SCOMMENT = CHAR(200),
## #SADVISOR = CHAR(20))
## DISPLAY #masterfrm UPDATE
## INITIALIZE
## {
## MESSAGE "Enter an Advisor name . . ."
## SLEEP 2
## }
## ACTIVATE MENUITEM "Students", FIELD "pname"
## {
* Load the students of the specified professor
## GETFORM (PNAME = #pname)
* If no professor name is given then resume
IF PNAME = "" THEN
## RESUME FIELD #pname
END-IF.
* Verify the professor exists. Local error handling just prints
* the message, and continues. We assume that each professor has
* exactly one department.
MOVE "" TO PDEPT.
## RETRIEVE (PDEPT = p.#pdept, PNAME = p.#pname)
## WHERE p.#pname = PNAME
IF PDEPT = "" THEN
MOVE "" TO MSGBUF
STRING "No professor with name """ DELIMITED BY SIZE,
PNAME DELIMITED BY " ",
""" [RETURN]" DELIMITED BY SIZE
INTO MSGBUF
## PROMPT NOECHO (MSGBUF, RESPBUF)
## CLEAR FIELD ALL
## RESUME FIELD #pname
END-IF.
* Fill the department field and load students
## PUTFORM (#pdept = PDEPT, #pname = PNAME)
* Refresh for query
## REDISPLAY
PERFORM LOAD-STUDENTS THROUGH END-LOAD.
## RESUME FIELD studenttbl
## }
## ACTIVATE MENUITEM "Zoom"
## {
* Confirm that user is on "studenttbl", and that the table
* field is not empty. Collect data from the row and zoom
* for browsing and updating.
## INQUIRE_FRS FIELD #masterfrm (ISTABLE = table)
IF ISTABLE = 0 THEN
## PROMPT NOECHO
## ("Select from the student table [RETURN]",
## RESPBUF)
## RESUME FIELD studenttbl
END-IF.
## INQUIRE_FRS TABLE #masterfrm (LASTROW = lastrow)
IF LASTROW = 0 THEN
## PROMPT NOECHO ("There are no students [RETURN]",
## RESPBUF)
## RESUME FIELD #pname
END-IF.
* Collect all data on student into global record
## GETROW #masterfrm studenttbl
## (SNAME = #sname,
## SAGE = #sage,
## SBDATE = #sbdate,
## SGPA = #sgpa,
## SIDNO = #sidno,
## SCOMMENT = #scomment,
## SADVISOR = #sadvisor)
* Display "studentfrm", and if any changes were made make the
* updates to the local table field row. Only make updates to the
* columns corresponding to writable fields in "studentfrm". If
* the student changed advisors, then delete this row from
* the display.
MOVE SADVISOR TO OLD-ADVISOR.
PERFORM STUDENT-INFO-CHANGED THROUGH END-STUDENT.
IF CHANGED = 1 THEN
IF OLD-ADVISOR NOT = SADVISOR THEN
## DELETEROW #masterfrm studenttbl
ELSE
## PUTROW #masterfrm studenttbl
## (#sgpa = SGPA,
## #scomment = SCOMMENT,
## #sadvisor = SADVISOR)
END-IF
END-IF.
## }
## ACTIVATE MENUITEM "Quit", FRSKEY2
## {
## BREAKDISPLAY
## }
## FINALIZE
END-MASTER.
**
* Paragraph: LOAD-STUDENTS
*
* For the current professor name, this paragraph loads into the
* "studenttbl" table field all the students whose advisor is
* the professor with that name.
**
LOAD-STUDENTS.
## MESSAGE "Retrieving Student Information . . ."
## CLEAR FIELD studenttbl
## RETRIEVE (
## SNAME = s.#sname,
## SAGE = s.#sage,
## SBDATE = s.#sbdate,
## SGPA = s.#sgpa,
## SIDNO = s.#sidno,
## SCOMMENT = s.#scomment,
## SADVISOR = s.#sadvisor)
## WHERE s.#sadvisor = PNAME
## {
## LOADTABLE #masterfrm studenttbl
## (#sname = SNAME,
## #sage = SAGE,
## #sbdate = SBDATE,
## #sgpa = SGPA,
## #sidno = SIDNO,
## #scomment = SCOMMENT,
## #sadvisor = SADVISOR)
## }
END-LOAD.
**
* Paragraph: STUDENT-INFO-CHANGED
*
* Allow the user to zoom into the details of a selected
* student. Some of the data can be updated by the user.
* If any updates were made, then reflect these back into
* the database table. The paragraph records whether or not
* changes were made via the CHANGED variable.
**
STUDENT-INFO-CHANGED.
* Control ADDFORM to only initialize once
IF LOADFORM = 0 THEN
## MESSAGE "Loading Student form . . ."
## ADDFORM STUDENTF
MOVE 1 TO LOADFORM
END-IF.
## DISPLAY #studentfrm FILL
## INITIALIZE
## (#sname = SNAME,
## #sage = SAGE,
## #sbdate = SBDATE,
## #sgpa = SGPA,
## #sidno = SIDNO,
## #scomment = SCOMMENT,
## #sadvisor = SADVISOR)
## ACTIVATE MENUITEM "Write", FRSKEY4
## {
* If changes were made then update the database table. Only
* bother with the fields that are not read-only.
## INQUIRE_FRS form (CHANGED = change)
IF CHANGED = 0 THEN
## BREAKDISPLAY
END-IF.
## VALIDATE
## MESSAGE "Writing changes to database. . ."
## GETFORM
## (SGPA = #sgpa,
## SCOMMENT = #scomment,
## SADVISOR = #sadvisor)
* Enforce integrity of professor name.
MOVE 0 TO VALID-ADVISOR
## RETRIEVE (VALID-ADVISOR = 1)
## WHERE p.#pname = SADVISOR
IF VALID-ADVISOR = 0 THEN
## MESSAGE "Not a valid advisor name"
## SLEEP 2
## RESUME FIELD #sadvisor
ELSE
## REPLACE s (#sgpa = SGPA, #scomment = SCOMMENT,
## #sadvisor = SADVISOR)
## WHERE s.#sidno = SIDNO
## BREAKDISPLAY
END-IF.
## }
## ACTIVATE MENUITEM "End", FRSKEY3
## {
* Quit without submitting changes
MOVE 0 TO CHANGED.
## BREAKDISPLAY
## }
## FINALIZE
END-STUDENT.