The Table Editor Table Field Application
This EQUEL/FORMS application uses a table field to edit the Person table in the Personnel database. It allows the user to update a person's values, remove the person, or add new persons. Various table field utilities are provided with the application to demonstrate their use and their interaction with an Ingres database.
The objects used in this application are:
When the application begins, a retrieve statement is issued to load the table field with data from the Person table. Once the table field has been loaded, the user can browse and edit the displayed values. Entries can be added, updated, or deleted. When finished, the values are unloaded from the table field, and, in a multi-statement transaction, the user's updates are transferred back into the Person table.
The following create statement describes the format of the Person database table:
## create person
## (name = c20, /* Person name */
## age = i2, /* Age */
## number = i4) /* Unique id number */
/*
** Global structure pers corresponds to "person" table
*/
## struct {
## char pname[21]; /* Full name (with C null) */
## int page; /* Age of person */
## int pnumber; /* Unique person number */
## int maxid; /* Max person id number */
## }pers;
/*
** Procedure: MAIN
** Purpose: Entry point into Table Editor program.
*/
## main()
## {
/* Table field row states */
# define stundef 0 /* Empty or undefined row */
# define stnew 1 /* Appended by user */
# define stunchanged 2 /* Loaded by program - not updated */
# define stchange 3 /* Loaded by program - since changed */
# define stdelete 4 /* Deleted by program */
/* Table field entry information */
## int state; /* State of data set entry */
## int record; /* Record number */
## int lastrow; /* Last row in table field */
/* Utility buffers */
## char msgbuf[256]; /* Message buffer */
## char respbuf[256]; /* Response buffer*/
/* Status variables */
## int update_error; /* Update error from database */
## int update_rows; /* Number of rows updated */
int xact_aborted; /* Transaction aborted */
/* Start up Ingres and the FORMS system */
## ingres "personnel"
## forms
/* Verify that the user can edit the "person" table */
## prompt noecho ("Password for table editor: ", respbuf)
if (strcmp(respbuf, "MASTER_OF_ALL") != 0)
{
## message "No permission for task. Exiting . . ."
## endforms
## exit
exit(-1);
}
##message "Initializing Person Form . . ."
##range of p is person
##forminit personfrm
/*
** Initialize "persontbl" table field with a data set in FILL
** mode so that the runtime user can append rows. To keep track
** of events occurring to original rows that will be loaded into
** the table field, hide the unique person number.
*/
## inittable personfrm persontbl fill (number = i4)
Load_Table();
## display personfrm update
## initialize
## activate menuitem "Top"
## {
/*
** Provide menu, as well as the system FRS key to scroll
** to both extremes of the table field.
*/
## scroll personfrm persontbl to 1
## }
## activate menuitem "Bottom"
## {
## scroll personfrm persontbl to end /* Forward */
## }
## activate menuitem "Remove"
## {
/*
** Remove the person in the row the user's cursor is on.
*/
## deleterow personfrm persontbl /* Record later */
## }
## activate menuitem "Find"
## {
/*
** Scroll user to the requested table field entry.
** Prompt the user for a name, and if one is typed in
** loop through the data set searching for it.
*/
## prompt ("Person's name : ", respbuf)
if (respbuf[0] == '\0')
## resume field persontbl
## unloadtable personfrm persontbl
## (pers.pname = name, record = _record, state = _state)
## {
/* Do not compare with deleted rows */
if ((strcmp(pers.pname, respbuf) == 0) && (state != stDELETE))
{
## scroll personfrm persontbl TO record
## resume field persontbl
}
## }
/* Fell out of loop without finding name */ sprintf(msgbuf,
"Person \"%s\" not found in table [HIT RETURN] ", respbuf);
## prompt noecho (msgbuf, respbuf)
## }
## activate menuitem "Exit"
## {
## validate field persontbl
## breakdisplay
## }
## finalize
/*
** Exit person table editor and unload the table field. If any
** updates, deletions or additions were made, duplicate these
** changes in the source table. If the user added new people we
** must assign a unique person id before returning it to
** the table. To do this, increment the previously saved
** maximum id number with each insert.
*/
/* Do all the updates in a transaction */
## begin transaction
update_error = 0;
xact_aborted = 0;
## message "Exiting Person Application . . .";
## unloadtable personfrm persontbl
## (pers.pname = name, pers.page = age,
## pers.pnumber = number, state = _state)
##{
/* Appended by user. Insert with new unique id */
if (state == stnew)
{
pers.maxid = pers.maxid + 1;
## repeat append to person (name = @pers.pname,
## age = @pers.page,
## number = @pers.maxid)
}
/* Updated by user. Reflect in table */
else if (state == stchange)
{
## repeat replace p (name = @pers.pname, age = @pers.page)
## where p.number = @pers.pnumber
}
/*
** Deleted by user, so delete from table. Note that only
** original rows are saved by the program, and not rows
** appended at runtime.
*/
else if (state == stdelete)
{
## repeat delete from p where p.number = @pers.pnumber
}
/* Else UNDEFINED or UNCHANGED - No updates */
/*
** Handle error conditions -
** If an error occurred, then abort the transaction.
** If no rows were updated then inform user, and
** prompt for continuation.
*/
## inquire_ingres (update_error = errorno, update_rows=rowcount)
if (update_error) /* Error */
{
## inquire_equel (msgbuf = errortext)
## abort
xact_aborted = 1;
## endloop
}
else if (!update_rows)
{
sprintf(msgbuf,
"Person \"%s\" not updated. Abort all updates? ",
pers.pname);
## prompt (msgbuf, respbuf)
if (respbuf[0] == 'Y' || respbuf[0] == 'y')
{
## abort
xact_aborted = 1;
## endloop
}
}
## }
if (!xact_aborted)
## end transaction /* Commit the updates */
## endforms /* Terminate the FORMS and Ingres */
## exit
if (update_error)
{
printf( "Your updates were aborted because of error:\n" );
printf( msgbuf );
printf( "\n" );
}
## } /* Main Program */
/*
** Procedure: Load_Table
** Purpose: Load the table field from the "person" table. The
** columns "name" and "age" will be displayed, and
** "number" will be hidden.
** Parameters:
** None
** Returns:
** Nothing
*/
## Load_Table()
## {
/* Set up error handling for loading procedure */
message "Loading Person Information . . ."
/* Fetch the maximum person id number for later use */
## retrieve (pers.maxid = max(p.number))
/* Fetch data, and load table field */
## retrieve (pers.pname = p.name, pers.page = p.age,
## pers.pnumber = p.number)
## {
## loadtable personfrm persontbl
## (name = pers.pname, age = pers.page,
## number = pers.pnumber)
## }
## } /* Load_Table */