Variable Declarations
The following sections describe variable declarations.
Embedded SQL Variable Declaration Sections
Embedded SQL statements use BASIC variables to transfer data to and from the database or a form into the program. BASIC constants can also be used in those SQL statements transferring data from the program into the database. You must declare BASIC variables, constants, and structure definitions to SQL before using them in any Embedded SQL statements. The preprocessor does not allow implicit variable declarations. For this reason, the "%" and "$" suffixes cannot be used with variable names. BASIC variables are declared to SQL in a declaration section. This section has the following syntax:
exec sql begin declare section
BASIC variable declarations
exec sql end declare section
Embedded SQL variable declarations are global to the program file from the point of declaration onwards. Multiple declaration sections can be incorporated into a single file, as would be the case when a few different BASIC subprograms issue embedded statements using local variables. Each subprogram can have its own declaration section. For a discussion of the declaration of variables and types that are local to BASIC subprograms, see
The Scope of Variables in this chapter.
Reserved Words in Declarations
All Embedded SQL keywords are reserved. Therefore, you cannot declare variables with the same name as ESQL keywords. You can only use them in quoted string literals. These words are:
The Embedded SQL preprocessor does not distinguish between uppercase and lowercase in keywords. In generating BASIC code, it converts any uppercase letters in keywords to lowercase.
Data Types
The Embedded SQL preprocessor accepts the following elementary BASIC data types. The table below maps these types to their corresponding Ingres type categories. For a description of exact type mapping, see
Data Type Conversion in this chapter.
Because BASIC supports the packed decimal datatype, the Ingres decimal type is mapped to it. For example, the BASIC packed decmial declarations:
declare decimal pack1
declare decimal (p,s) pack2
correspond to the Ingres decimal types:
decimal (15, 2)
decimal (p,s)
In addition, the preprocessor accepts the BASIC record type in variable declarations, providing the record has been predefined in an Embedded SQL declaration section.
The data types gfloat and hfloat are illegal and will cause declaration errors.
Neither the preprocessor nor the runtime support routines support gfloat or hfloat floating-point arithmetic. Consequently, the precision of floating-point data is less than that which is available in VMS BASIC programs. You should not compile the BASIC source code with the command line qualifiers gfloat or hfloat if you intend to pass those floating-point values to or from Ingres objects.
The following sections discuss the variable declarations and the use of variables in Embedded SQL statements.
String Data Type
The Embedded SQL preprocessor accepts both fixed-length and dynamic string declarations. Strings can be declared using any of the declarations listed later. Note that you can indicate string length only for non-dynamic strings, that is, for string declarations appearing in common, map, or record declarations. For example,
common (globals) string ename = 30
is acceptable, but
declare string bad_str_var = 30 ! length is illegal
will generate an error.
The reference to an uninitialized BASIC dynamic string variable in an embedded statement that assigns the value of that string to Ingres will result in a runtime error because that restriction does not apply to the retrieval of data into an uninitialized dynamic string variable.
Integer Data Type
Embedded SQL/BASIC accepts all BASIC integer data type sizes. It is important that the preprocessor know about
integer size because it generates code to load data in and out of program variables. The preprocessor assumes that integer size is four bytes by default. However, you can inform the preprocessor of a non-default integer size by using the
-i flag on the preprocessor command line. For detailed information on this flag, see
Advanced Processing in this chapter.
You can explicitly override the default size or the preprocessor -i command-line flag by using the BASIC subtype words byte, word, or long in the variable declaration, as these examples illustrate:
declare byte one_byte_int
common (globals) word two_byte_int
external long four_byte_int
These declarations instruct the preprocessor to create integer variables of one, two, and four bytes respectively, regardless of the default setting.
You can use an integer variable with any numeric-valued object to assign or receive numeric data. For example, you can use such a variable to set a field in a form or to select a column from a database table. It can also specify simple numeric objects, such as table field row numbers.
Real Data Type
As with the
integer data type, the preprocessor must know the size of real data variables so that these variables can interact with Ingres correctly at runtime. The preprocessor accepts two sizes of real data: 4-byte variables (the default) and 8-byte variables. Again, you can change the default size with a flag on the preprocessor command line—in this case, the
-r flag. For detailed information on this flag, see
Advanced Processing in this chapter.
You can explicitly override the default size by using the BASIC subtype words single or double in a variable declaration. For example, the following two declarations:
declare single four_byte_real
map (myarea) double eight_byte_real
create real variables of four and eight bytes, respectively, regardless of the default setting.
A real variable can be used in Embedded SQL statements to assign or receive numeric data (both real and integer) to and from database columns, form fields, and table field columns. It cannot be used to specify numeric objects, such as table field row numbers.
Decimal Data Type
The preprocessor accepts variable declarations of the decimal data type. Note that because the current implementation of Ingres does not store data in packed decimal format, Ingres converts the contents of a decimal variable to and from a double at runtime. Therefore, although decimal variables can interact with Ingres, the movement of data at runtime, both before and after database manipulation, can lead to some loss of precision.
Decimal variables can be used in Embedded SQL statements to transmit numeric values to and from database columns, form fields, and table field columns. You cannot, however, use decimal variables with Ingres integer objects, such as table field row numbers.
The default scale and precision for both decimal variables and decimal symbolic constants in EQUEL/BASIC is the BASIC default of (15,2). The preprocessor does not support the BASIC compile flag /decimal_size. Compiling with the flag will not change the default precision and scale of decimal variables as far as the preprocessor is concerned. You should always specify the precision and scale when declaring a decimal variable or constant. For example:
declare decimal (10.4) constant = 1.2345 – Preferred declaration
declare decimal constant = 1.234 – Will use default (15,2) thus
scale is truncated to two places.
Record Data Type
The Embedded SQL preprocessor supports the declaration and use of user-defined record variables. You can declare a variable of type record if you have already defined the record in an Embedded SQL declaration section. Later sections discuss the syntax of record declarations and their use in Embedded SQL statements.
Variable and Constant Declaration Syntax
Embedded SQL/BASIC variables and constants can be declared in a variety of ways when those declarations are in a declare section. The following sections enumerate these declaration statements and describe their syntax.
The Declare Statement
The declare statement for an Embedded SQL/BASIC variable has the following syntax:
declare type identifier [(dimensions)] {, [type] identifier [(dimensions)]}
The declare statement for an Embedded SQL/BASIC constant has the syntax:
declare type constant identifier = literal {, identifier = literal}
Syntax Notes:
• If you specify the word constant, the declared constants cannot be targets of Ingres assignments.
• The type must be a BASIC type acceptable to the preprocessor (see previous section) or, in the case of variables only, a record type already defined in the Embedded SQL declaration section. Note that the type is mandatory for Embedded SQL/BASIC declarations, because the preprocessor has no notion of a default type. You need only specify the type once when declaring a list of variables of the same type.
• The dimensions of an array specification are not parsed by the preprocessor. Consequently, the preprocessor does not check bounds. Note also that the preprocessor will accept an illegal dimension, such as a non-numeric value, but this will later cause BASIC compiler errors.
The following example illustrates the use of the declare statement:
exec sql begin declare section
declare integer enum, eage, string ename
declare single constant minsal = 12496.62
declare real esal(100)
declare word null_ind ! Null indicator
exec sql end declare section
The Dimension Statement
The dimension statement can be used to declare arrays to the preprocessor. Its syntax is:
dimension | dim type identifier(dimensions) {, [type] identifier (dimensions)}
Syntax Notes:
• The type must be a BASIC type acceptable to the preprocessor (see previous section) or a record already defined in the Embedded SQL declaration section. Note that the type is mandatory for Embedded SQL/BASIC declarations because the preprocessor has no notion of a default type. You need only specify the type once when declaring a list of variables of the same type.
• The dimensions of an array specification are not parsed by the preprocessor. Consequently, the preprocessor does not check bounds. Note also that the preprocessor will accept an illegal dimension, such as a non-numeric value, but it will later cause BASIC compiler errors. Furthermore, the preprocessor does not distinguish between executable and declarative dimension statements. If you have used the dimension statement to declare an executable array to Embedded SQL/BASIC, subsequent executable dimension statements of the same array in a declaration section will cause a redeclaration error.
The following example illustrates the use of the dimension statement:
exec sql begin declare section
dim string employee_names(100,20)
! declarative DIM statement
dimension long emp_id(100,2,2)
dimension double expenses(numdepts)
! executable DIM statement
exec sql end declare section
Static Storage Variable Declarations
Embedded ESQL/BASIC supports the BASIC common and map variable declarations. The syntax for a common variable declaration is as follows:
common | com [(com_name)]
type identifier [(dimensions)] [= str_length]
{, [type] identifier [(dimensions)] [= str_length]}
The syntax for a map variable declaration is as follows:
map | map dynamic (map_name)
type identifier [(dimensions)] [= str_length]
{, [type] identifier [(dimensions)] [= str_length]}
Syntax Notes:
• The type must be a BASIC type acceptable to the preprocessor (see previous section) or a record type already defined to Embedded SQL/BASIC. Note that the type is mandatory for Embedded SQL/BASIC declarations because the preprocessor has no notion of a default type. You need only specify the type once when declaring a list of variables of the same type.
• The dimensions of an array specification are not parsed by the preprocessor. Consequently, the preprocessor does not check bounds. Note also that the preprocessor will accept an illegal dimension, such as a non-numeric value, but it will later cause BASIC compiler errors.
• The string length, if present, must be a simple integer literal.
• The com_name or map_name clause is not parsed by the preprocessor. Consequently, the preprocessor will accept common and map areas of the same name in a single declaration section. It will also accept a map dynamic statement whose com_name has not appeared in another map statement. Either of these situations will later cause BASIC compiler errors.
The following example uses the common and map variable declarations:
exec sql begin declare section
common (globals) string address = 30, integer zip
map (ebuf) byte eage, string
ename = 20, single emp_num
common (globals) integer empid (200)
exec sql end declare section
The External Statement
You can inform Embedded SQL/BASIC of variables and constants declared in an external module. The syntax for a variable is as follows:
external type identifier {, identifier}
The syntax for a constant is as follows:
external type constant identifier {, identifier}
Embedded SQL/BASIC applies the same restrictions on type as VAX-11 BASIC.
exec sql begin declare section
external integer empform, infoform
external single constant emp_minsal
exec sql end declare section
Record Type Definitions
Embedded SQL/BASIC accepts BASIC record definitions. The syntax of a record definition is:
record identifier
record_component
{record_component}
end record [identifier]
where record_component can be any of the following:
type identifier [(dimensions)] [= str_length]
{, [type] identifier [(dimensions)] [= str_length]}
group_clause
variant_clause
In turn, the syntax of a group_clause is:
group identifier [(dimensions)]
record_component
{record_component}
end group [identifier]
The syntax of a variant_clause is:
variant
case_clause
{case_clause}
end variant
where case_clause consists of:
case
record_component
Syntax Notes:
• The type must be a BASIC type acceptable to the preprocessor (see previous section) or a record type already defined in the declaration section. Note that the type is mandatory for Embedded SQL/BASIC declarations because the preprocessor has no notion of a default type. You need only specify the type once when declaring a list of variables of the same type.
• Use the str_length clause only with record components of type string.
• Record definitions must appear before declarations using that record type.
The following example contains record type definitions:
exec sql begin declare section
record emp_history
string ename = 30
group prev_employers(10)
string comp_name = 30
real salary
integer num_years
end group prev_employers
end record emp_history
record emp_sports
string ename = 30
variant
case
group golf
integer handicap
string club_name
end group golf
case
group baseball
integer batting_avg
string team_name
end group baseball
case
group tennis
integer seed
string club_name
end group tennis
end variant
end record emp_sports
exec sql end declare section
Indicator Variables
An indicator variable is a 2-byte integer variable. There are three possible ways to use them 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 value.
• In a statement that sets data to Ingres, you can use an indicator variable to assign a null to the database column.
• In a statement that retrieves character data from Ingres, you can use the indicator variable as a check that the associated host variable was large enough to hold the full length of the returned character string. You can use SQLSTATE to do this. Although you can use SQLCODE as well, it is preferable to use SQLSTATE because SQLCODE is a deprecated feature.
You can declare an indicator using the integer word subtype or, if you used the -i2 preprocessor command line flag, you can declare an indicator as an integer. The following example declares two indicator variables, one a single variable and the other an array of indicators:
declare word ind, ind_arr(10)
When using an indicator variable with a BASIC record, you must declare the indicator variable as an array of 2-byte integers. In the above example, you can use the variable "ind_arr" as an indicator array with a record assignment.
DCLGEN Utility
DCLGEN (Declaration Generator) is a record-generating utility that maps the columns of a database table into a record that can be included in a declaration section.
Use the following command to invoke DCLGEN from the operating system level:
dclgen language dbname tablename filename recordname [-n] [-q]
where
language
Defines the Embedded SQL host language, in this case, ada.
dbname
Defines the name of the database containing the table.
tablename
Defines the name of the database table.
filename
Defines the output file into which the record declaration is placed.
recordname
Defines the name of the BASIC record variable that the command generates. The command generates a record definition named recordname followed by an underscore character (_) and a declaration for a record variable of recordname.
-n
Does not print the DECLARE TABLE statement.
-q
Creates output in QUEL format.
This command creates the declaration file filename, containing a record corresponding to the database table. The file also includes a record statement for the record variable, as well as a declare table statement that serves as a comment and identifies the database table and columns from which the record was generated.
Once the file has been generated, you can use an Embedded SQL include statement to incorporate it into the variable declaration section. The following example demonstrates how to use DCLGEN in a BASIC program.
Assume the Employee table was created in the Personnel database as:
exec sql create table employee
(eno smallint not null,
ename char(20) not null,
age integer1,
job smallint,
sal decimal not null,
dept smallint)
and the DCLGEN system-level command is:
dclgen basic personnel employee employee.dcl emprec
The employee.dcl file created by this command contains a comment and three statements. The first statement is the declare table description of "employee" which serves as a comment. The second statement is a definition of the BASIC record "emprec_". The last statement is a declare statement for the record "emprec". The contents of the employee.dcl file are:
! Description of table employee from database personnel
exec sql declare employee table
(eno smallint not null, &
ename char(20) not null, &
age integer1, &
job smallint, &
sal decimal not null, &
dept smallint)
record emprec_
word eno
string ename = 20
byte age
word job
double sal
word dept
end record
declare emprec_ emprec
This file should be included, by means of the Embedded SQL include statement, in an Embedded SQL declaration section:
exec sql begin declare section
exec sql include 'employee.dcl'
exec sql end declare section
You can then use the emprec record in a select, fetch, or insert statement.
DCLGEN and Large Objects
You can use DCLGEN to generate an appropriate declare table statement with BASIC variables for tables that contain long varchar columns. For columns that have a limited length, the variables generated will be identical to the variables generated for the Ingres varchar datatype. For columns with unlimited length, such as:
create table long_obj_table(blob_col long varchar);
DCLGEN will issue an error message and generate a character string variable with zero length. You can modify the length of the generated variable before attempting to use the variable in an application.
For example the following table definition:
create tablelongobj_table
(long_column long varchar));
results in the following DCLGEN generated output for BASIC compilers that support structures:
exec sql declare long_obj_table table &
(long_column long varchar)
record blobs_rec_
string long column = 0
end record blobs_rec_
declare blobs_rec_ blobs_rec
How to Declare External Compiled Forms
You can precompile your forms in the Visual Forms Editor (VIFRED). This saves the time that would be 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 you have 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 Embedded SQL/FORMS statement addform can refer to this global object, the object must be declared in an Embedded SQL declaration section with the following syntax:
external integer formname
Syntax Notes:
• The formname is the actual name of the form. VIFRED gives this name to the address of the global object. The formname is also used as the title of the form in other Embedded SQL/FORMS statements.
• The external statement associates the object with the external form definition.
The example below shows a typical form declaration and illustrates the difference between using the form's object definition and the form's name.
exec sql begin declare section
external integer empform
...
exec sql end declare section
...
exec frs addform :empform ! The global object
exec frs display empform ! The name of the form
...
Embedded SQL/BASIC Declarations Example
The following example demonstrates some simple Embedded SQL/BASIC declarations:
exec sql include sqlca
exec sql begin declare section
declare byte d_byte ! variables of each data type
declare word d_integer2
declare long d_integer4
declare integer d_integer_def
declare single d_real4
declare double d_real8
declare real d_real_def
declare decimal(6,2) d_decimal
declare string d_string
declare integer constant num_depts = 10 ! constant
common(globs) real e_raise ! static storage variables
map (ebuf) string ename = 20
dim string emp_names(100,30) ! array declarations
declare integer dept_id(10)
common(globs) string e_address(40) = 30
record person ! Variant record
byte age
long flags
variant
case
group emp_list
string full_name = 30
end group
case
group emp_directory
string firstname = 12
string lastname = 8
end group
end variant
end record
declare person p_table(100) ! Array of records
exec sql include 'employee.dcl' ! From DCLGEN
external integer empform, deptform ! Compiled forms
dim word indicators(10) ! Array of null indicators
exec sql end declare section