# CHAPTER 10: Creating Applications: Miscellaneous

This chapter will describe some miscellaneous topics which are important when you create an Empress 4GL application.

## 10.1 Flow Control Statements

Since part of an Empress 4GL application is a procedural language, it is important to have statements which control how the script executes. There are three basic types of control statements:

- function calls and returns
- branching controls
- looping controls

### 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.

### 10.1.2 Branching Statements

A branching statement is used to control whether or not Empress 4GL executes a section of code. There are two types of statements that you may use to execute code: `IF` and `SWITCH`.

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.

### 10.1.3 Looping Statements

The only looping statement that is available in Empress 4GL is the `WHILE` loop. It has the following syntax:

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.

## 10.2 Transactions

When you use an Empress database, it is important to consider the data integrity. Transactions and locking help you ensure the data integrity during operations that modify the database.

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.

### 10.2.1 Statements

There are four statements you can use to control transactions within an Empress 4GL application: `START`, `SET SAVEPOINT`, `COMMIT`, and `ROLLBACK`.

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.

## 10.3 Locking

Data integrity can also be destroyed by simultaneous updates of a record. For example, two users update the exact same record at the same time on an airline reservation system. Both users try to reserve the same seat on the same flight. Without locking, both update operations may succeed and only one will take effect or half of each update takes effect so that the reservation has one person's last name and the other's first name.

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.1 Locking Levels

As well as the lock type, Empress tables have locking levels associated with them. There are four different levels and each one affects the way that locks are placed on records. To set the lock level, you use Empress SQL commands.

1. The lowest level of locking is the no lock level. A table without locking will never create locks on the records. If the database is used by one person at a time, this is acceptable. There will never be problems with multiple access.
2. However, once two or more users try to update a record at the same time, you must use locking. The lowest locking level is record level locking. When you set a table for record level locking, each record is locked when a user makes the record current. This means that other records in the table (including ones in the selected context) are not locked.
3. Use group level locking if you need to lock an array of selected records. This way, the Empress 4GL places the appropriate locks on every record in the selected context. Users cannot change records once the records have been selected by an application. However, other users will have trouble selecting records as there will be the potential for more locked records.
4. The highest level of locking is table level. As soon as a user selects a context of records from the table, all the records in the table are locked. This will ensure that the entire table will not change while the application is working on the table.

### 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 Error Handling

Empress 4GL will handle any errors it encounters. However, Empress 4GL may not handle errors in the way that you want. For this reason, you can use these statements to trap errors and interrupts and handle them within the application: `ON ERROR` and `ON INTERRUPT`. These statements allow you to handle specific errors or interrupts in various ways.

### 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.

1. You can have an application script which handles the errors. This is useful for dealing with transactions that fail half-way through. When an error is encountered, it can be rolled back.
2. Any parameters that are passed to the script must be globally available. This is because the script may not be called from within the script that defines the error handling.
3. You can also reset the error handling to the Empress 4GL default, which will ignore the errors or exit the application upon an error.
4. The list of error numbers indicates which errors are to be handled in the previously described fashion.

A list of error numbers can be found in the Empress 4GL Programmer's Reference manual.

### 10.4.2 Interrupts

As well as errors, you must also deal with system interrupts using the `ON INTERRUPT` statement. The `ON INTERRUPT` statement has a similar syntax to the `ON ERROR`. However, there are no default or ignore options. But, there is a break option. The break option will usually behave the same as the ignore option for `ON ERROR`, but if the debugger is active it will cause a breakpoint to be set and the debug windows to be entered.

If a signal is to be ignored for a period of time, you can use the `DISABLE INTERRUPT` and `ENABLE INTERRUPT` statements.

## 10.5 System Commands

An Empress 4GL application can interface with other operating environments using various system commands. With these commands, it can interface with the operating system environment, Empress SQL , and the Empress Report Writer manual.

### 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`.

## 10.6 Mouse and Touch Screen Functions

To handle a mouse or a touch screen, Empress 4GL has functions to determine their locations.

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.