This chapter will describe some miscellaneous topics which are important when you create an Empress 4GL application.
10.1.1 Function Calls and Returns
A CALL statement is usually used to call functions. These include Empress
4GL functions, subscripts, or other applications. The syntax for
the CALL statement is as follows:
Syntax
CALL function_name ([param {, param}])
where:
| function_name | is the name of the function you would like to call. |
| param | is any parameter you would like to include. |
When you call an application, the syntax is slightly different:
Syntax
CALL APPLICATION apname ([param {, param}])
where:
| apname | is the name of the application you would like to call. |
| param | is any parameter you would like to include. |
If a function returns a value, you can include it as part of an expression. In this case, you can omit the CALL keyword because it is implied. Empress 4GL executes the function and the enters the value it returns in the expression. You may leave the script in several ways. The easiest way is to wait until the last statement of the script has executed. The script finishes and the part of the application which called the script continues where it left off.
However, sometimes it is necessary for a script to terminate earlier than normal or it may have to return a value. In these cases, you can use the RETURN statement. This statement causes the script to immediately return control to the application that called it. If an expression is part of the statement, the script will return a value.
There are two other functions which will terminate the execution of a script prematurely: the error_message function and the EXIT statement. The error_message function immediately returns control to the application and prints out the appropriate error message. The EXIT statement immediately begins executing the application exit script and terminates the application.
The IF statement has an expression called a condition. This expression will be evaluated to a value of true or false. If the expression is true, the statements following the condition, or the optional keyword THEN, preceding the END, ELSE or ELSEIF keyword will be executed. If the expression is false, the statements following ELSE or ELSEIF statements and preceding the END keyword are executed. The syntax for IF statement follows:
Syntax
IF cond [THEN]
{statement}
{ELSEIF cond [THEN]
{statement}}
[ELSE {statement}]
END
If you use a SWITCH statement, the expression is compared with several different values. If it equals any of the statements that follow, the value preceding the case, default or end keyword will be executed. The syntax of a SWITCH statement is as follows:
Syntax
SWITCH expr
CASE value {, value}:
statement [;] {statement [;]}
{CASE value {, value}:
statement [;] {statement [;]}}
[DEFAULT:
statement [;] {statement [;]}]
END
Note the default case. This is a "catch all" case which will be executed to catch any values that are not mentioned specifically in the cases above.
Syntax
WHILE condition {statement [;]} END
The condition is a boolean expression - as in the IF statement - and Empress 4GL continually evaluates the expression to see if the loop should be executed again. As long as the condition remains true, the statements preceding the END keyword will continue to execute.
Keep in mind you will have to eventually make the condition false. The statements in the WHILE loop will be the only ones executed until that happens. That means that these statements must eventually cause the condition to become false. Otherwise, your program will have an endless loop.
Many programming languages have other statements for looping, for example, FOR loops and DO UNTIL loops. These loops can be created easily using a WHILE loop in Empress 4GL.
An example of a FOR loop in C is as follows:
Syntax
FOR (i=0;i;i++) {
...
code
...
}
In Empress 4GL you can replace it with:
LET i = 0
WHILE i < 10
...
code
...
LET i = i + 1
END
An example of a DO UNTIL loop in C is as follows:
DO {
...
code
...
} UNTIL cond
In Empress 4GL you can replace it with:
LET flag = 0
WHILE flag = 0
...
code
...
IF cond LET flag = 1 END
END
Other common looping statements such as BREAK or CONTINUE are not available in Empress 4GL, but you can simulate them. For example, with this you can simulate a BREAK statement:
Syntax
LET _flag = false
WHILE _flag = false
...
code
...
IF condition LET _flag = true ELSE code END
END
You could use a similar example to simulate a CONTINUE statement.
Data integrity simply refers to the "meaningfulness" of the data. Data integrity is lost when the data no longer represents a meaningful state. This generally happens when a record or group of records is partially changed.
For example, William Ansell has been promoted at AAA Software. Therefore, his new position and salary must be entered into the personnel database. If the position is updated and the system crashes before William's new salary is updated, the data integrity is lost. It is better to have neither change made than to have only one change made.
With Empress, you can maintain data integrity using transactions to make several operations behave as a single operation. These operations are grouped into a transaction which can be undone if one of the operations fails.
In the personnel example, you could start a transaction and then enter William's new salary and position. If Empress detects an error on either the salary or position update, the transaction can be rolled back and the database will not change. If no errors are detected, the transaction can be committed. Either way, data integrity is maintained.
In addition, when you restart a system after it has crashed, the database administrator can roll back or commit outstanding transactions as necessary.
The START TRANSACTION statement is used to begin a transaction. Each operation that follows this statement and changes the database belongs to the transaction. Transactions store the information needed to undo each operation that occurs within the transaction. The transaction stores this information until the transaction is rejected or accepted.
Since you cannot start a second transaction within another, you can use the SAVEPOINT statement to place a "mark" within the transaction. With this, you can partially undo a transaction. You can set as many savepoints as necessary in a single transaction, although each must have a separate name. A name can be reused if the transaction has been rolled back past the savepoint that originally used that name.
Once a transaction is complete, you can issue the COMMIT TRANSACTION statement. This commits the transaction to the database and it can no longer be rolled back.
Once a transaction is committed, the system assumes that the data integrity is not violated. At this point, you can begin a new transaction.
If Empress detects an error in the course of a transaction, you can use the ROLLBACK TRANSACTION to undo the parts that have completed successfully. If you do not specify a savepoint, the entire transaction is rolled back. The database will be in the same state as it was when the transaction was started. A new transaction can be started as there is no longer a transaction in effect.
However, the ROLLBACK statement can roll back to a specific savepoint in the transaction. This allows the application to rollback to a set point in the transaction and try again without having to go all the way back to the beginning.
For example, an application tries to update ten tables in a single event. If any one of the updates fails, the data integrity will be lost. It is possible to put all the update operations inside a transaction. If any of the updates fail, the entire transaction can be cancelled and restarted. However, if the first five tables are updated properly, you may want to set a SAVEPOINT here. If the last five tables fail, Empress 4GL only needs to back out half way and try the last five updates once again.
To prevent this from happening, locking is used. With locking, only one person at a time can update a record. Therefore, the airline reservation scenario cannot happen.
You can place two different types of locks on records: EXCLUSIVE and SHARED. An EXCLUSIVE lock is used for update operations. When an EXCLUSIVE lock is in place, you can be assured that another user cannot access the record you are using.
A SHARED lock is used for selection operations. You would use this type of lock if the record is only displayed and does not need to be restricted. In this case, a limitless number of users can get a SHARED lock on the record. However, you cannot get an EXCLUSIVE lock when there is an existing SHARED lock.
In Empress 4GL, a table is opened in a specific mode. This mode determines the type of locks that will be placed on records that are selected from the table. There are three different modes.
The first mode is the read mode. Any records you select from a table opened in read mode will use SHARED locks. However, no update operations are possible.
In order to allow updates, a table must be opened in update or deferred mode. Both allow EXCLUSIVE locks to be set. The update mode always tries to get EXCLUSIVE locks on the data while the deferred mode uses SHARED locks until the application actually attempts an update operation.
Opening tables in deferred mode allows an endless number of users to access data, but it does require extra overhead when users perform update operations.
10.3.2 LOCK Table
While you sometimes need to lock an entire table for an operation, this
is not usually the case. For this reason, Empress 4GL has
the LOCK statement.
You can only issue the LOCK statement inside a transaction. Also, you must specify the lock mode as either EXCLUSIVE or SHARED. When you issue this statement, Empress 4GL locks the table regardless of the lock level, unless you have a no lock level. This lock remains in effect from the time you issue the statement until the current transaction is completed.
This ensures that records affected earlier in a transaction cannot be updated as the transaction continues. If the transaction is rolled back, this could cause problems since the second operation is updating data that is not yet stable.
10.4.1 Errors
The syntax for the ON ERROR statement is as follows:
Syntax
ON ERROR CALL script ([param {, param}]) err_no
{, err_no} |DEFAULT|
|IGNORE |
|EXIT |
An ON ERROR statement instructs Empress 4GL about what to do when certain error conditions occur. It is in force from the time that you define it until there is another ON ERROR statement for the same error number. It gives you four different ways in which to handle error conditions.
A list of error numbers can be found in the Empress 4GL Programmer's Reference manual.
If a signal is to be ignored for a period of time, you can use the DISABLE INTERRUPT and ENABLE INTERRUPT statements.
10.5.1 The Operating System
There are four system commands that you can use to interface with the operating
system. The first two execute operating system commands while the second
two return values from the operating system environment.
The SYSTEM function allows an application to execute an operating system command. The syntax for this function is as follows:
Syntax
CALL SYSTEM ([command {, argument}])
The command you specify and any supplied arguments are passed to the operating system and executed. Once the command completes, Empress 4GL asks you to press a key to return to the application.
You build the command that is passed to operating system by taking the command and appending any of the arguments after they are surrounded by double quotes. As well, any special characters in the shell, like "*", are preceded by a backslash to avoid interpretation by the shell. If this you would rather not do this, for example if the command uses the "*" as a wildcard, you can make it part of the command string that is not quoted in any way.
If the SYSTEM function is called without any parameters, an operating system shell will be started. The shell that is run will be determined by the MSSHELL variable. When you exit the shell, you will be back in the application.
The CALL sys_command function will also execute an operating system command. Note that in this case, the command is not optional. This function cannot be used to get a operating system shell.
In addition, the CALL sys_command function, unlike the SYSTEM function, does not prompt users to hit a key before returning to the application. The command is simply executed and control is passed back to the application.
If the sys_command function is used to execute an operating system command that produces any output on the standard output or error, this output will appear wherever the cursor is on the screen. This function is best suited to silent commands while the SYSTEM function is better for commands that produce output.
In order to get values from the operating system into an Empress 4GL application, you must use the sys_value or sys_variable functions.
The sys_value takes the same parameters as the sys_command function. Any output that is generated by that command is then passed back by the command as a character string. For example, to get the system date you could use the following:
Syntax
LET sys_date = sys_value ("date")
Operating system environment variables are also made available to Empress 4GL applications with the sys_variable function. The function returns the value of the environment variable that is named as a parameter. For example, you can retrieve the terminal type using:
Syntax
LET terminal_type = sys_variable("TERM")
10.5.2 Empress Environments
There are two Empress environments available from within
an Empress 4GL application. You can execute SQL commands
and Empress reports.
To execute SQL commands, use the following:
Syntax
CALL empsql ([db_name [, sql_command]])
It will execute the SQL command in the specified database.
If you omit the SQL command, an Empress SQL session will start with the specified database as the default database. If you do not specify a database name, there will be no default database, but an SQL session will still start. When you exit the SQL session normally, you return to the application.
To execute an Empress report, use the following command syntax:
Syntax
CALL emprepwr context (script, output [, mess {, expr}])
This command will take the records in the selected context and pass them to the Report Writer. They are treated just like a data file created by the SQL SELECT statement with the REPORT DUMP option. The script name and output file are mandatory parameters. The message, which is printed as soon as the Report Writer starts, and the arguments, which are passed to the report script, are optional. If you do not want a message to appear, but you would like parameters, set the message as the keyword NULL.
These functions are mouse_field_name and touch_field_name. They determine the field location of the mouse cursor and the screen position for the touch screen. Similarly, you can determine the field number and window.
To update the global variables which indicate the row and column of the mouse cursor or touch screen position, you can use mouse_location or touch_location.
The mouse has one additional function. This is the mouse_key_down function which returns "1" if someone presses the mouse key and returns a "0" otherwise. There is no analogous function for touch screens because they have no buttons.