HomeStartingEnvironmentDBMSVisualPQLProceduresSQLFormsHost/APIIndex
VisualPQL homecontents start chapter top of pagebottom of pagenext page index Control Flow

Control Flow

There are a number of commands that deal with the flow of control within a program depending on particular logical conditions.

The simple IF,IFNOT commands test a logical condition and execute one or more commands immediately if the condition is satisfied.

The JUMP command transfers control to a specific point in the program identified by a statement label.

Subprocedures are parts of a routine that can be executed from any point within that routine, returning control to the next statement. Subprocedures are defined at the end of the routine and share data with the routine.

Blocks

The major control structures are blocks and other commands occur in blocks that are treated as a unit. Blocks are defined by commands that specify the type of block and are bounded by an END command. Block structures are used for all database and table access.

Blocks consist of a command that starts the block and an end command that ends the block (e.g. LOOP / END LOOP). Blocks may be nested within other blocks and an inner block must be completely within an outer block. Blocks may not overlap. The block structures are:

AFTER

A block of commands executed after all other processing. (There is no END AFTER; this block is delimited by the end of the program or retrieval.)

BEGIN
A block of commands executed at this point.

FOR
A block of commands executed a specified number of times.

IFTHEN
A block of commands executed when a condition is true. IFNOTTHEN is a variant that executes the block when a condition is false.

CASE IS, RECORD IS and ROW IS.
These blocks relate to one occurrence of a particular database record or row. Specify the key to identify the record on the command. The commands have variants using the keywords NEW and OLD. These specify that the block is only executed if the record created/already exists.

The JOURNAL RECORD IS creates a block that processes data from a journal entry that matches the specified record type. This can only be used inside a PROCESS JOURNAL block.

LOOP
A block of commands executed repeatedly until specifically ended (typically by an EXIT LOOP).

PROCESS CASE, PROCESS RECORD, PROCESS DATA and PROCESS ROW.

A block of commands executed once for each occurrence of a record in a database or row in a table.

PROCESS JOURNAL specifies a block of commands that is executed once for each occurrence of matching records on a database journal.

UNTIL
A block of commands executed until a specified condition is met.

WHILE
A block of commands executed as long as a specified condition is met.

The EXIT and NEXT commands further control processing within the block. EXIT passes control to the first command after the end of the block; NEXT goes to the next iteration of a looping block.

homecontents start chapter top of pagebottom of pagenext page index

Logical Conditions

A logical condition can be composed of a number of elements. The basic element is a logical expression that uses a Relational Operator to specify a comparison between two values. This returns either true or false. The values must be of the same type, either string or numeric. Constants, variables, functions and expressions using arithmetic, functions and other computations may be compared. When expressions are compared, all string and arithmetic operations are completed before the relational operations. When strings are compared, they are case sensitive (upper or lower) and tests for greater than/less than use the standard sort sequence: 'B' is greater than 'A' and 'BOY' is greater than 'BOX'. The relational operators are:

EQ or = True when values are equal.

NE or >< True when values are not equal.

GT or > True when the first value is greater than the second value.

GE or >= or => True when first value is greater than or equal to the second value.

LT or < True when the first value is less than the second value.

LE or <= or =< True when first value is less than or equal to the second value.

The logical condition can also contain the NOT operator:

NOT NOT operates on a logical expression and negates its logical value. A true (non-zero, non-missing) expression is made false and a false expression is made true. NOT operates on the expression that follows up through the next relational operator or the next un-matched right parenthesis. NOT is evaluated and resolved after the entire expression to which it applies has been resolved and before other logical operators at the same level of nesting are evaluated. For example:
IF( NOT 1 GT 2 ) WRITE 'TRUE'

homecontents start chapter top of pagebottom of pagenext page index

Compound Conditions

Compound conditions test two logical expressions and resolve to either true or false. The relationship between the two expressions is specified using the logical operators:

AND Intersection. True if both expressions are true.

OR Inclusive Union. True if either expression is true.

XOR Exclusive Union. True if one but not both expressions are true.

These logical expressions resolve to either true or false. For example,

IF(1 LT 2 AND 'A' LT 'B') WRITE 'Both statements are true'

Compound Logical Operations on the same variable.

When the same variable is repeatedly tested for different values, the variable name (and test if that repeats) do not have to be repeated. For example:
IF(ID EQ 1 OR 3 OR 12 OR 16)   WRITE ID
The phrase 'ID EQ' is assumed to follow each 'OR' making this equivalent to:
IF(ID EQ 1 OR ID EQ 3 OR ID EQ 12 OR ID EQ 16) WRITE ID

The following two statements are equivalent:

IF (ID EQ 1 OR ID GT 10) WRITE 'TRUE'
IF (ID EQ 1 OR GT 10)    WRITE 'TRUE'
The following two statements are also equivalent:
IF (ID EQ A OR B AND NOT C)             WRITE 'TRUE'
IF (ID EQ A OR ID EQ B AND NOT ID EQ C) WRITE 'TRUE'

Precedence

Parentheses may be used to establish precedence, in which case more deeply nested operations are resolved earlier. Within any expression, the various elements are resolved in the order listed below. Elements at an equal level of precedence are resolved left to right.

  1. parenthesised expressions

  2. functions

  3. string concatenation

  4. exponentiation ( ** )

  5. multiplication and division ( * and / )

  6. addition and subtraction ( + and - )

  7. relational operators EQ, NE, GT, GE, LT, LE

  8. logical operator NOT

  9. compound logical operators AND, OR, XOR

Logical Values

Expressions that contain relational or logical operators resolve into true or false logical values equivalent to a 1 (one) or a 0 (zero). It is valid to compute a numeric variable to hold the result of a logical expression and to use logical expressions as arguments in functions such as SUM.

IF commands can directly test expressions that resolve to numeric values. Zero tests to false, missing tests to false and all other values test to true. In the following example, LOGICVAR contains the value 0 (zero) if the value of A does not equal the value of B, or 1 if it does:

COMPUTE LOGICVAR = (A EQ B)
IF (LOGICVAR) WRITE 'TRUE'
Because of the simple syntax for multiple tests on a single variable, compound conditions on logical variables must be specified with care. Consider the following two statements,

IF ( LOGVAR1 AND AGE GT 21) WRITE 'TRUE'
IF ( AGE GT 21 AND LOGVAR1) WRITE 'TRUE'

The first statement test LOGVAR1 to be 1 (true) and AGE greater than 21. However the second statement is expanded to:

IF ( AGE GT 21 AND AGE GT LOGVAR1) WRITE 'TRUE'

homecontents start chapter top of pagebottom of pagenext page index

IF, IFNOT

IF     ( logical expression ) command(s)
IFNOT  ( logical expression ) command(s)
IF executes the specified command or commands when the logical expression is true. When the logical expression is false, program execution continues with the next executable command. IFNOT executes the specified command or commands when the logical expression is false. When the logical expression is true, program execution continues with the next executable command.

Any VisualPQL command may be specified as the executable result of an IF/IFNOT except:

Separate multiple commands with semi-colons (;). For example:

IF (1 EQ 1) SET X(1); WRITE 'OK'
IF (X EQ 1) SET X(0);
            WRITE 'OK 2';
            EXIT RETRIEVAL
PROCESS REC EMPLOYEE
. IFNOT(SALARY  GE  2000) NEXT REC
. WRITE NAME SALARY
END REC
The example goes to the next record when salary is not greater than or equal to 2000 and also when salary is missing (because the expression is treated as false).

homecontents start chapter top of pagebottom of pagenext page index

JUMP

JUMP  statement label
JUMP  (statement label , statement label, ...) variable
JUMP transfers control to the point in the program identified by the specified statement label. Execution continues serially from that point. It is possible to jump to a statement label or to fall through to it from the normal flow of control. A JUMP command must be at an equal or higher level of nesting and within the same nested set as the statement label that it references. JUMP can jump out of a block, but not into the middle of a more deeply nested block. JUMP can not jump out of or into a SUBROUTINE or SUBPROCEDURE.

Specify a statement labels as the first element on a line. A statement label is a name followed by a colon (:). When referenced in the JUMP command, do not specify the colon. If you need to use a non-standard name (enclosed in curly brackets {}) as a label in PQL, there is a possible conflict with the syntax for command labels used to control command processing. Avoid this conflict by indenting the label and specifying a full stop in column 1.

The first form of JUMP specifies a single statement label and transfers control to the command after the label.

The second form of the command, the computed JUMP, transfers control to the nth label in a specified list of labels, where the numeric variable contains the value N.

homecontents start chapter top of pagebottom of pagenext page index

AFTER

AFTER PROGRAM or AFTER RETRIEVAL

Specifies a block of commands executed when the program or retrieval is complete. The block is typically used to print report ending information and for actions that are taken just before ending the program.

Table, case or record processing commands are not allowed. Reference may not be made to any data in the database or table files. Local variables are available for output.

This command is typically used with the Full Report Procedure.

AFTER PROGRAM is identical to AFTER RETRIEVAL, except that it is used in programs rather than retrievals.

homecontents start chapter top of pagebottom of pagenext page index

BEGIN

BEGIN

Specifies the beginning of a block of commands. The commands in a BEGIN block are executed when control reaches this point.

END BEGIN
Delimits the BEGIN block.

EXIT BEGIN
Transfers program control to the statement following the END BEGIN command. It is usually used conditionally to terminate processing of the block.

BEGIN can be used to anywhere in a program to group a set of commands that have some common purpose. For example, initialisation at the start of the program.

PROGRAM
BEGIN
. COMPUTE TOTAL = 0
. other initialisation commands
END BEGIN
PROCESS ROWS SCHOOLS.STUDENTS
. COMPUTE TOTAL = TOTAL + 1
. other commands performed for every row
END ROW
END PROGRAM

BEGIN is often used to create a better structure in a program with complex logical conditions and to avoid the use of JUMP or very complex IFTHEN / ELSEIF constructs. For example:

BEGIN
. IF (logical condition) EXIT BEGIN
. visualpql code

. IF (logical condition) EXIT BEGIN
. IF (logical condition) EXIT BEGIN
. visualpql code

END BEGIN

homecontents start chapter top of pagebottom of pagenext page index

EXIT

EXIT [ blocktype ]
EXIT blocktype stops execution of the block at that point and transfers control to the first command following the END blocktype command. An EXIT can be used in any block. If the blocktype is specified, the command exits the innermost block of that type. If the blocktype is not specified, the command exits the innermost block. It is good practice to specify blocktype. An EXIT command may be specified in the following blocks:

EXIT BEGIN Exits the current BEGIN block.

EXIT CASE Exits the current case processing block.

EXIT DATA Exits the current record processing block.

EXIT FOR Exits the current FOR block.

EXIT IF Exits the current IFTHEN or IFNOTTHEN block.

EXIT JOURNAL Exits the current JOURNAL RECORD IS block.
EXIT LOOP Exits the current LOOP block.

EXIT PROCESS JOURNAL Exits the current PROCESS JOURNAL loop.
EXIT PROCESS RECORD Exits the current PROCESS RECORD loop.

EXIT PROCESS ROW Exits the current PROCESS ROW loop.

EXIT PROGRAM Terminates the PROGRAM after executing any commands in the AFTER PROGRAM block. STOP is a synonym for EXIT PROGRAM.

EXIT RECORD Exits the current record processing block.

EXIT RETRIEVAL Terminates the RETRIEVAL after executing any commands in the AFTER RETRIEVAL block. STOP is a synonym for EXIT RETRIEVAL.

EXIT ROW Exits the current row processing block.

EXIT UNTIL Exits the current UNTIL block.

EXIT WHILE Exits the current WHILE block.

homecontents start chapter top of pagebottom of pagenext page index

FOR

FOR control_var = startvalue, endvalue [ ,increment ]

The FOR command specifies the number of times the commands in a FOR block are executed. FOR assigns a new value to the control variable each time the block is repeated.

control_var The control variable must be a numeric variable and may not be an array element. It is incremented by the value of increment during each pass through the block. When the value of this variable exceeds the endvalue, the block is exited and control is transferred to the first statement following END FOR. If the control variable is not explicitly declared, it is declared implicitly as a REAL*8 local variable.

startvalue The control variable is set to this value when the block is first executed. The value may be a program variable, array element reference, expression or a numeric constant.

endvalue The end value determines the final pass through the FOR block. The value may be a program variable, array element reference, expression or a numeric constant.

increment The value by which the control variable is incremented during each pass through the block. The value may be a program variable, array element reference, expression or a numeric constant. The default increment value is 1 (one).

END FOR Delimits the FOR block.

EXIT FOR Terminates processing of the FOR block and transfers program control to the first statement following END FOR. This command is usually executed conditionally with an IF command or from within a conditionally executed block of commands.

NEXT FOR Terminates processing of the current pass through the FOR block and passes control to the start of the next FOR loop after incrementing and checking the control variable.

The following sequence is executed in a FOR block:

homecontents start chapter top of pagebottom of pagenext page index

IFTHEN

IFTHEN    (logical_expression)
IFNOTTHEN (logical_expression)

The IFTHEN command defines a block of commands that is executed conditionally.

In its simplest form, IFTHEN defines a block of commands that is executed when a logical expression is true. An IFNOTTHEN block of commands is executed when the logical expression is false. Any command may be included within an IFTHEN or IFNOTTHEN block, including other complete blocks of commands and other logical test commands.

Other conditional blocks within the condition, can be defined with the ELSE , ELSEIF, and ELSEIFNOT commands. Each conditional block is terminated with another ELSEIF, ELSE or the END IF. An IFTHEN block may contain multiple ELSEIF and ELSEIFNOT blocks. It may only contain one ELSE block.

END IF Delimits the IFTHEN block.

EXIT IF Directs the flow of the program to the statement following the END IF of the block in which it appears.

ELSE Specifies a block of commands that is executed when no other commands are executed in the IFTHEN block. The block of commands is delimited by the END IF.

ELSEIF
ELSEIFNOT
Specifies a block of commands that is executed when the conditions specified on the IFTHEN and any other previous ELSEIF commands are not satisfied and the condition specified on this command is satisfied. The block of commands is delimited by a further ELSEIF, ELSE or the END IF.

IFTHEN (logical expression)
.  commands executed when above expression is TRUE
. ELSEIF (logical expression)
.  commands executed when above expression is TRUE
. ELSEIFNOT (logical expression)
.  commands executed when above expression is FALSE
. ELSE
.  commands executed when no other blocks are executed
END IF

homecontents start chapter top of pagebottom of pagenext page index

LOOP

LOOP

LOOP repeatedly executes a block of commands. By definition, a LOOP block is an infinite loop and a command such as EXIT or JUMP must be used to terminate looping. The compiler does not check for the existence of these commands within a LOOP.

END LOOP Delimits the LOOP block.

EXIT LOOP Terminates looping, directing program execution to the statement following the END LOOP. This command is frequently executed conditionally, as with an IF command, to terminate the looping.

NEXT LOOP Terminates processing of the current pass through the block and passes control to the next iteration of the current LOOP block (control is passed to the statement following LOOP).

homecontents start chapter top of pagebottom of pagenext page index

NEXT

NEXT [ blocktype ]

Some blocks (e.g. WHILE) are looping structures and execute repeatedly until some controlling condition is met. In looping blocks, the NEXT blocktype command transfers control to the first command in the block at the next iteration.

If the blocktype is specified, the command transfers control to the next iteration of the innermost block of that type. If blocktype is not specified, control is transferred to the next iteration of the innermost looping block. It is good practice to specify blocktype. NEXT may be specified in the following looping blocks:

NEXT CASE Transfers control to the next iteration of PROCESS CASES if another case exists.

NEXT FOR Transfers control to the next iteration of the FOR, if the end condition specified on the FOR has not yet been reached.

NEXT LOOP Transfers control to the next iteration of the LOOP.

NEXT REC Transfers control to the next iteration of PROCESS RECORDS if another record exists.

NEXT DATA Transfers control to the next iteration of PROCESS DATA if another record exists.

NEXT ROW Transfers control to the next iteration of PROCESS ROWS if another row exists.

NEXT UNTIL Transfers control to the next iteration of the UNTIL, if the end condition specified on the UNTIL has not yet been reached.

NEXT WHILE Transfers control to the next iteration of the WHILE, if the end condition specified on the WHILE has not yet been reached.

For example:

PROCESS REC EMPLOYEE
.  IF ( GENDER = 1 ) NEXT PROCESS REC
    ...
END  PROCESS  REC

homecontents start chapter top of pagebottom of pagenext page index

UNTIL

UNTIL (logical expression)

UNTIL repeatedly executes a block of commands until the logical expression becomes true. When the expression becomes true, the block is exited and program control is transferred to the statement following the END UNTIL command.

The condition of the logical expression is tested at the start of each pass through the UNTIL block. If the condition is initially true, the block is skipped entirely.

END UNTIL Delimits the UNTIL block

NEXT UNTIL Terminates the current pass through the block and transfers control to the next iteration of the UNTIL command. This command is usually executed conditionally, as the result of a logical test (e.g. with the IF command). This command may only be used within an UNTIL block.

EXIT UNTIL Terminates processing of the UNTIL block and transfers program control to the statement following the END UNTIL. This command is usually executed conditionally, as the result of a logical test (e.g. with the IF command). This command may only be used within an UNTIL block.

homecontents start chapter top of pagebottom of pagenext page index

WAIT

WAIT num_exp
Pauses execution of this program for the specified number of tenths of a second.

PROCESS RECORD PATIENT LOCK = 4    | get the patient record
. LOOP
.  IF(SYSTEM(36) = 1)  EXIT LOOP  | exit if we get the record
.  WRITE 'Waiting for locked record'
.  WAIT 5                         | wait half a second
.  RETRY RECORD                   | try to get the record
. END LOOP
...
END PROCESS RECORD

homecontents start chapter top of pagebottom of pagenext page index

WHILE

WHILE (logical expression)

WHILE repeatedly executes a block of commands while the expression is true. When the expression becomes false, execution of the block is terminated and program control is transferred to the statement following the END WHILE. The condition of the expression is tested at the start of each pass through the WHILE block. If the condition is initially false, the block is skipped entirely.

END WHILE Delimits the WHILE block

NEXT WHILE Terminates the processing of the current pass through the block and passes control to the next iteration of the block. This command is usually executed conditionally, as the result of a logical test (e.g. with the IF command).

EXIT WHILE Terminates processing of the WHILE block and transfers program control to the statement following the END WHILE. This command is usually executed conditionally, as the result of a logical test (e.g. with the IF command).

homecontents start chapter top of pagebottom of pagenext page index

SUBPROCEDURE

SUBPROCEDURE name [ NOAUTOCASE ]

A subprocedure is a named, structurally complete, block of commands that may be executed from any point within a routine with the EXECUTE SUBPROCEDURE command. Subprocedure names must be unique within the routine. A subprocedure is compiled with, and belongs to, the routine it is defined in. A subprocedure shares variables with the routine and other subprocedures and has access to all variables available to the routine in which it is defined. Declare any variables used by the routine before they are referenced. (i.e. do not declare new variables in the subprocedure that are referenced by the routine.)

Define subprocedures at the end of the routine ahead of any VisualPQL Procedures or an AFTER RETRIEVAL block. There is an implicit STOP (or RETURN if the routine is a subroutine) just before the first subprocedure.

The SUBPROCEDURE command begins a subprocedure definition. The subprocedure definition ends with the END SUBPROCEDURE command.

If you define a subprocedure with the name RT_ERROR, this procedure is given control if a run time error occurs. It is then this subprocedure's responsibility to take any appropriate action necessary. If the subprocedure does not exit the routine, control is passed back to the next command following the command that caused the run time error.

NOAUTOCASE Specifies that the subprocedure is called from within a CASE block, allowing specification of a RECORD block within the subprocedure and/or references to CIR variables. If the subprocedure is executed outside a CASE block, the execution of a RECORD block causes an error and the main routine terminates. Any references to variables with names matching CIR variable names reference CIR variables. If the subprocedure is executed outside a CASE block, references to CIR variables return undefined values.

References to other variables in the subprocedure are to local variables, unless within a RECORD block physically specified in the subprocedure itself, even if the subprocedure is executed from within a record block. However, if the subprocedure is executed from within a record block, this alters the behaviour of certain VisualPQL functions that allow an expression as a variable name, such as VARGET and VARPUT. Because these functions resolve their variable references at execution time and are checked against any CIR variables, then any active record variables ahead of any local variables, execution of these functions from within a record block references any matching record variable regardless as to whether the functions are in a subprocedure.

END SUBPROCEDURE

END SUBPROCEDURE ends the block of subprocedure code. Control is passed back to the first command following the EXECUTE SUBPROCEDURE command that invoked the subprocedure.

EXIT SUBPROCEDURE

EXIT SUBPROCEDURE exits the subprocedure and control is passed to the first statement following the EXECUTE SUBPROCEDURE command that invoked the subprocedure.

homecontents start chapter top of pagebottom of pagenext page index

EXECUTE SUBPROCEDURE

EXECUTE SUBPROCEDURE name

Transfers control to the first line of code in the named subprocedure. When the subprocedure is exited, control returns to the first statement following the EXECUTE SUBPROCEDURE. This command may appear anywhere in a routine including within a subprocedure.

Subprocedure Example:

PROGRAM
TIME NOON NOWTIME ('HHiMM')   | declare time variables
COMPUTE NOON = '12:00'        | set the value of midday
COMPUTE NOWTIME = NOW(0)      | get the current time
IFTHEN (NOWTIME LT NOON)
.   EXECUTE SUBPROCEDURE MORNING    | execute MORNING
. ELSE
.   EXECUTE SUBPROCEDURE AFTERN     | execute AFTERN
ENDIF
SUBPROCEDURE MORNING
. WRITE 'Good Morning'
END SUBPROCEDURE
SUBPROCEDURE AFTERN
. WRITE 'Good Afternoon'
END SUBPROCEDURE
END PROGRAM

homecontents start chapter top of pagebottom of pagenext page index