Back to Contents
Summary:
See also: Records, Arrays,
Data Types, Constants.
A variable is a program element that can hold volatile data. The
following list summarizes variables usage:
- You must DEFINE variables before usage.
- After definition, variables have default values
according to the data type.
- The scope of a variable can be global, local to
a module, or local to a function.
- You can define structured variables with records
and arrays.
- Variables can be initialized with the INITIALIZE
instruction.
- Variables can be assigned with the LET instruction.
- Variables can be validated with the VALIDATE
instruction.
- Variables can be used as parameters or fetch buffers in Static
or Dynamic SQL statements.
- Variables can be used as input or display buffers in interactive
instructions such as INPUT, INPUT
ARRAY, DISPLAY ARRAY, CONSTRUCT.
Purpose:
A variable contains volatile information of a specific data
type.
Syntax:
DEFINE identifier [,...] { type | LIKE
[dbname:]tabname.colname }
Notes:
- identifier is the name of the variable to be defined.
- type can be any data type
supported by the language, a record definition, an
array definition, or a built-in class.
- When using the LIKE clause, the data type is taken from the schema
file. Columns defined as SERIAL are converted to INTEGER.
- dbname identifies a specific database
schema
file.
- tabname.colname can be any column reference defined in the database
schema file.
- Variables can be global to the program, local to a
module, or local to a function.
Tips:
- To write well-structured programs, it is recommended
that you not use global
variables. If you need persistent data storage during a program's execution, use
variables local to the module and give access to them with functions.
Warnings:
- When defining variables with the LIKE clause, the data types are taken from the schema
file during compilation. Make sure that the schema file of the
development database corresponds to the production
database;
otherwise
the variables defined in the compiled version of your modules will not match
the table structures of the production database.
Usage
A variable is a named location in memory that can store a single
value, or an ordered set of values. You cannot reference any program variable
before it has been declared by the DEFINE statement.
The DEFINE statement declares the identifier of one or more variables.
There are two important things to know about these identifiers:
- Where in the program can they be used? The answer defines the scope of
reference of the variable. A point in the program where an identifier can be
used is said to be in the scope of the identifier. A point where the
identifier is not known is outside the scope of the identifier.
- When is storage for the variable allocated? Storage can be allocated
either statically, when the program is loaded to run (at load time), or
dynamically, while the program is executing (at runtime).
The context of its declaration in the source module determines where a
variable can be referenced by other language statements, and when storage is
allocated for the variable in memory. The DEFINE statement can appear in three
contexts:
- Within a FUNCTION, MAIN, or REPORT program block,
DEFINE declares local variables, and causes memory to be allocated
for them. These DEFINE declarations of local variables must precede any executable
statements within the same program block.
- The scope of reference of a local variable is restricted to the same
program block. The variable is not visible elsewhere.
- Storage for local variables is allocated when its FUNCTION,
REPORT, or MAIN block is entered during execution.
Functions can be called recursively, and each recursive entry creates its
own set of local variables. The variable is unique to that invocation of
its program block. Each time the block is entered, a new copy of the variable
is created.
- Outside any FUNCTION, REPORT, or MAIN program
block, the DEFINE statement declares names and data types of module
variables, and causes storage to be allocated for them. These declarations must
appear before any program blocks.
- Scope of reference is from the DEFINE statement to the end of
the same module. The variable, however, is not visible within this scope in
program blocks where a local variable has the same identifier.
- Memory for variables of modules is allocated statically, when
the program starts.
- Inside a GLOBALS block, the DEFINE statement declares global variables.
- Scope of reference is global to the whole program.
- The memory for global variables is allocated statically, when the
program starts.
- Multiple GLOBALS blocks can be defined for a given module. Use
one module to declare all global variables and reference that module
within other modules by using the GLOBALS "filename.4gl"
statement as the first statement in the module, outside any program block.
A compile-time error occurs if you declare the same name for two variables
that have the same scope. You can, however, declare the same name for variables
that differ in their scope. For example, you can use the same identifier to
reference different local variables in different program blocks.
You can also declare the same name for two or more variables whose scopes of
reference are different but overlapping. Within their intersection, the compiler
interprets the identifier as referencing the variable whose scope is smaller,
and therefore the variable whose scope is a superset of the other is not
visible.
If a local variable has the same identifier as a global variable, then the
local variable takes precedence inside the program block in which it is
declared. Elsewhere in the program, the identifier references the global
variable.
A module variable can have the same name as a global variable that is
declared in a different module. Within the module where the module variable is declared,
the module variable takes precedence over the global variable. Statements in that
module cannot reference the global variable.
A module variable cannot have the same name as a global variable that is
declared in the same module.
If a local variable has the same identifier as a module variable, then the
local identifier takes precedence inside the program block in which it is
declared. Elsewhere in the same source-code module, the name references the
module variable.
You can use the RECORD or ARRAY keywords to declare a
structured variable.
For example:
01
MAIN
02
DEFINE myarr ARRAY[100] OF RECORD
03
id INTEGER,
04
name VARCHAR(100)
05
END RECORD
06
LET myarr[2].id = 52
07
END MAIN
For more detail, refer to Arrays and Records.
You can use the LIKE keyword to declare a variable that has the same
data type as a specified column in a database
schema, for example:
01
DATABASE stores
02
DEFINE cname LIKE customer.cust_name
03
MAIN
05
DEFINE cr RECORD LIKE customer.*
06
END MAIN
The following rules apply when using the LIKE keyword:
- A SCHEMA statement must define the database name identifying
the database schema files to be used.
- The column data types are read from the schema file during compilation,
not at runtime. Make sure that your schema files correspond exactly to the
production database.
- The database schema files must exist and
must be available as specified in the
FGLDBPATH variable.
- The column data type defined by the database schema must be supported by
the language. For more detail about supported types, refer to Data Types.
- When using database views, the column cannot be based on an
aggregate function like SUM().
- If LIKE references a SERIAL column, the new variable is of the
INTEGER
data type.
- The table qualifier
must specify owner if table.column is not a unique column
identifier within its database, or if the database is ANSI-compliant and any
user of your application is not the owner of table.
To
understand how to generate database schema files, refer to Database Schema
Files.
After a variable is defined, it is automatically
initialized by the runtime system to a default value based
on the data type. The following table shows all
possible default values that variables can take:
Data Type |
Default Value |
CHAR |
NULL |
VARCHAR |
NULL |
STRING |
NULL |
INTEGER |
Zero |
SMALLINT |
Zero |
FLOAT |
Zero |
SMALLFLOAT |
Zero |
DECIMAL |
NULL |
MONEY |
NULL |
DATE |
1899-12-31 (=Zero in number of days) |
DATETIME |
NULL |
INTERVAL |
NULL |
TEXT |
NULL, See LOCATE |
BYTE |
NULL, See LOCATE |
Purpose:
The INITIALIZE instruction assigns initial NULL
or default values to variables.
Syntax:
INITIALIZE target [,...] { TO NULL | LIKE {table.*|table.column} }
Notes:
- target is the name of the variable to be initialized.
- target can be a simple variable, a record
or an array element.
- If target is a record, you can use the star to
reference all record members in the initialization.
- The TO NULL clause initializes the variable to NULL.
- The LIKE clause initializes the variable to the default value
defined in the database schema attributes
file.
- table.column can be any column reference defined in the database
schema file.
Tips:
- To initialize a complete record, use
the star to reference all members:
INITIALIZE record.* LIKE table.*
Warnings:
- The LIKE clause requires the IBM Informix upscol utility
to populate the syscolatt table. See the database
schema files for more details. Informix only!
- You cannot initialize variables defined with a complex data type (like TEXT
or BYTE) to a non-NULL value.
Example:
01
DATABASE stores
02
MAIN
03
DEFINE cr RECORD LIKE customer.*
04
INITIALIZE cr.cust_name TO NULL
05
INITIALIZE cr.* LIKE customer.*
06
END MAIN
Purpose:
The VALIDATE statement tests whether the value of a variable is within the
range of values for a corresponding column in database schema files.
Syntax:
VALIDATE target [,...] LIKE {table.*|table.column}
Notes:
- target is the name of the variable to be validated.
- target can be a simple variable, a record,
or an array element.
- If target is a record, you can use the star to
reference all record members in the validation.
- Values are compared to the value defined in the database
schema validation file.
- table.column can be any column reference defined in the database
schema file.
Errors:
- If the value does not match any value defined in the INCLUDE attribute of
the corresponding column, the runtime system raises an exception
with error code -1321.
Warnings:
- The LIKE clause requires the IBM Informix upscol utility
to populate the syscolval table. See the database
schema files for more details. Informix only!
- You cannot initialize variables defined with a complex data type (like TEXT
or BYTE) to a non-NULL value.
Example:
01
DATABASE stores
02
MAIN
03
DEFINE cname LIKE customer.cust_name
04
LET cname = "aaa"
05
VALIDATE cname LIKE customer.cust_name
06
END MAIN
Purpose:
The LET statement assigns a value to a variable, or a set of values
to a record.
Syntax:
LET target = expression
Notes:
- target is the name of the variable to be assigned.
- target can be a simple variable, a record,
or an array element.
- expression is any valid expression
supported by the language
- The runtime system applies data type
conversion rules if the data type of expression does not
correspond to the data type of target.
- If target is a record, you can use the star to
reference all record members in the validation, and expressions can also use
this notation (record.*).
Warnings:
- Variables defined with a complex data type (like TEXT
or BYTE) can only be assigned to NULL.
- For more detail, refer to the assignment operator.
Example:
01
DATABASE stores
02
MAIN
03
DEFINE c1, c2 RECORD LIKE customer.*
04
LET c1.* = c2.*
05
END MAIN
Purpose:
The LOCATE statement specifies where to store data of TEXT
and BYTE variables.
Syntax:
LOCATE target [,...] IN { MEMORY | FILE filename
}
Notes:
- Defining the location of large object data is mandatory before usage.
- target is the name of a TEXT
or BYTE variable to be located.
- target can be a simple variable, a record
member, or an array element.
- filename is a string
expression defining the name of a file.
- The IN MEMORY clause specifies that the large object data must be
located in memory.
- The IN FILE clause specifies that the large object data must be
located in a file.
- After defining the data storage, the variable can be used as a parameter or
as a fetch buffer in SQL statements.
- You can free the resources allocated to the large object variable with the
FREE instruction.
Warnings:
- You cannot use a large object variable if the data storage location is not
defined.
Example:
01
MAIN
02
DEFINE ctext1, ctext2 TEXT
03
DATABASE stock
04
LOCATE ctext1 IN MEMORY
05
LOCATE ctext2 IN FILE "/tmp/data1.txt"
06
CREATE TABLE lobtab ( key INTEGER, col1 TEXT, col2 TEXT )
06
INSERT INTO lobtab VALUES ( 123, ctext1, ctext2 )
07
END MAIN
Purpose:
The FREE statement releases resources allocated to store the data of TEXT
and BYTE variables.
Syntax:
FREE target
Notes:
- target is the name of a TEXT
or BYTE variable to be freed.
- target can be a simple variable, a record
member, or an array element.
- If the variable was located in memory, the runtime system releases the
memory.
- If the variable was located in a file, the runtime system deletes the
named file.
- For variables declared in a local scope of reference, the resources are
automatically freed by the runtime system when returning from the function
or MAIN block.
Warnings:
- After freeing a large object, you must LOCATE the
variable again before usage.
Example:
01
MAIN
02
DEFINE ctext TEXT
03
DATABASE stock
03
LOCATE ctext IN FILE "/tmp/data1.txt"
04
SELECT col1 INTO ctext FROM lobtab WHERE key=123
05
FREE ctext
06
END MAIN
Example 1: Function variables
01
FUNCTION myfunc( )
02
DEFINE i INTEGER
03
FOR i=1 TO 10
04
DISPLAY i
05
END FOR
06
END FUNCTION
Example 2: Module variables
01
DEFINE s VARCHAR(100)
02
03
FUNCTION myfunc( )
04
DEFINE i INTEGER
05
FOR i=1 TO 10
06
LET s = "item #" || i
07
END FOR
08
END FUNCTION
Example 3: Global variables
File "myglobs.4gl":
01
GLOBALS
02
DEFINE userid CHAR(20)
03
DEFINE extime DATETIME YEAR TO SECOND
04
END GLOBALS
File "mylib.4gl":
01
GLOBALS "myglobs.4gl"
02
03
DEFINE s VARCHAR(100)
04
05
FUNCTION myfunc( )
06
DEFINE i INTEGER
07
DISPLAY "User Id = " || userid
08
FOR i=1 TO10
09
LET s = "item #" || i
10
END FOR
11
END FUNCTION
File "mymain.4gl":
01
GLOBALS "myglobs.4gl"
02
03
MAIN
04
LET userid = fgl_getenv("LOGNAME")
05
LET extime = CURRENT YEAR TO SECOND
06
CALL myfunc()
07
END MAIN