Was this helpful?
Variable and Type Declarations
The following sections describe Ada variable and type declarations.
EQUEL Variable Declarations Procedures
EQUEL statements use Ada variables to transfer data from a database or a form into the program and conversely. You must declare Ada variables to EQUEL before using them in EQUEL statements. Ada variables are declared to EQUEL by preceding the declaration with the ## mark. The declaration must be in a syntactically correct position for the Ada language.
In general, each declared object can be referred to in the scope of the enclosing compilation unit. An object name cannot be redeclared in the same compilation unit scope. For details on the scope of types and variables, see Compilation Units and the Scope of Variables.
The With Equel and With Equel_Forms Statements
Along with your declarations, and prior to any executable EQUEL statements or Ada compilation units in your file, you must issue the following Ada with statement:
## with equel;
If the compilation unit uses EQUEL/FORMS statements, you should instead issue the statement:
## with equel_forms;
The above statements instruct the preprocessor to generate code to call Ingres runtime libraries. Both statements generate Ada with and use statements to make all the generated calls acceptable to the Ada compiler by including their package specifications. Note that both statements must terminate with a semicolon, as required by Ada.
The EQUEL and EQUEL_FORMS package specifications should already be in your Ada program library. (For the appropriate procedures, see Entering EQUEL Package Specifications.) Both packages assume that the types integer, float, string, and address have not been redefined by any other packages or type declarations included in your file.
Reserved Words in Declarations and Program Units
All EQUEL keywords are reserved. You cannot declare variables with the same names as EQUEL keywords. You can only use them in quoted string literals. These words are:
access
array
body
case
constant
declare
delta
digits
function
limited
new
others
package
private
procedure
record
renames
return
separate
subtype
type
when
use
Data Types and Constants
The EQUEL/Ada preprocessor accepts certain data types and constants from the Ada STANDARD and SYSTEM packages. The table below maps the types to their corresponding Ingres type categories. For information on the exact type mapping, see Data Type Conversion.
Ada Data Types and Corresponding Ingres Types
Ada Type
Ingres Type
short_short_integer
integer
short_integer
integer
integer
integer
natural
integer
positive
integer
boolean
integer
float
float
long_float
float
f_float
float
d_float
float
character
character
string
character
None of the types listed above should be redefined by your program. If they are redefined, your program may not compile and will not work correctly at runtime.
The table in Ada Constants and Corresponding Ingres Types (see Ada Constants and Corresponding Ingres Types) maps the Ada constants to their corresponding Ingres type categories.
Ada Constants and Corresponding Ingres Types
Ada Constant
Ingres Type
max_int
integer
min_int
integer
true
integer
false
integer
Note that, if the type or constant is derived from the SYSTEM package, the program unit must specify that the SYSTEM package should be included—EQUEL does not do so itself. You cannot refer to a SYSTEM object by using the package name as a prefix, because EQUEL does not allow this type of qualification. The types f_float and d_float and the constants max_int and min_int are derived from the SYSTEM package.
The Integer Data Type
All integer types and their derivatives are accepted by the preprocessor. Even though some integer types do have Ada constraints, such as the types natural and positive, EQUEL does not check these constraints, either during preprocessing or at runtime. An integer constant is treated as an EQUEL constant value and cannot be the target of a Ingres assignment.
The type boolean is handled as a special type of integer. In Ada, the boolean type is defined as an enumerated type with enumerated literals false and true. EQUEL treats the boolean type as an enumerated type and generates the correct code in order to use this type to interact with a Ingres integer. Enumerated types are described in more detail later.
The Float Data Type
There are four floating-point types that are accepted by the preprocessor. The types float and f_float are the 4-byte floating-point types. The types long_float and d_float are the 8-byte floating-point types. Long_float requires some extra definitions or default Ada pragmas to be able to interact with Ingres floating-point types. Note that the preprocessor does not accept long_long_float and h_float data types.
The Long Float Storage Format
Ingres requires that the storage representation for long floating-point variables be d_float, because the EQUEL runtime system uses that format for floating-point conversions. If your EQUEL program has long_float variables that interact with the EQUEL runtime system, you must make sure they are stored in the d_float format. Floating-point values of types g_float and h_float are stored in different formats and sizes. The default Ada format is g_float; consequently, you must convert your long floating-point variables to type d_float. You can use three methods to ensure that the Ada compiler always uses the d_float format.
The first method is to issue the following Ada pragma before every compilation unit that declares long_float variables:
pragma long_float( d_float );
...
## dbl: long_float;
Note that the pragma statement is not an EQUEL statement, but an Ada statement that directs the compiler to use a different storage format for long_float variables.
The second method is a more general instance of the first. If you are certain that all long_float variables in your Ada program library will use the d_float format, including those not interacting with Ingres, then you can install the pragma into the program library by issuing the following ACS command:
$ acs set pragma/long_float=d_float
This system-level command is equivalent to issuing the Ada pragma statement for each file that uses long_float variables.
The third method is to use the type d_float instead of the type long_float. This has the advantage of allowing you to mix both d_float and g_float storage formats in the same compilation unit. Of course, all EQUEL floating-point variables must be of the d_float type and format. For example:
## d_dbl: d_float;
   g_dbl: g_float; -- Unknown to EQUEL
One side effect of all the above conversions is that some default system package instantiations for the type long_float become invalid, because they are set up under the g_float format. For example, the package LONG_FLOAT_TEXT_IO, which is used to write long floating-point values to text files, must be reinstantiated. Assuming that you have issued the following ACS command on your program library:
$ acs set pragma/long_float=d_float
you must reinstantiate the LONG_FLOAT_TEXT_IO package before you can use it. A typical file might contain the following two lines, which serve to enter your own copy of LONG_FLOAT_TEXT_IO into your library:
with text_io;
package long_float_text_io is new
    text_io.float_io(long_float);
A later statement, such as:
with long_float_text_io; use long_float_text_io;
will pick up your new copy of the package, which is defined using the d_float internal storage format.
The Character and String Data Types
Both the character and string data types are compatible with Ingres string objects. By default, the string data type is an array of characters.
The character data type does have some restrictions. Because it must be compatible with Ingres string objects, you can use only a one-dimensional array of characters. Therefore, you cannot use a single character or a multidimensional array of characters. Note that you can use a multidimensional array of strings.
For example, the following four declarations are legal:
## subtype Alphabet is Character range 'a'..'z';
## type word_5 is array(1..5) of Character; 
                                    -- 1-dimensional array
## word_6: String(1..6);            -- Default string type
## word_arr: array(1..5) of String(1..6);
                                    -- Array of strings
However, the declarations below are illegal, because they violate the EQUEL restrictions for the character type. Although the declarations may not generate EQUEL errors, the references will not be accepted by the Ada compiler when used with EQUEL statements. For example:
## letter: Character; -- 1 character
## word_arr: array(1..5) of word_5; 
                      -- 2-dimensional array of char
Both could be declared instead with the less restrictive string type:
## letter: array(1..1) of Character;-- or equivalently...
## letter: String(1..1);
## word_arr: array(1..5) of String(1..6);   -- Array of strings
Variable and Number Declaration Syntax
The following sections describe the syntax for variable and number declarations.
Simple Variable Declarations
An EQUEL/Ada variable declaration has the following syntax:
identifier {, identifier} :
                             [constant]
                             [array (dimensions) of]
                             type_name
                             [type_constraint]
                             [:= initial_value];
Syntax Notes:
1. The identifier must be a legal Ada identifier beginning with an alphabetic character.
2. If the constant clause is specified, the declaration must include an explicit initialization.
3. If the constant clause is specified, the declared variables cannot be targets of Ingres assignments.
4. The dimensions of an array specification are not parsed by the EQUEL preprocessor. Consequently, unconstrained array bounds and multidimensional array bounds will be accepted by the preprocessor. However, an illegal dimension (such as a non-numeric expression) will also be accepted but will cause Ada compiler errors. For example, both of the following declarations are accepted, even though only the first is legal Ada:
## square: array (1..10, 1..10) of Integer;
## bad_array: array ("dimensions") of Float;
5. The type_name must be either an EQUEL/Ada type (see Data Types and Constants) or a type name already declared to EQUEL.
6. The legal type_constraints are described in the next section.
7. The initial_value is not parsed by the preprocessor. Consequently,
any initial value is accepted, even if it may later cause a Ada compiler error. For example, both of the following initializations are accepted, even though only the first is legal Ada:
## rowcount: Integer := 1;
## msgbuf: String(1..100) := 2; 
        -- Incompatible value
You must not use a single quote in an initial value to specify an Ada attribute. EQUEL will treat it as the beginning of a string literal and will generate an error. For example, the following declaration will generate an error:
id: Integer := Integer 'first
## rows, records:Integer range 0..500 := 0;
## was_error:    Boolean;
## min_sal:          constant Float := 15000.00;
## msgbuf:           String(1..100) := (1..100 = ' ');
## operators:  constant array(1..6) of String(1..2)
##         := ("= ", "!=", "< ", "> ", "<=", ">=");
Type Constraints
Type constraints can optionally follow the type name in an Ada object declaration. In general, they do not provide EQUEL with runtime type information, so they are not fully processed. The following two constraints describe the syntax and restrictions of EQUEL type constraints.
The Range Constraint
The syntax of the range constraint is:
range lower_bound .. upper_bound
In a variable declaration, its syntax is:
identifiertype_name range lower_bound .. upper_bound;
Syntax Notes:
1. Even if a range constraint is not allowed by Ada, it will be accepted by EQUEL. For example, both of the following range constraints are accepted, although the second is illegal in Ada because the string type is not a discrete scalar type:
## digit: Integer range 0..9;
## chars: String range 'a'..'z';
2. The two bounds, lower_bound and upper_bound, must be integer literals, floating-point literals, character literals, or identifiers. Other expressions are not accepted.
3. The bounds are not checked for compatibility with the type_name or with each other. For example, the following three range constraints are accepted, even though only the first is legal Ada:
## byte: Integer range -128..127;
## word: Integer range 1.0..30000.0;
                                 -- Incompatible with type name
## long: Integer range 1..'z';   -- Incompatible  with each other
The Discriminant and Index Constraints
The discriminant and index constraints have the following syntax:
(discriminant_or_index_constraint)
In a variable declaration the syntax is:
identifier: type_name (discriminant_or_index_constraint);
Syntax Notes:
1. Even if a constraint is not allowed by Ada, it will be accepted by EQUEL. For example, both of the following constraints are accepted, even though the second is illegal in Ada because the integer type does not have a discriminant:
## who: String(1..20);-- Legal index constraint
## nat: Integer(0);   -- Illegal context for discriminant
2. The contents of the constraint contained in the parentheses are not processed. Consequently, any constraint will be accepted, even if not allowed by Ada. For example, the following declaration will be accepted by EQUEL but will generate a later Ada compiler error because of the illegal index constraint:
## password: String(secret word);
Note that the above type constraints are not discussed in detail after this section, and their rules and restrictions are considered part of the EQUEL/Ada declaration syntax.
Formal Parameter Declarations
An EQUEL/Ada formal parameter declaration has the following syntax:
identifier {identifier:
              
[in out | in out]
              type_name
              [:= default_value]
              [;]
In a subprogram declaration, its syntax is:
procedure name ( parameter_declaration {parameter_declaration} )
 is
              
...
or
function name ( parameter_declaration {parameter_declaration)
              return 
type_name is
              
...
Syntax Notes:
1. If the in mode alone is specified, the declared parameters are considered constants and cannot be targets of Ingres assignments.
2. If no mode is specified, the default in mode is used and the declared parameters are considered constants.
3. The type_name must be either an EQUEL/Ada type or a type name already declared to EQUEL.
4. The default_value is not parsed by the preprocessor. Consequently, any default value is accepted, even if it may cause a later Ada compiler error. For example, both of the following parameter defaults are accepted, even though only the first is legal in Ada:
## procedure Load_Table
##     (clear_it: in Boolean := TRUE;
##     is_error: out Boolean := "FALSE") is
 ...
You must not use a single quote in a default value to specify an Ada attribute. EQUEL will treat it as the beginning of a string literal and will generate an error.
5. The semicolon is required with all parameter declarations except the last.
6. The scope of the parameters is the subprogram in which they are declared. For detailed scope information, see Compilation Units and the Scope of Variables.
Number Declarations
An EQUEL/Ada number declaration has the following syntax:
identifier {identifier:
              constant:= 
initial_value;
Syntax Notes:
1. A number declaration is only allowed for integer numbers. You cannot declare a floating-point number declaration using this format. If you do, EQUEL will treat it as an integer number declaration, causing later compiler errors. For example, the following two number declarations are treated as integer number declarations, even though the second is a float number declaration:
## max_employees: constant := 50000;
## min_salary: constant := 13500.0; --Treated as INTEGER
To declare a constant float declaration, you must use the constant variable syntax. For example, the second declaration above should be declared as:
## min_salary: constant Float := 13500.0;  -- Treated as FLOAT
2. The declared numbers cannot be the targets of Ingres assignments.
3. The initial_value is not parsed by the preprocessor. Consequently, any initial value is accepted, even if it may later cause an Ada compiler error. For example, both of the following initializations are accepted, even though only the first is a legal Ada number declaration:
## no_rows: constant := 0;
## bad_num: constant := 123 + "456";
You must not use a single quote in an initial value to specify an Ada attribute. EQUEL will treat it as the beginning of a string literal and will generate an error.
Renaming Variables
The syntax for renaming variables is:
identifiertype_name renames declared_object;
Syntax Notes:
1. The type_name must be a predeclared type, and the declared_object must be a known EQUEL variable or constant.
2. The declared_object must be compatible with the type_name in base type, array dimensions and size.
3. If the declared object is a record component, any subscripts used to qualify the component are ignored. For example, both of the following rename statements will be accepted even though one of them must be wrong, depending on whether "emprec" is an array:
## eage1: Integer renames emprec(2).age;
## eage2: Integer renames emprec.age;
Type Declaration Syntax
EQUEL/Ada supports a subset of Ada type declarations. In a declaration, the EQUEL preprocessor only notes semantic information relevant to the use of the variable in EQUEL statements at runtime. Other semantic information is ignored by the preprocessor. Refer to the syntax notes in this section and its subsections for details.
Type Definition
An EQUEL/Ada full type declaration has the following syntax:
type identifier [discriminant_partis type_definition;
Syntax Notes:
1. The discriminant_part has the syntax:
(discriminant_specifications)
and is not processed by EQUEL. As with variable declarations, a discriminant specification will always be accepted by EQUEL, even if not allowed by Ada. For example, the following declaration will be accepted by EQUEL but will later generate an Ada compiler error, because the discriminant type is not a discrete type and the discriminant part is not allowed in a non-record declaration:
## type shapes(name: String := "BOX") 
##      is array(1..10) of String(1..3);
From this point on, discriminant parts are not included in the syntax descriptions or notes.
2. The legal type_definitions allowed in type declarations are described below.
Subtype Definition
An EQUEL/Ada subtype declaration has the following syntax:
subtype identifier is type_name [type_constraint];
Syntax Note:
The type_constraint has the same rules as the type constraint of a variable declaration. The range, discriminant, and index constraints are all allowed and are not processed against the type_name being used. For more details about these constraints, refer to the section above on variable type constraints. The floating-point constraint and the digits clause, which are allowed in subtype declarations, are discussed later.
Integer Type Definitions
The syntax of an EQUEL/Ada integer type definition is:
range lower_bound .. upper_bound
In the context of a type declaration, the syntax is:
type identifier is range lower_bound .. upper_bound;
In the context of a subtype declaration, the syntax is:
subtype identifier is integer_type_name
               range lower_bound .. upper_bound;
Syntax Notes:
1. In an integer type declaration (not a subtype declaration), the range constraint of an integer type definition is processed by EQUEL to evaluate storage size information. Both lower_bound and upper_bound must be integer literals. Based on the specified range and the actual values of the bounds, EQUEL treats the type as a byte-size, a word-size, or a longword-size integer. For example:
## type Table_Num is range 1..200;
2. In an integer subtype declaration, the range constraint is
treated as a variable range constraint and is not processed. Consequently, the same rules that apply to range constraints for variable declarations apply to integer range constraints for integer subtype declarations. The base type and storage size information is determined from the integer_type_name used. For example:
## subtype Ingres_I1 is Integer range -128..127;
## subtype Ingres_I2 is Integer range -32768..32767;
## subtype Table_Low is Table_Num range 1..10;
## subtype Null_Ind  is Short_Integer range -1..0;   -- Null Indicator
Floating-point Type Definitions
The syntax of an EQUEL/Ada floating-point type definition is:
digits digit_specification [range_constraint]
In the context of a type declaration the syntax is:
type identifier is digits digit_specification [range_constraint];
The syntax of a floating-point subtype declaration is:
subtype identifier is floating_type_name
              [digits digit_specification]
              [range_constraint];
Syntax Notes:
1. The value of digit_specification must be an integer literal. Based on the value of the specification, EQUEL will determine whether to treat a variable of that type as a 4-byte float or an 8-byte float. The rules in the following table are applicable.
Digit Range
Type
1 < = d < = 6
4-byte floating-point type
7 < = d < = 16
8-byte floating-point type
Note that if the digits specified are out of range, the type is unusable. Recall that EQUEL does not accept either the long_long_float or the h_float type. For detailed information on the internal storage format for 8-byte floating-point variables, see The Long Float Storage Format.
2. The range_constraint for floating-point types and subtypes is treated as a variable range constraint and is not processed. Although EQUEL will allow any range constraint, you should not specify a range constraint that will alter the size needed to store the declared type. EQUEL obtains its type information from the digits clause, and altering this type information by a range clause, which may require more precision, will result in runtime errors.
3. The digits clause in a subtype declaration does not have any effect on the EQUEL type information. This information is obtained from floating_type_name. For example:
## type Emp_Salary   is digits 8 range
                    0.00..500000.00;

## subtype Directors_Sal is Emp_Salary
                    100500.00..500000.00;
## subtype Raise_Percent is Float range 1.05..1.20;
Enumerated Type Definitions
The syntax of an EQUEL/Ada enumerated type definition is:
(enumerated_literal {enumerated_literal})
In the context of a type declaration, the syntax is:
type identifier is (enumerated_literal {enumerated_literal});
In the context of a subtype declaration, the syntax is:
subtype identifier is enumerated_type_name [range_constraint];
Syntax Notes:
1. There can be at most 1,000 enumerated literals in an enumerated type declaration. The preprocessor treats all literals and variables declared with this type as integers. Enumerated literals are treated as though they were declared with the constant clause, and therefore they cannot be the targets of Ingres assignments. When an enumerated literal is used with embedded statements, only the ordinal position of the value in relation to the original enumerated list is relevant. When assigning from an enumerated variable or literal, the preprocessor generates:
enumerated_type_name'pos(enumerated_literal)
When assigning from or into an enumerated variable, the preprocessor passes the object by address and assumes that the value being assigned from or into the variable will not raise a runtime constraint error.
2. An enumerated literal can be an identifier or a character literal. EQUEL does not store or process enumerated literals that are character literals.
3. Enumerated literal identifiers must be unique in their scope. EQUEL does not allow the overloading of variables or constants.
4. The range_constraint for enumerated subtypes is treated as a variable range constraint and is not processed. The type information is determined from enumerated_type_name. For example:
## type Table_Field_States is
## (UNDEFINED, NEWROW, UNCHANGED, CHANGED, DELETED);
## subtype Updated_States is Table_Field_States
## range CHANGED..DELETED;
## tbstate: Table_Field_States := UNDEFINED;
5. EQUEL accepts the predefined enumeration type name boolean that contains the two literals FALSE and TRUE.
6. You can use a representation clause for enumerated types. When you do so, however, you should not reference any enumerated literals of that type in the embedded statements. Enumerated literals are interpreted into their integer relative position (pos) and representation clauses invalidate the effect of the pos attribute that the preprocessor generates. The representation clauses should not be preceded by the ## mark.
7. Enumerated variables and literals can only be used to assign to or from Ingres. These objects cannot be used to specify simple numeric objects, such as table field row numbers or sleep statement seconds.
Array Type Definitions
The syntax of an EQUEL/Ada array type definition is:
array (dimensions) of type_name;
In the context of a type declaration, the syntax is:
type identifier is array (dimensions) of
              
type_name [type_constraint];
Syntax Notes:
1. The dimensions of an array specification are not parsed by the EQUEL preprocessor. Consequently, unconstrained array bounds and multidimensional array bounds will be accepted by the preprocessor. However, an illegal dimension (such as a non-numeric expression) will also be accepted but will later cause Ada compiler errors. For example, both of the following type declarations are accepted, even though only the first is legal in Ada:
## type Square is array(1..10, 1..10) of Integer;
## type What is array("dimensions") of Float;
Because the preprocessor does not store the array dimensions, it only checks to determine that when the array variable is used, it is followed by a subscript in parentheses.
2. The type_constraint for array types is treated as a variable type constraint and is not processed. The type information is determined from type_name.
3. Any array built from the base type character (not string) must be exactly one-dimensional. EQUEL will treat the whole array as though it were declared as type string. If more dimensions are declared for a variable of type character, EQUEL will still treat it as a one-dimensional array.
4. The type string is the only array type.
Record Type Definitions
The syntax of an EQUEL/Ada record type definition is:
record
              
record_component {record_component}
end record;
where record_component is:
component_declarationvariant_partnull;
where component_declaration is:
identifier {identifier:
              
type_name [type_constraint] [:= initial_value]
In the context of a type declaration, the syntax of a record type definition is:
type identifier is
              record
                            
record_component record_component}
              end record;
Syntax Notes:
1. In a component_declaration, all clauses have the same rules and restrictions as they do in a regular type declaration. For example, as in regular declarations, the preprocessor does not check initial values for correctness.
2. The variant_part accepts the Ada syntax for variant records: if specified, it must be the last component of the record. The variant discriminant name, choice names, and choice ranges are all accepted. There is no syntactic or semantic checking on those variant objects. EQUEL uses only the final component names of the variant part and not any of the variant object names.
3. You can specify the null record.
4. A record_component can also be Ada host code. Consequently, you can include components that will not be used by EQUEL (and with types unknown to EQUEL), by not marking the line with a ## mark. Also, if some variant_part syntaxes are not accepted by EQUEL, you do not have to mark those lines, as EQUEL does not store the variant information. For example:
## type Address_Rec is
## record
##    street: String(1..30);
##    town: String(1..10);
##    zip: Positive;
## end record;
 
## type Employee_Rec is
## record
##    name:   String(1..20);
##    age:    Short_Short_Integer;
##    salary: Float := 0.0;
##    address: Address_Rec;
-- The following two components are unknown to EQUEL
        scale:   Long_Long_Float;
        checked: Boolean := FALSE;
## end record;
Incomplete Type Declarations and Access Types
The incomplete type declaration should be used with an access type. The syntax for an incomplete type declaration is:
type identifier [discriminant_part];
Syntax Notes:
1. As with other type declarations, the discriminant_part is ignored.
2. You must fully define an incomplete type before using any object declared with it.
The syntax for an access type declaration is:
type identifier is access type_name [type_constraint];
Syntax Notes:
1. The type_name must be a predeclared type, whether it is a full type declaration or an incomplete type declaration.
2. The type_constraint has the same rules as other type declarations.
The following is an example of the incomplete type declaration:
## type Employee_Rec; -- Incomplete declaration
## type Employee is access 
##        Employee_Rec;-- Access to above

## type Employee_Rec is -- Real definition
## record
##    name: String(1..20);
##    age: Short_Short_Integer;
##    salary: Float := 0.0;
##    link: Employee;
## end record;
Derived Types
The syntax for a derived type is:
type identifier is new type_name [type_constraint];
Syntax Notes:
1. The type_name must be a predeclared type, whether it is a full type declaration or an incomplete type declaration.
2. EQUEL assigns the type being declared the same properties as the type_name specified. The preprocessor will make sure that any variables of a derived type are cast into the original base type when used with the runtime routines.
3. The type_constraint has the same rules as other type declarations.
The following example illustrates the use of the derived type:
##  type Dbase_Integer is new Integer;
Private Types
The syntax for a private type is:
type identifier is [limitedprivate;
Syntax Note:
This type declaration is treated as an incomplete type declaration. You must fully define a private type before using any object declared with it.
Representation Clauses
With one exception, you must not use the representation clause for any types or objects you have declared to EQUEL and intend to use with the EQUEL runtime system. Any such clause will cause runtime errors. These clauses include the Ada statement:
for type_or_attribute use expression;
and the Ada pragma:
pragma pack(type_name);
The exception is that you can use a representation clause to specify internal values for enumerated literals. When you do so, however, you should not reference any enumerated literals of the modified enumerated type in embedded statements. The representation clause invalidates the effect of the pos attributes that the preprocessor generates. If the application context is one that requires the assignment from the enumerated type, then you should deposit the literal into a variable of the same enumerated type and assign that variable to Ingres. In all cases, do not precede the representation clause with the ## mark.
For example:
    ## type Opcode is (OPADD, OPSUB, OPMUL);
    for Opcode use (OPADD => 1, OPSUB => 2, 
                        OPMU, =>4);
    ...
        opcode_var ;= OPSUB;
## append to codes (opcode = opcode_var);
Indicator Variables
An indicator variable is a 2-byte integer variable. There are three possible ways to use these in an application:
In a statement that retrieves data from Ingres, you can use an indicator variable to determine if its associated host variable was assigned a null.
In a statement that sets data to Ingres, you can use an indicator variable to assign a null to the database column, form field, or table field column.
In a statement that retrieves character data from Ingres, you can use the indicator variable as a check that the associated host variable is large enough to hold the full length of the returned character string.
To declare an indicator variable you should use the short_integer data type. The following example declares two indicator variables:
## ind: Short_Integer; -- Indicator variable
## ind_arr: array(1..10) of Short_Integer; -- Indicator array
Note that a variable declared with any derivative of the short_integer data type will be accepted as an indicator variable.
Assembling and Declaring External Compiled Forms
You can pre-compile your forms in the Visual Forms Editor (VIFRED). This saves the time otherwise required at runtime to extract the form's definition from the database forms catalogs. When you compile a form in VIFRED, VIFRED creates a file in your directory describing the form in the VAX-11 MACRO language. VIFRED prompts you for the name of the file with the MACRO description. After the file is created the file, use the following VMS command to assemble it into a linkable object module:
macro filename
This command produces an object file containing a global symbol with the same name as your form. Before the EQUEL/FORMS statement addform can refer to this global object, it must be declared in an EQUEL declaration section. The Ada compiler requires that the declaration be in a package and that the objects be imported with the import_object pragma.
The syntax for a compiled form package is:
##    package compiled_forms_package is
##        formname: Integer;
                          pragma import_object( formname );
##    end compiled_forms_package;
You must then issue the Ada with and use statements on the compiled form package before every compilation unit that refers to the form:
with compiled_forms_package; use compiled_forms_package;
Syntax Notes:
1. The formname is the actual name of the form. VIFRED gives this name to the address of the external object. The formname is also used as the title of the form in other EQUEL/FORMS statements. In all statements that use formname as the form title you must dereference the name with a # sign.
2. The import_object pragma associates the object with the external form definition. In order to use this pragma, the package must be issued in the outermost scope of the file.
The next example shows a typical form declaration and illustrates the difference between using the form's object definition and the form's name.
## package Compiled_Forms is
## empform: Integer;
        pragma import_object( empform );
## end Compiled_Forms;
        ...

with Compiled_Forms; use Compiled_Forms;
        ...

## addform empform; -- The imported object
## display #empform; -- The name of the form
        ...
Concluding Example
The following example demonstrates some simple EQUEL/Ada declarations:
## package Compiled_Forms is
## empform, deptform: Integer; -- Compiled forms

pragma import_object( empform );
pragma import_object( deptform );
## end Compiled_Forms;

with Compiled_Forms; use Compiled_Forms;

## package Concluding_Example is

## MAX_PERSONS: constant := 1000;
## dbname: String(1..9) := "personnel";
## formname, tablename, columnname: String(1..12);
## salary: Float;
## type DATATYPES_REC is -- Structure of all types
##   d_byte:   Short_Short_Integer;
##   d_word:   Short_Integer;
##   d_long:   Integer;
##   d_single: Float;
##   d_double: Long_Float;
##   d_string: String(1..20);
## end record;
## d_rec: DATATYPES_REC;
## -- Record with a discriminant
## record PERSONTYPE_REC (married: in Boolean) is
##   age: Short_Short_Integer;
##   flags: Integer;
##   case married:
##     when TRUE =>
##        spouse_name: String(1..30);
##     when FALSE =>
##        dog_name: String(1..12);
##   end case;
## end record;
## person: PERSONTYPE_REC(TRUE);
## person_store: array(1..MAX_PERSONS) of PERSONTYPE_REC(FALSE);

## ind_var: Short_Integer := -1; -- Indicator Variable

## end Concluding_Examples;
Last modified date: 01/30/2023