Variable Usage
Ada variables declared to EQUEL can substitute for most elements of EQUEL statements that are not keywords. Of course, the variable and its data type must make sense in the context of the element. To use an Ada variable in an EQUEL statement, just use its name. To refer to an element, such as a database column, with the same name as a variable, dereference the element by using the EQUEL dereferencing indicator (#). As an example of variable usage, the following retrieve statement uses the variables "namevar" and "numvar" to receive data, and the variable "idnovar" as an expression in the where clause:
## retrieve (namevar = e.name, numvar = e.num)
## where e.idno = idnovar;
When referencing a variable, you cannot use an Ada attribute, because the attribute is introduced by a single quote. EQUEL will treat this single quote as the beginning of a string literal and will generate a syntax error.
When referencing a variable, you also cannot use the dotted notation to refer to hidden or ambiguous objects by prefixing the object with a subprogram or package name, even if the package is explicitly declared. EQUEL will generate a syntax error on the qualifying dot.
If, in retrieving from Ingres into a program variable, no value is returned for some reason (for example, no rows qualified in a query), the variable will contain an undefined value.
Various rules and restrictions apply to the use of Ada variables in EQUEL statements. The sections below describe the usage syntax of different categories of variables and provide examples of such use.
Simple Variables
A simple scalar-valued variable (integer, floating-point or character string) is referred to by the syntax:
simplename
Syntax Notes:
1. If the variable is used to send data to Ingres, it can be any scalar-valued variable, constant or enumerated literal.
2. If the variable is used to receive data from Ingres, it cannot be a variable declared with the constant clause, a formal parameter that does not specify the outmode, a number declaration, or an enumerated literal.
3. A string variable (a 1-dimensional array of characters) is referenced as a simple variable.
The following program fragment demonstrates a typical message-handling routine that uses two scalar-valued variables, "buffer" and "seconds":
## procedure Msg (buffer: String; seconds: Integer) is
## begin
## message buffer
## sleep seconds
## end Msg;
A special case of a scalar type is the enumerated type. The preprocessor treats all enumerated literals and any variables declared with an enumerated type as integers. When an enumerated literal is used in an EQUEL statement, only the ordinal position of the value in relation to the original enumerated list is relevant. When assigning from an enumerated literal, the preprocessor generates the following:
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. In order to relax the restriction imposed by the preprocessor on enumerated literal assignments (of enumerated types that have included representation clauses to modify their values), you should assign the literal to a variable of the same enumerated type before using it in an embedded statement. For example, the following enumerated type declares the states of a table field row, and the variable of that type will always receive one of those values:
## type Table_Field_States is
## (UNDEFINED, NEWROW, UNCHANGED, CHANGED, DELETED);
## tbstate: Table_Field_States := UNDEFINED;
## ename: String(1..20);
...
## getrow empform employee
## (ename = name, tbstate = _state);
case tbstate is
when UNDEFINED =>
...
end case;
Another example retrieves the value TRUE (an enumerated literal of type boolean) into a variable when a database qualification is successful:
## found: Boolean;
## qual: String(1..100);
..
## retrieve (found = TRUE) where qual;
if (not found) then
...
end if;
Array Variables
An array variable is referred to by the syntax:
arrayname(subscript{,subscript})
Syntax Notes:
1. The variable must be subscripted, because only scalar-valued elements (integers, floating-point, and character strings) are legal EQUEL values.
2. When the array is declared, the array bounds specification is not parsed by the EQUEL preprocessor. Consequently, illegal bounds values will be accepted. Also, when an array is referenced, the subscript is not parsed, allowing illegal subscripts to be used. The preprocessor only confirms that an array subscript is used for an array variable. You must make sure that the subscript is legal and that the correct number of indices is usedA character string variable is not an array and cannot be subscripted in order to reference a single character or a slice of the string. For example, if the following variable were declared:
## abc: String(1..3) := "abc";
you could not reference
abc(1)
to access the character "a." To perform such a task, you should declare the variable as an array of three one-character long strings. For example:
## abc: array(1..3) of String(1..1) := ("a","b","c");
Note that variables of the Ada character type can only be declared as a one-dimensional array. When a variable of that type is used, it must not be subscripted. In the following example, the loop variable "i" is used as a subscript and need not be declared to EQUEL, as it is not parsed.
## formnames: array(1..3) of String(1..8);
...
for i in 1..3 loop
## forminit formnames(i)
end loop;
Record Components
The syntax EQUEL uses to refer to a record component is the same as in Ada:
record.component{.component}
Syntax Notes:
1. The last record component denoted by the above reference must be a scalar value (integer, floating-point or character string). There can be any combination of arrays and records, but the last object referenced must be a scalar value. Thus, the following references are all legal:
-- Assume correct declarations for "employee",
-- "person" and other records.
employee.sal -- Component of a record
person(3).name -- Component of an element of an
array
rec1.mem1.mem2.age -- Deeply nested component
2. All record components must be fully qualified when referenced. You can shorten the qualification by using the Ada renames clause in another declaration to rename some components or nested records.
The following example uses the array of records "emprec" to load values into the tablefield "emptable" in form "empform."
## type Employee_Rec is
## record
## ename: String(1..20);
## eage: Short_Integer;
## eidno: Integer;
## ehired: String(1..25);
## edept: String(1..10);
## esalary: Float;
## end record;
## emprec: array(1..100) of Employee_Rec;
...
for i in 1..100 loop
## loadtable empform emptable
## (name = emprec(i).ename, age = emprec(i).eage,
## idno = emprec(i).eidno,
## hired = emprec(i).ehired,
## dept = emprec(i).edept,
## salary = emprec(i).esalary)
end loop;
If you want to shorten the reference to the record, you can use the renames clause to rename a particular member of the "emprec" array, as in the following example:
for i in 1..100 loop
## declare
## er: Employee_Rec renames emprec(i);
## begin
## loadtable empform emptable
## (name = er.ename, age = er.eage,
## idno = er.eidno, hired = er.ehired,
## dept = er.edept, salary = er.esalary)
## end;
end loop;
Access Variables
An access variable must qualify another object by means of the dot operator, using the same syntax as a record component:
access.reference
Syntax Notes:
1. By the time an access variable is referenced, the type to which it is pointing must be fully defined. This is true even for access types that were declared to point at incomplete types.
2. The final object denoted by the above reference must be a scalar value (integer, floating-point or character string). There can be any combination of arrays, records or access variables, but the last object referenced must be a scalar valuIf an access variable is pointing at a scalar-valued type, then the qualification must include the Ada .all clause to refer to the scalar value. If used, the .all clause must be the last component in the qualification. For example:
## type Access_Integer is access Integer;
## ai: Access_Integer;
...
ai := new Integer'(2);
## sleep ai.all
In the following example, an access type to an employee record is used to load a linked list of values into the Employee database table:
## type Employee_Rec;
## type Emp_Link is access Employee_Rec;
## type Employee_Rec is
## record
## ename: String(1..20);
## eage: Short_Integer;
## eidno: Integer;
## enext: Emp_Link;
## end record;
## elist: Emp_Link;
...
while (elist /= null) loop
## repeat append to employee
## (name = @elist.ename, age = @elist.eage,
## idno = @elist.eidno)
elist := elist.enext;
end loop;
Using Indicator Variables
The syntax for referring to an indicator variable is the same as for a simple variable, except that an indicator variable is always associated with a host variable:
host_variable:indicator_variable
Syntax Note:
The indicator variable can be a simple variable, an array element or a record component that yields a 2-byte integer (short_integer). For example:
## ind: Short_Integer; -- Indicator variable
## ind_arr: array(1..10) of Short_Integer; -- Indicator
-- array
var_1:ind_var
var_2:ind_arr(2)