INFORMIX 4GL STATEMENTS
This chapter deals in detail with the components of the
INFORMIX-4GL language and their use, paying particular attention to
the specialized programming statements that INFORMIX-4GL provides
for dealing with the database and the screen display of
database-bound information.
From this point, you deal with a sample application for a
fictitious company that specializes in recruiting long-haul truck
drivers. This chapter uses two tables from this company's database,
named recruiters, to illustrate the basic principles of
INFORMIX-4GL program development. These tables are employers and
states.
The database schema can be extracted from the database by using
the utilitydbschema, which is provided with all Informix products.
This is only one of a group of utilities provided by Informix for
the purpose of migrating data between databases or engines. This
utility creates an ASCII file that can be used to re-create the
table with the same structure it had originally. Thedbschemacommand
is used as follows:
dbschema {[-t ]
[-s ]
[-p ]
-d
[-ss]
[]}
The options in this command are defined as follows:
-t is the name of the table to extract or the wordto generate
the schema for all tables in the database.
-s generatescreate synonymstatements fororfor all users.
-p generatesgrantstatements to grant permissions toorfor all
users.
-d indicates the name of the database used to extract the schema
files.
-ssgenerates server-specific syntax.
is the name of the ASCII file that receives the SQL statements
generated. (It is a good practice to name this file.SQLso that you
can deal with it as you do any other SQL script.)
NOTE:To distinguish options and arguments that are required in a
command line or in a statement from those that are optional, I have
enclosed the optional arguments in square brackets ([]), whereas
the required arguments are not enclosed in brackets. I have used
curly brackets ({}) to denote a grouping of items, and pointed
brackets () to illustrate that the contents are to be filled in as
appropriate.
The database schema for these tables is displayed in Listing
36.1.
Listing 36.1. Schema of employers and states tables.
{ TABLE "jose".employers row size = 179 number of columns = 16
index size = 78 }
create table "jose".employers
(
empl_code serial not null constraint "jose".n103_18,
employer char(35) not null constraint "jose".n103_19,
add_line1 char(35),
add_line2 char(35),
city char(18),
state char(2),
zip char(5),
phone char(10),
trl_len char(2),
freight char(10),
area char(15),
nbr_trks char(4),
authority char(1),
leased char(1),
dac char(1),
authorized char(1),
primary key (empl_code) constraint "jose".pk_employers
);
revoke all on "jose".employers from "public";
create index "jose".ix100_2 on "jose".employers (employer);
create index "jose".ix100_16 on "jose".employers
(authorized);
{ TABLE "jose".states row size = 17 number of columns = 2 index
size = 9 }
create table "jose".states
(
state char(2) not null constraint "jose".n101_4,
state_name char(15) not null constraint "jose".n101_5,
primary key (state) constraint "jose".pk_states
);
revoke all on "jose".states from "public";
The schema for these tables shows all permissions revoked
from"public". The database administrator must grant connect
permissions to the database and table permissions to the
appropriate users before these tables are accessible to users.
What Should an INFORMIX-4GL Program Do?
Generally, an INFORMIX-4GL program should have a discrete,
focused purpose and encompass only the tasks that are directly
related either to the tables being processed or to the functional
business process that the software serves. Try to apply to
INFORMIX-4GL programs the same principles of normalization that you
apply to relational databases. In the same way you don't create a
single table to represent all aspects of your enterprise, you
design the scope of your programs to facilitate the execution of a
single business process. The larger the scope of your program, the
larger the executables the compiler generates. Larger executables
are slower to load into memory and usually more cumbersome for the
user to navigate. An application in this scenario becomes a
collection of limited, focused purpose programs, glued together by
some form of menu system.
NOTE:It was once common practice to develop an application by
first developing an INFORMIX-4GL program that provided only a
cascading menu system. When the user selected a specific task from
any of the submenus of this program, the program executed a call to
run the selected task in a subshell, while the menu program went
dormant waiting for its child to be completed. Current Informix
database engines count both programs as separate users because both
hold connections to the database engine. Keep this user count in
mind when determining your user licenses, or perhaps use a
different menu management strategy for your application.
In this chapter, you develop software to query and input data
into the employers table. The fictitious company that recruits
long-haul drivers needs software to support multiple business
endeavors: managing potential employers, receiving applications
from prospective drivers, and verifying employment histories of
prospective drivers. Your application should strive to mimic the
nature of your business and support each business function with
separate programs. One program collects the functionality to
support all tasks related to managing potential employers, and
another program collects all functionality to receive applications
from prospective drivers. This is not to say that the programs are
completely isolated islands; the program that manages potential
employers is likely to offer a peek at the prospective drivers that
an employer hired but is unlikely to provide facilities for
receiving new driver applications.
Basic Program Design
If you embrace the concepts that each program in your
application should have a narrow, defined focus and that programs
should be structured and modular so component reuse is facilitated,
then it becomes important to organize the various programs, forms,
and components of your application in such a way that sharing those
components is simple. In this section, I suggest a directory
structure that provides an adequate infrastructure in support of
these principles.
Directory Structure
A possible organization of the UNIX directory structure to
support these criteria for developing applications is as follows
(with the indentation indicating hierarchy):
Application Directory
Module Directory Module Directory System Library
Program Directory Program Directory Module Library Module
Screens
Module File #1 Module File #2 Module File #n
At the root of the tree is the application directory. This
directory collects all the organized components that make up the
application. Directly under the application directory, you find the
module directories. A module directory contains a logical grouping
of program directories and libraries, which contain programs that
cooperate to perform various tasks of a business function. In the
fictional company, the application directory could be named
corporate accounting. The module directories could be accounts
receivable, operations, general ledger, recruiting, and so on. The
system library, located at this level in the hierarchy, contains
components: source code module files and objects and form source
files and objects that are used by all modules. For instance, the
company-wide logo that is displayed whenever a specific program is
loaded is an example of a component located here. Within the
recruiting module, you might find a program directory named
employers (the example developed in this chapter) that collects all
the functionality that is needed to manage prospective employers.
You might also have another program directory named drivers that
collects all the information about the truck drivers and provides
the required functionality to manage them: taking applications,
verifying employment records, verifying driving records, and so
on.
In a directory structure like this, executable files
(*.4gior*.4ge) reside in the program directories. Source and
compiled screen forms (*.perand*.frm) reside also in program
directories but may be found in module screens directories and
perhaps even in the system library. Source code modules (*.4gl) and
object modules (*.4goor*.o) are located in the program directories,
module libraries, and the system library. Each program directory
also contains the error log file for the program it defines.
Defining a program in any of the program directories requires that
you identify the local globals file and local source code modules
and you include other objects that are located in../or
in../../.
Executing a program in any program directory requires that
yourDBPATHvariable point to the directory where the executables are
(usually the current directory), as well as to directories that
contain forms that are called by the program. The definition
ofDBPATH, in this directory structure,
becomesDBPATH=$DBPATH:.:../:../../.
Libraries
In this context, libraries are defined as repositories of
functions or reports that perform a specific task. These functions
receive a collection of arguments and return a collection of values
without interacting with the calling program in any way other than
through arguments and returned values.
Libraries tend to be organized along the same criteria used to
organize module directories. There are multiple library
directories, both at the module and system levels, that collect
similar types of objects. A library of error management routines
collects all error detection, error display, and reporting
mechanisms, as well as adequate responses depending on the severity
of the runtime errors encountered. There may also be a library of
common database delivery functions that collects source code
modules that are defined to receive a key for a table and return
some descriptive value from that table. (For example, upon
receiving an employee code, it returns a string that concatenates
the first name, middle initial, and last name of an employee with
appropriate spacing.) There may also be a library of conversion
functions that perform numeric-to-string conversions and vice versa
while rounding or truncating the numeric values to the desired
number of decimal places. There may also be a library of
string-manipulation functions that collect functions that find
substrings within a string or center or right justify a string.
Common Forms and Modules
In the context of a programming language that is designed to
deal with database information, common forms and modules are
defined as repositories of functions that perform a task that
requires user and database interaction through query or input
within a form or prompt. These functions respond to the user's
action by returning a collection of values to the calling program.
Common forms and modules tend to be organized within libraries
along the same criteria used to organize module directories.
Many business applications require that you provide users with
pop-up, zoom, or drill-down facilities to fill in values during
data entry that have to exist in a parameter table. For instance,
in the fictitious company, while entering the code for a state in
an employer address, you want to make sure that the spelling of the
state is correct and force the value entered to be validated
against a table of valid state codes. If the user does not remember
the state code or if he fails to provide a correct state code, you
want to provide a pop-up window that allows the user to view the
valid state codes and select the appropriate value, which is then
returned to the calling program. The screen forms and source code
modules for this type of zooming operation is used throughout an
application and become prime candidates for a common library.
Accounting applications usually require the user to provide an
account, or a pair of accounts, for recording or posting a business
transaction. A pop-up window for providing the suggested defaults
and allowing the user to alter the defaults is also a typical
example of a screen form and its processing source code that are
candidates for placement in a common access library.
Skeleton of an INFORMIX-4GL Program
The basic skeleton for an INFORMIX-4GLprogram consists of the
following program blocks (placed in a single source code module
file or in multiple source code module files):
[database ] --Required if the program interacts with a
database
[globals] --Only one globals definition per program
end globals ]
[globals ""]
--Many global declarations per program
main --One, and only one, is required in a program
end main
[function () --A program may have many functions
[return ]
end function]
[report () --A program may have many reports
end report]
Each of these program blocks is defined in more detail in the
following sections, except for reports, which are covered in
Chapter 37, "4GL Development."
Database
Thedatabasestatement has the following syntax:
[database [exclusive]]
The options in this command are defined as follows:
is a database name on your database server.
[exclusive]opens the connection to the database in exclusive
mode if there are no open connections and prevents any other user
from connecting to the database.
Thedatabasestatement performs two functions. While developing
the program, it provides the compiler with a database to use when
you define variables by reference to database tables and columns.
On execution, it opens a connection to a specific databaseand
closes the connection to the database that was open prior to its
execution.
The database nameused in this statement is a reference to a
database in the database server (dbservername) that is referenced
by your environment (INFORMIXSERVERsetting). You may specify a
different server and establish a connection to a remote database by
using the following notation@or`///'for the OnLine engine
or`////'or`//@'for the SE engine.
Examples of thedatabasestatement are
database recruiters
database recruiters@on_fort_tcp
Globals
Theglobalsprogram block has two forms. The first version
declares and defines the program variables that have global scope
throughout the program. The second version identifies a file that
contains global definitions to be used in the source code module
that includes the statement.
The syntax for the first version of the statement is
[globals
end globals ]
It is useful to isolate theglobalsdefinitions in a source code
module file that can then be referenced by the second version of
the statement. It is convenient to include thedatabasestatement in
the globals source code module so that it is inherited by the
source code modules that use the second version of
theglobalsstatement.
The syntax for the second version of the statement is
[globals ""]
An example of theglobals.4glfile used for the fictitious company
is provided in Listing 36.2.
Listing 36.2. globals.4gl for the fictitious company.
database recruiters
##################################################################
globals
##################################################################
define p_employers record like employers.*,
is_valid smallint
end globals
The keywordsglobalsandend globalsencapsulate theglobalsprogram
block. Within aglobalsprogram block, you include global variable
definitions. Variable scope is discussed further in the section
"Variables Definition, Initialization, and Scope," later in this
chapter.
Main
Themainprogram block is required in a program. A program must
have only onemainprogram block. This is the starting point in the
execution of an INFORMIX-4GL program:
main
end main
The keywordsmainandend mainencapsulate themainprogram block.
Within themainprogram block, you can include local variable
definitions, function calls, and any other valid 4GL statement.
Themainprogram block is usually kept very small and often limited
to managing the flow of control for the application.
An example of amainprogram block is
main
call InitEnv()
call FlowOfControl()
end main
This sample program first calls a function calledInitEnvand then
calls the functionFlowOfControl. The program then terminates when
it reachesend mainunless it was terminated programmatically before
reaching theend mainstatement.
Function
A function can be called within themainprogram block or within
anotherfunctionorreportprogram block. The syntax for the call to a
function, if the function returns more than one value, must be as
follows:
call () [returning ]
The options are as follows:
identifies the function called.
is a list of values or variables passed to the function as
arguments.
is a list of program variables that are loaded with the values
returned by the function to the calling program.
If a function returns a single value, thecallstatement can be
used to invoke it, but the function can also be invoked within
another command-line argument without using the keywordcall.
For example, the functionMakeNameis defined to receive three
arguments--first name, middle initial, and last name--and return a
concatenated string with the structure, . The function could be
invoked as follows:
call MakeName(p_employee.fname, p_employee.mi,
p_employee.lname)
returning p_full_name
Because it returns a single value, theMakeNamefunction could be
invoked as part of a statement involving other components, as
follows:
let p_print_name = "Employee: ", MakeName(p_employee.fname,
p_employee.mi,
p_employee.lname) clipped, " (", p_employee.emp_no, ")"
This statement concatenates the string"Employee: ", the string
returned by theMakeNamefunction, removing trailing blanks
(clipped),and it follows this with the string" (", followed by the
employee code, followed by the string")".
A function definition has the following syntax:
[function ()
[return ]
end function]
The options in this definition are covered in detail later in
this chapter. As an example, I define the functionMakeName:
function MakeName (fn, mi, ln)
define fn, mi, ln char(80),
full_name char(256)
let full_name = ln clipped, ", ", fn clipped, " ", mi
return full_name
end function
The order of the arguments in the calling clause and in the
function definition is important because the first argument in the
calling statement is passed to the first parameter in the function.
This function returns a single value and therefore can be called in
the two forms described. Functions that return multiple values can
be invoked only by means of thecallstatement.
TIP:The function program block is reentrant, thereby allowing
recursive programming; a function can call itself. INFORMIX-4GL
manages the stack on your behalf.
Report
Thereportprogram block defines the format of a report. A report
must be started (initialized) before it receives output and must be
finished after all output is sent to the report. To manage a
report, you must use the following logical sequence of
statements:
start report [to {[]
[printer]
[pipe ]}
The options in this command are defined as follows:
is the specific report to initialize.
tois the destination of the report and supersedes the
destination defined in the report program block.
sends the output of the report to a file.
printersends the output of the report to the default printer or
the printer specified by yourLPDESTsettings.
pipe sends the output of the report to be processed by the
program.
To continue with the example for functionMakeName, you can
initialize a report that prints the name stored in
variablep_print_nameand sends its output to the commandpg:
start report PrintName to pipe "pg"
After the report is initialized with the statementstart report,
the program sends records to the report formatter within some form
of a loop using theoutput tostatement as follows:
output to report ()
The options in this command are defined as follows:
is the specific report to send the record to.
is the list of variables or constants to be sent to the report
formatter.
Within a loop, you invoke theoutput to reportstatement as
follows:
let p_print_name = "Employee: ", MakeName(p_employee.fname,
p_employee.mi,
p_employee.lname) clipped, " (", p_employee.emp_no, ")"
output to report PrintName (p_print_name)
The order of the arguments in theoutput to reportand in
thereportdefinition is important because the first parameter in
theoutput to reportstatement is passed to the first parameter in
the report.
Finally, after all records are sent to the report, the report
must be terminated with thefinish reportstatement as follows:
finish report
The options in this command are defined as follows:
is the specific report to finish.
After looping through all the employee records in the fictitious
company that you want to print, you issue afinish reportstatement
as follows:
finish report PrintName
A report definition has the following syntax:
[report ()
end report]
The options in this definition are covered in detail in Chapter
37. As an example, I define the reportPrintNamewith the simplest
possible syntax in a report:
report PrintName (p_name)
define p_name char(256)
format every row
end report
Data Types, Operators, and Functions
Most of the data types available in INFORMIX-4GL are part of the
basic set of data types that Informix engines support. The basic
data types that Informix provides with its database engines were
introduced in Chapter 30, "Data Management Using SQL." A summary of
those basic data types is included in Table 36.1 for easy
reference.
Table 36.1. Basic Informix data types by engine.
Type and Structure
SE
OnLine
char (n)
Y
Y
character (n)
Y
Y
dec (precision, scale)
Y
Y
decimal (precision, scale)
Y
Y
double precision (float precision)
Y
Y
float (float precision)
Y
Y
int
Y
Y
integer
Y
Y
money (precision, scale)
Y
Y
numeric (precision, scale)
Y
Y
real
Y
Y
serial (starting number)
Y
Y
smallfloat
Y
Y
smallint
Y
Y
date
Y
Y
datetime to
Y
Y
interval to
Y
Y
byte in
N
Y
text in
N
Y
varchar (, )
N
Y
INFORMIX-4GL offers two additional data types that are unique to
4GL. The declaration and definition of all data types is covered in
detail in the next section. These additional INFORMIX-4GL-only data
types are listed here to complete the list of available data types
in INFORMIX-4GL:
record {[like .*]
[[ like ., ...]
[ , ...]]}
end record
array "[" [, [ , ] ] "]"
of
See the next section for the definitions and examples of these
two types of variables.
Variables Definition, Initialization, and Scope
Variables of all types are declared and their data type is
identified in thedefinestatement as follows:
define , ...
It is appropriate to apply to INFORMIX-4GL programs the same
variable-naming conventions that are applicable in other
programming environments at your organization. In lieu of any other
naming conventions, a very simple naming arrangement uses ap_prefix
to identify program variables, ans_prefix to define screen records
in forms, perhaps apa_prefix to identify program arrays, and
ansa_prefix to define screen records in forms. A more comprehensive
naming set is shown in Table 36.2.
Table 36.2. Variable naming standards.
Variable Name
Used for
g_
Global variables
p_
Non-record program variables
r_
Record program variables
a_
Array program variables
ra_
Array of record variables
s_
Screen record in form definitions
sa_
Screen array of records in form definitions
No matter what your naming standards are, adherence to the
standards greatly simplifies both development and maintenance
tasks.
Examples of variable definitions have already appeared earlier
in this chapter. Here are some more examples, particularly for
record and array data types:
define p_print_name char(256),
is_valid smallint,
p_emp_count, p_counter integer
This declaration makesp_print_namea character string of a fixed
256-byte length. Theis_validvariable, defined as a small integer,
does not follow the naming conventions illustrated earlier, but in
the environment, it is always used as a Boolean test, so it has
also become a standard. The variablesp_emp_countandp_counterare
both defined as integers.
Variables can also match the data types of the columns in
database tables that they represent. Thelikekeyword is used to
match the declaration to a column data type as follows. (Please
refer to the schema files for the fictitious company example,
listed at the beginning of this chapter.)
define p_empl_code integer,
p_employer like employers.employer,
p_state like states.state
Thep_empl_codevariable is defined as an integer to match
theserialdata type that the
columnemployers.empl_codehas.p_employerinherits the data type and
attributes of theemployers.employercolumn, andp_stateinherits
fromstates.state. Because there is no reference to a database
engine, INFORMIX-4GL attempts to find these variables in the
database managed by the server defined by theINFORMIXSERVERsetting
unless thedatabasestatement in your program specifically points to
a remote database. To specifically define a variable from a remote
database, while most of your variables are defined by the database
in thedatabasestatement, use the same notation illustrated when
defining thedatabaseblock:
define p_remote_empl_code like
test@on_fort_tcp:employers.empl_code
test@on_fort_tcp uses the notation@, andemployersis the name of
the table sought.p_remote_empl_coderefers to
columnemployers.empl_codein the databasetestin database
serveron_fort_tcp.
A record variable is a data structure that collects multiple
members that can be addressed collectively or individually. One of
the frequent uses of a record variable is to match an entire table
definition in the database to a program variable in memory. This
definition looks like
define p_employers record like employers.*,
p_states like states.*
The record variablep_employershas as many members as there are
columns in the employers table. You can address members in a record
singly or in groups as follows:p_employers.cityrefers to the
elementcityof the recordp_employersand is often used in this form
for testing, assigning, entering, or
printing.p_employers.employerthroughphonerefers to all members
included between theemployerandphonein the same sequence as they
are defined in the database table and is often used in entering or
when fetching records from the database.p_employers.*refers to all
members of the record and is often used to enter or to retrieve
records from the table.
You can also make up records for program-specific purposes and
define their members individually as follows:
define p_address record
empl_code like employers.emp_code,
state like employers.state,
state_long_name like states.state_name,
employee_count integer,
regional_airport char(25)
end record
This record inherits data types from two tables for part of its
members and uses basic data types for others.
A variable of typearrayis defined as follows:
define pa_calendar array [12] of date,
pa_employers array [500] of record like employers.*
Thepa_calendaris an array of up to 12 dates, but the
arraypa_employersmay contain up to 500 elements, each of which has
a record data structure that matches that of the table employers.
To refer to a specific entry in an array, you indicate the position
of the member in the array (the first member is identified by1) as
inpa_employers[100].empl_code, which refers to theempl_codevalue of
the 100th element of the arraypa_employers.
To initialize variables, INFORMIX-4GL uses the
statementinitializeand at times the assignment statementlet(which
is covered later). The syntax forinitializeis
initialize to null
An example is
initialize p_employers.* to null
initialize p_states.state_code to null
initialize is_valid to null
You can define variables in three places in an INFORMIX-4GL
program: in globals, outside of any program block, or inside a
program block (main, function, or report). The scope of a variable
is determined by the position of thedefinestatement that declares
it. Variables declared in the globals program block are available
and visible throughout an entire program; their values can be
altered anywhere and are preserved when the flow of control moves
from program block to program block. Variables declared inside a
program block, as in afunctionprogram block, are available and
visible only within that program block. Variables defined outside
all program blocks within a source code module are global to all
functions and reports (and main) also defined in that source code
module. When the name of a local variable is the same as the name
of a global variable, the value of the local variable is used in
preference over the value of the global variable within the local
function. In general, when name conflicts occur, the most local
variable wins.
Data Types and Implicit Conversions
INFORMIX-4GL supports assignments of variables of different data
types and attempts to convert them implicitly as best it can. If it
fails, it issues an error message.
Conversion between numeric data types is successful if the
destination can actually store the value it receives. For instance,
assigning an integer to a smallint fails if the magnitude of the
integer exceeds 32,767, the value of the largest smallint. Numeric
conversion always occurs within an arithmetic expression because
INFORMIX-4GL performs all arithmetic with decimal data types of
differing precision and scale.
Conversion between numeric data types and character data types
is also possible in both directions. A numeric data type can be
assigned to a character data type, and as long as the character
string is large enough, the conversion functions. When the
character variable is not large enough to receive the numeric
value, truncation occurs and theSQLCArecord reports that action.
Assigning a character data type to a numeric data type is
acceptable as long as the characters are numbers or proper
punctuation, such as a comma, period, or plus or minus sign.
Conversion between character data types of different size may
result in truncation if the destination character variable is
smaller than the original.
Dates are stored as integer values in INFORMIX-4GL and can be
assigned to an integer variable without problems. The reverse
assignment from integer to date is also possible. Dates start at
1/1/1900 (integer value 1 represents 1/1/1900; an uninitialized
date variable is displayed as 12/31/1899). Values smaller than 1
yield dates earlier than 1/1/1900. Dates can also be converted to
character, and as long as a character variable contains a valid
date format, it converts properly to a date.
The most difficult conversions are from date or character to
datetime and interval variables. A date variable can be converted
to a datetime variable, but if the precision of the datetime is
smaller than day, Informix fills the time units smaller than day
with zeroes. A better method to convert date variables to datetime
variables is to use theextendoperator and manage the conversion in
your own terms. A character variable can be converted to a datetime
as long as the format within the string matches the expectations of
the datetime for the precision in its definition. The character
variable requires a format likeyyyy-mm-dd hh:mm:ss.fffffwith a
space between the date and the time or the appropriate portion of
this format that matches the precision of the datetime variable.
Converting character variables to interval variables requires the
same formatting as the conversion between character and datetime
variables.
Operators
INFORMIX-4GL supports operators that are also valid in SQL, such
as those shown in Table 36.3.
Table 36.3. SQL operators supported in INFORMIX-4GL.
Operator
Functional Description
Mathematical Operators
+
Unary plus and addition
-
Unary minus and subtraction
*
Multiplication
/
Division
Relational Operators
=
Greater than or equal to
=
Equal
Not equal
!=
Not equal
[not] between
Inclusive range
Boolean Operators
not
Unary
and
Conditional and
or
Conditional or
String Operators
||
Concatenation
matches
Pattern matching
like
Pattern matching
Set Operators
[not] in
Value contained (or not) in list
[not] exists
True if at least one row is returned by subquery
all
True if all values returned by subquery are true
any
True if any values returned by subquery are true
some
True if some values returned by subquery are true
Null Operators
is [not] null
True if the argument is not null
In addition, INFORMIX-4GL also supports some operators that are
not available in SQL. These are listed in Table 36.4.
Table 36.4. Additional INFORMIX-4GL operators.
Operator
Functional Description
**
Exponentiation
mod
Modulus (division remainder)
,
Concatenate strings
clipped
Clip trailing blanks from a string
using
Format data for display or report purposes
For example, the following statements result in the
variablep_resultreceiving the value8:
let p_value1 = 2
let p_value2 = 3
let p_result = p_value1 ** p_value2
In the following code, the variablep_resultreceives the
value3:
let p_value1 = 17
let p_value2 = 20
let p_result = p_value2 mod p_value1
In the following code, the character variablep_resultreceives
the value"John Doe":
let p_string1 = "John "
let p_string2 = "Doe "
let p_result = p_string1 clipped, " ", p_string2
Formatting with theusingoperator allows you to display dates and
numbers in the format you specify. For date values, theusingclause
uses the strings identified in Table 36.5.
Table 36.5. Date formatting with using.
String
Results in a Display of
dd
Day of the month from 1 to 31
ddd
Day of the week: Sun, Mon, ...
mm
Month of the year from 1 to 12
mmm
Abbreviation of the month: Jan, Feb, ...
yy
Two-digit year
yyyy
Four-digit year
For example, to place the stringTue, Apr 15, 1997in the
character variablep_result, you use a date variablep_datewith the
appropriate value, as in the following code:
let p_date = "4/15/97"
let p_result = p_date using "ddd, mmm dd, yyyy"
using is used extensively in reporting and display statements.
To format numbers, theusingclause uses the strings identified in
Table 36.6.
Table 36.6. Number formatting with using.
String
Results in a Display of
#
Number or blank
&
Number or zero
*
Number or asterisk
|
}
The cursor is given the name, and it can be declared for a, for
an, or for a preprocessed. If rows will be retrieved only
sequentially, you can use a regular cursor, but if you want to
navigate back and forth within the result set, you need to use
thescrollclause to declare a scroll cursor. By default, after you
open a cursor in INFORMIX-4GL, the system closes the cursor every
time it completes a transaction. Thewith holdclause keeps the
cursor open after ending a transaction. If you intend to update the
current row, use thefor updateclause. Here are examples of
adeclarecursor statement:
declare c_employers scroll cursor with hold for statement_1
declare c_employers2 scroll cursor with hold for statement_2
for update of freight
declare c_employers cursor for select * from employers order by
empl_code
Now that the cursor is declared, you need to activate its result
set by using theopenstatement, like this:
open [ using [ , ... ] ]
When the program invokes this statement, the server receives the
SQL it represents for the first time. The server performs error
checking, sets the SQLCA variable, and stops short of delivering
the first row of the result set. If theselectstatement that was
prepared contained placeholders (question marks) for replacement by
program variables at execution time, theusingclause delivers these
variables to theopenstatement. Here are examples of both forms
ofopenstatements:
open c_employers
let p_state = "MO"
open c_employers2 using p_state
Now that the cursor is open, you can start retrieving records
and placing them in program variables. Thefetchstatement serves
this purpose, and its syntax is as follows:
fetch { next | previous | prior | first |
last | current |
relative |
absolute
} [ into ]
A sequential cursor (one declared without the scroll clause) can
perform only afetch next, but a scroll cursor can use any of the
positioning clauses indicated earlier. (The next and previous
clauses are used in the example in Listing 36.7.) The record
retrieved by thefetchis placed in program variables listed in
theinto clause. Here's an example of this statement:
fetch first c_employers into p_employers.*
After you are finished using the cursor, you need to close it
and free the resources it holds. Theclosestatement uses the
following syntax:
close
Thefreestatement uses the following syntax:
free { | }
An alternative to theopen,fetch, andclosecombination is
theforeachstatement, which performs all these functions on your
behalf. Theforeachstatement is widely used in reports or when
loading static arrays, and it is discussed in that context in
Chapter 37.
To display the data placed in program variables to the form on
the screen, you use thedisplaystatement as follows:
display { by name [ , ... ] }
[ attribute ( [ , ... ] ) ] |
[ , ... ] |
[ , ... ]
[ { to { [ , ... ] } |
["[""]"].*
at , }
[ attribute ( [ , ... ] ) ]
]
Thedisplaystatement is used to display program variables onto
screen fields. You can also display ato a screen field. If the
program variables and the screen fields use the same names, you can
use theby nameclause; otherwise, you have to match the program
variable and the screen field to display it with thetoclause. Theat
, clause was covered earlier in this chapter.
Here are some examples of thedisplaystatement:
display by name p_employers.*
display p_employers.* to s_employers.*
To modify the program variables on the screen form and
ultimately the database rows, you use theinputstatement. This
statement is discussed in the section titled "Adding, Deleting, and
Updating Records." Take some time to look at thefind.4glmodule in
Listing 36.7, which covers the entire process described here in
functionfind_it().
Finding Records and Displaying Records
The Find menu option in Figure 36.1 is designed to allow the
user to create a query dynamically. After the user chooses the Find
option, the cursor drops down to the form and allows the user to
specify the criteria desired for any of the displayed screen
fields. This process allows the user to create a Query-By-Example.
A collection of characters is available to build the
Query-By-Example. These special characters are listed in Table
36.8.
Table 36.8. The Query-By-Example special characters.
Character
Purpose
=
Equal to (if followed by nothing will look for null values)
>
Greater than
>=
Greater than or equal to