Examples of Method: Hire Method
The following sections describe the Hire method as it is defined for the Employee class and the TempEmployee, PermanentEmployee, and Manager subclasses.
Each of these methods handles error checking, which performs a rollback if the database access fails. A failure at the bottom of the hierarchy causes rollbacks in every method previously invoked by the SendSuperclass method.
Note: No commit statements are issued in these methods to allow for future additions to the user class hierarchy. Adding a new subclass whose method includes additional SQL statements as part of the same transaction would force a revision of all superseded methods containing a commit statement.
These methods assume that the programmer handles all commits. For consistency, the rollback statements could alternatively be handled by individual programmers and removed from the method scripts.
Employee Version
In this top-level version of the Hire method, the method script defines the functions described in the following steps. The attributes referenced in this script are set interactively by the user in a frame whose fields are mapped directly to the user class. The method script does the following:
1. Declares a variable to store error status:
method Hire() =
declare
errstat = integer not null;
enddeclare
2. Checks the employee's hire date. If no date has been assigned, supplies the current date:
if CurObject.HireDate = '' then
CurObject.HireDate = 'today';
endif;
3. Generates an employee number by increasing the sequence value in v_highest_number:
update v_highest_number set h_number = h_number
+ 1 where tbl_name = 'emp'
4. Selects the highest employee number into the EmpNum attribute for the current employee:
select h_number as :CurObject.EmpNum from
v_highest_number
where tbl_name = 'emp';
5. Inserts a new row into both the emp and jobs tables and checks for errors:
insert into emp (emp_num, emp_type, last_name,
first_name, hire_date, term_date, term_reason)
values (:CurObject.EmpNum, :CurObject.Type,
:CurObject.LastName, :CurObject.FirstName,
:CurObject.HireDate,
:CurObject.TerminationDate,
:CurObject.TerminationReason);
if CurMethod.DBSession.ErrorNumber = 0 then
insert into jobs (emp_num, job_class, pay,
start_date)
values (:CurObject.EmpNum,
:CurObject.CurrentClass,
:CurObject.CurrentPay, :CurObject.HireDate);
endif;
if CurMethod.DBSession.ErrorNumber != 0 then
rollback;
message 'Database error; unable to insert
employee record.';
endif;
return CurMethod.DBSession.ErrorNumber;
end
TempEmployee Version
Because all temporary employees have a known termination date and a standard termination reason at the time of hire, the purpose of redefining the method for this user class is to guarantee that these values are inserted into the emp table. After gathering the first of these values and providing the second, this method invokes its parent's method by using the SendSuperclass method.
The TempEmployee invokes this method after setting values for the two critical attributes (TerminationDate and TerminationReason) so that the parent's version of the Hire method runs with real values for these attributes.
The following 4GL code is the entire Hire method script for TempEmployee:
method Hire() =
declare
errstat = integer not null;
enddeclare
begin
if CurObject.TerminationDate = '' then
CurMethod.InfoPopup(messagetext =
'Temporary employees must have a termination ' +
date specified.', messagetype = MT_ERROR);
errstat = -1;
else
CurObject.TerminationReason = 'Contract
period end';.errstat =
CurMethod.SendSuperclass();
endif;
return errstat;
end
Because the TempEmployee subclass requires termination information for a new employee to be added to the database, it sets this information prior to calling its superclass's version of the method.
PermanentEmployee Version
Unlike the TempEmployee class, which invokes the SendSuperclass method only after providing values for attributes critical only to that subclass, PermanentEmployee invokes the SendSuperclass method first and then does additional work.
The PermanentEmployee subclass requires a successful insertion of new employee information into the emp and jobs tables (performed by the parent's version of the method) before it adds a new row to the permemp table. Therefore, it forces successful completion of the first insertions before performing its own insertion.
The PermanentEmployee version of the Hire method handles the following values for the defined attributes of the PermanentEmployee subclass:
• NextReviewDate
• VacationDays
• InsurancePlan
• BonusTemp
The Hire method defined for this subclass inserts values from all of these attributes into the permemp table. When this method is invoked on a permanent employee, rather than on its manager subclass, the value of the bonus_rate column of the permemp table defaults to null (only managers are entitled to a bonus).
If the BonusTemp attribute had not been defined for the PermanentEmployee class, hiring a manager would require two separate database operations, an insertion and an update (both into the permemp table). The insertion would be the same one performed by the PermanentEmployee's Hire method, and the update would be required to store the manager's bonus rate.
To enhance performance by executing a single database operation when hiring managers, the PermanentEmployee class has a private BonusTemp attribute, which is null by default. Because this attribute is private, no value can be supplied by invoking this method on a permanent employee object.
The following code is the entire Hire method for PermanentEmployee:
method Hire() =
declare
errstat = integer not null;
enddeclare
begin
errstat = CurMethod.SendSuperclass();
if errstat = 0 then
CurObject.NextReviewDate =
CurObject.HireDate + '3 months';
insert into permemp (emp_num,
next_review_date,insurance_plan,
bonus_rate)
values (:CurObject.EmpNum,
:CurObject.NextReviewDate,
:CurObject.InsurancePlan,
:CurObject.BonusTemp);
errstat = CurMethod.DBSession.ErrorNumber;
if errstat != 0 then
rollback;
CurMethod.InfoPopup(messagetext =
'Database insert failed with error ' +
varchar(CurMethod.DBSession.ErrorNumber),
message_type = MT_ERROR);
endif;
endif;
return errstat;
end
Manager Version
The only difference between a manager and its PermanentEmployee superclass is that managers are given a bonus rate when hired. Therefore, the script for the Hire method that is redefined for the Manager subclass is the simplest of all the classes described.
The following code is the entire Hire method script for Manager:
method Hire() =
declare
errstat = integer not null;
enddeclare
begin
CurObject.BonusTemp = CurObject.BonusRate;
errstat = CurMethod.SendSuperclass();
return errstat;
end
This script first sets a value for the BonusTemp attribute and then invokes its superclass's version of the method. The Manager class's superclass, PermanentEmployee, also invokes the Hire method defined by its superclass, Employee. The SendSuperclass method in this script, therefore, has the effect of superseding the Hire method all the way up the hierarchy.
The SendSuperclass method is effective even if the immediate superclass does not define the method being superseded. For example, assume that the PermanentEmployee class did not define its own version of the Hire method, but its subclass, Manager, needs to supersede the version defined at the top of the hierarchy for the Employee class.
In this case, invoking the SendSuperclass method in the Hire method for Manager automatically invokes the current method as it was defined by Employee. The Manager class's script does not need to specify that it is superseding the method defined for Employee.
For the complete method scripts of the user classes discussed, see the user class components in the online Videos application.