Variable and Type Declarations
The following sections describe the various variable and type declarations
Embedded SQL Variable Declaration Sections
Embedded SQL statements use C variables to transfer data from the database or form into the program. You must declare C variables to SQL before you can use them in any embedded SQL statement.
Example: C variables declared to SQL in a declaration section
exec sql begin declare section;
C variable and type declarations
exec sql end declare section;
Do not place a label in front of the exec sql end declare section statement because it causes a preprocessor syntax error.
Embedded SQL variable declarations are global to the program file from the point of declaration onwards. You can incorporate multiple declaration sections into a single program, as is the case when a few different C procedures issue embedded statements using local variables. Each procedure can have its own declaration section. For more information on the declaration of variables and types that are local to C procedures, see
The Scope of Variables in this chapter.
Reserved Words in Declarations
The following C keywords are reserved. Therefore, you cannot declare types or variables with the same name as these keywords:
Not all C compilers reserve every keyword listed. However, the embedded SQL/C preprocessor does reserve all these words.
The embedded SQL preprocessor does not distinguish between uppercase and lowercase in keywords. When it generates C code, it converts any uppercase letters in keywords to lowercase.
For example, although the following declarations are initially unacceptable to the C compiler, the preprocessor converts them into legitimate C code:
# defINE ARRSIZE 256; /*"defINE"converts to "define" */
INT numarr[ARRSIZE]; /*"INT" is equivalent to "int" */
The rule just described is true only for keywords. The preprocessor does distinguish between case in program-defined types and variables.
Variable and type names must be legal C identifiers beginning with an underscore or alphabetic character.
Data Types
The embedded SQL/C preprocessor accepts the C data types shown in the following table. This table maps these types to their corresponding Ingres types. For further information on exact type mapping between Ingres and C data, see
Data Type Conversion in this chapter.
Integer Data Type
The embedded SQL preprocessor accepts all C integer data types. Even though some integer types do have C restrictions (for example, a variable of type short must have a value that can fit into two bytes) the preprocessor does not check these restrictions. At runtime, data type conversion is effected according to standard C numeric conversion rules. For details on numeric type conversion, see
Data Type Conversion in this chapter.
The type adjectives long, short, or unsigned can qualify the integer type.
In the type mappings table previously shown, the C data type char has three possible interpretations, one of which is the Ingres integer data type. The adjective unsigned can qualify the char data type when using it as a single-byte integer. If you declare a variable of the char data type without any C indirection, such as an array subscript or a pointer operator (the asterisk), it is considered a single-byte integer variable.
Example: Declare char without C indirection
char age;
The above example is a legal declaration and can be used as an integer variable. If the variable is declared with indirection, then it is considered an Ingres character string.
You can use an integer variable with any numeric-valued object to assign or receive numeric data. For example, you can use it to set a field in a form or to select a column from a database table. You can also specify simple numeric objects, such as table field row numbers as shown here.
Example: Specify table field row numbers
char age; /* Single-byte integer */
short empnums[MAXNUMS]; /* Array of 2-byte integers */
long *global_index; /* Pointer to 4-byte integer */
unsigned int overtime;
Floating-Point Data Type
The preprocessor accepts float and double as legal floating-point data types. The internal format of double variables is the standard C runtime format.
You can only use a floating-point variable to assign or receive floating-point numeric data. You cannot use it to specify numeric objects, such as table field row numbers.
The preprocessor accepts long float as a synonym for double.
Example: Long float equivalent to double
float salary;
double sales;
is equivalent to:
float salary;
long float sales;
Both data types are accepted by the preprocessor.
Character String Data Type
Any variables built up from the char data type, except simple variables declared without any C indirection, are compatible with any Ingres character string objects. As previously mentioned, a variable of type char declared without any C indirection is considered an integer variable.
The preprocessor treats an array of characters and a pointer to a character string in the same way. Always null terminate a character string if you are assigning it to an Ingres object. Ingres automatically null terminates any character string values that are retrieved into C character string variables. Consequently, any variable that you use to receive Ingres values should be declared as the maximum object length, plus one extra byte for the C null character. For more information, see
Runtime Character Type Conversion in this chapter.
The following example declares three character variables—one integer and two strings.
Example: Declare char variables
char age /* Single byte integer */
char *name; /* Use as a pointer to a static string */
char buf[16]; /* Use to receive string data */
Character strings containing embedded single quotes are legal in SQL.
Example: Embedded single quotes usage
mary's
User variables may contain embedded single quotes and need no special handling unless the variable represents the entire search condition of a where clause:
where :variable
In this case you must escape the single quote by reconstructing the :variable string so that any embedded single quotes are modified to double single quotes, as in:
mary''s
Otherwise, a runtime error will occur.
For more information on escaping single quotes, see
String Literals in this chapter. For more information on character strings that contain embedded nulls, see
Varying Length String Type in this chapter.
# Define Declaration
The preprocessor accepts the # define directive, which defines a name to be a constant_value. The preprocessor accepts the constant_name when it is in an embedded SQL statement and treats it as if a constant_value had been given.
The syntax for the # define statement is:
# define constant_name constant_value
Syntax Notes:
• The constant_value must be an integer, floating-point, or character string literal. It cannot be an expression or another name. It cannot be left blank, as happens if you intend to use it later with the # ifdef statement. If the value is a character string constant, you must use double quotes to delimit it. Do not delimit it with single quotes to make the constant_name be interpreted as a single character constant, because the preprocessor translates the single quotes into double quotes. For example, the preprocessor interprets both of the following names as string constants, even though the first might be intended as a character constant:
# define quitflag 'Q'
# define errormsg "Fatal error occurred."
• The preprocessor does not accept casts before constant_value. In general, the preprocessor does not accept casts, and it interprets data types from the literal value.
• Do not terminate the statement with a semicolon.
You can only use a defined constant to assign values to Ingres objects. Attempting to retrieve Ingres values into a constant causes a preprocessor error as demonstrated in this example.
Example: Retrieving Ingres values into a constant
exec sql begin declare section;
# define MINEMPNUM 1
# define MAXSALARY 150000.00
# define DEFAULTNM "No-name"
exec sql end declare section;
Embedded SQL statements in the program can reference :constant_name.
Example: :constant_name usage
exec frs putform formname (salary= :MAXSALARY);
Variable Declarations Syntax
The syntax of a variable declaration is:
[storage_class] [class_modifier] type_specification
declarator {, declarator};
where each declarator is:
variable_name [= initial_value]
Syntax Notes:
• Storage_class is optional but, if specified, can be any of the following:
auto
extern
register
static
varchar
The storage class provides no data type information to the preprocessor. The varchar storage class is described in more detail later.
• Class_modifier is optional, and can be one of the following:
const
volatile
The class modifier provides no information to the preprocessor, and is merely passed through to the C compiler. Use of const and volatile keywords in ESQL/C data declarations is supported to the extent specified in the ANSI/ISO SQL-92 standard for embedded SQL C. That does not include all the possible uses of const and volatile that are accepted by the C compiler.
• Begin a variable or type name with an alphabetic character, but follow it with alphanumeric characters or underscores.
• Although register variables are supported, be careful when using them in embedded SQL statements. In input/output statements, such as the insert and select statements, you can pass a variable by reference with the ampersand operator (&). Some compilers do not allow you to use register variables this way.
• The type_specification must be an embedded SQL/C type, a type built up with a typedef declaration (and known to the preprocessor), or a structure or union specification. Typedef declarations and structures are discussed in detail later.
• Precede the variable_name by an asterisk (*), to denote a pointer variable, or follow it with a bracketed expression ([expr]), to denote an array variable. Pointers and arrays are discussed in more detail later.
• Begin the variable_name, which must be a legal C identifier name, with an underscore or alphabetic character.
• Variable names are case sensitive; that is, a variable named empid is different from one named Empid.
• Do not use a previously defined typedef name for a variable name. This also applies to any variable name that is the name of a field in a structure declaration.
• The preprocessor does not parse initial_value. Consequently, the preprocessor accepts any initial value, even if it can later cause a C compiler error. For example, the preprocessor accepts both of the following initializations, even though only the first is a legal C statement:
char *msg = "Try again";
int rowcount = {0, 123};
Example: Variable declarations usage
extern int first_employee;
auto long update_mode = 1;
static char *names[3] = {"neil","mark","barbara"};
static char *names[3] = {"john","bob","tom"};
char **nameptr = names;
short name_counter;
float last_salary = 0.0, cur_salary = 0.0;
double stat_matrix[STAT_ROWS][STAT_COLS];
const char xyz[] = "xyz";
Type Declarations Syntax
The syntax of a type declaration is:
typedef type_specification typedef_name {, typedef_name};
Syntax Notes:
• The typedef keyword acts somewhat like a storage class specifier in a variable declaration, the only difference being that the resulting typedef_name is marked as a type name and not as a variable name.
• The type_specification must be an embedded SQL/C type known to the preprocessor, a type built up with a typedef declaration, or a structure or union specification. Structures are discussed in more detail later.
• Use an asterisk (*) before the typedef_name to denote a pointer type, or follow it with a bracketed expression ([expr]) to denote an array type. Pointers and arrays are discussed in more detail later.
• The preprocessor accepts an initial_value after typedef_name, although you should avoid putting one there because it does not signify anything. Most C compilers allow an initial_value that is ignored after the typedef_name.
• Once you declare a typedef name, it is reserved for all subsequent declarations in the current scope. Thus variable names (including variable names that are names of fields in structure declarations) cannot have the same name as a previously defined typedef name.
Example: Type declarations usage
typedef short INTEGER2;
typedef char CHAR_BUF[2001], *CHAR_PTR;
INTEGER2 i2;
CHAR_BUF logbuf;
CHAR_PTR name_ptr = (char *)0;
Array Declarations Syntax
The syntax of a C array declaration is:
array_name[dimension] {[dimension]}
In the context of a simple variable declaration, the syntax is:
type_specification array_variable_name[dimension] {[dimension]};
In the context of a type declaration, the syntax is:
typedef type_specification array_type_name[dimension] {[dimension]};
Syntax Notes:
• The preprocessor does not parse the dimension specified in the brackets. Consequently, the preprocessor accepts any dimensions. However, it also accepts illegal dimensions, such as non-numeric expressions, although these later cause C compiler errors. For example, the preprocessor accepts both of the following declarations, even though only the second is legal C:
typedef int SQUARE["bad expression"];
/* Non-constant expression */
int cube_5[5][5][5];
• You can specify any number of dimensions. The preprocessor notes the number of dimensions when the variable or type is declared. When you later reference the variable, it must have the correct number of indices.
• You can initialize an array variable, but the preprocessor does not verify that the initial value is an array aggregate.
• Variables cannot have grouping parentheses in their references or declarations.
• An array of characters is considered to be the pseudo character string type.
Example: Array declarations usage
# define COLS 5
typedef short SQUARE[COLS][COLS];
SQUARE sq;
static int matrix[3][3] =
{ {11, 12, 13},
{21, 22, 23},
{31, 32, 33} };
char buf[50];
Pointer Declarations Syntax
The syntax of a C pointer declaration is:
* {*} pointer_name
In the context of a simple variable declaration, the syntax is:
type_specification *{*} pointer_variable_name;
In the context of a type declaration, the syntax is:
typedef type_specification *{*} pointer_type_name;
Syntax Notes:
• You can specify any number of asterisks. The preprocessor notes the number specified when the variable or type is declared. When the variable is later referenced, it must have the correct number of asterisks.
• You can initialize a pointer variable, but the preprocessor does not verify that the initial value is an address.
• A pointer to the char data type is considered to be the pseudo character string type.
• Do not put grouping parentheses in variable references or variable declarations.
• You can use arrays of pointers.
Example: Pointer declarations usage
extern int min_value;
int *valptr = &min_value;
char *tablename = "employee";
Structure Declarations Syntax
A C structure declaration has three variants, depending on whether it has a tag and/or a body. The following sections describe these variants.
A Structure with a Tag and a Body
The syntax of a C structure declaration with a tag and a body is:
struct tag_name {
structure_declaration {structure_declaration}
}
where structure_declaration is:
type_specification member {, member};
In the context of a simple variable declaration, the syntax is:
struct tag_name {
structure_declaration {structure_declaration}
} [structure_variable_name];
In the context of a type declaration, the syntax is:
typedef struct tag_name {
structure_declaration {structure_declaration}
} structure_type_name;
Syntax Notes:
• Wherever the keyword struct appears, the keyword union can appear instead. The preprocessor treats them as equivalent.
• Each member in a structure_declaration has the same rules as a variable of its type. For example, as with variable declarations, the type_specification of each member must be a previously defined type or another structure. Also, you can precede the member name by asterisks or follow it with brackets. Because of the similarity between structure members and variables, the following discussion focuses only on those areas in which they differ.
struct person
{
charname[40];
struct
{
int day, month, year;
} birth_date;
} owner;
• The preprocessor permits an initial value after each member name. Do not, however, put one there, because it causes a compiler syntax error.
• If you do not specify structure_variable_name, the declaration is considered a declaration of a structure tag.
• You can initialize a structure variable, but the preprocessor does not verify that the initial value is a structure aggregate.
Example: Structure with tags and body
# define MAX_EMPLOYEES 1500
typedef struct employee
{
char name[21];
short age;
double salary;
} employee_desc;
employee_desc employees[MAX_EMPLOYEES];
employee_desc *empdex = &employees[0];
A Structure with a Body and No Tag
The syntax of a C structure declaration with a body and no tag is:
struct {
structure_declaration {structure_declaration}
}
where structure_declaration is the same as in the previous section.
In the context of a simple variable declaration, the structure's syntax is:
struct {
structure_declaration {structure_declaration}
} structure_variable_name;
In the context of a type declaration, the structure's syntax is:
typedef struct {
structure_declaration {structure_declaration}
} structure_type_name;
Syntax Notes:
• All common clauses have the same rules as in the previous section. For example, struct and union are treated as equivalent, and the same rules apply to each structure member as to variables of the same type.
• Specify the structure_variable_name when there is no tag. The actual structure definition applies only to the variable being declared.
Example: Structure with body and no tag
# define MAX_EMPLOYEES 1500
Struct
{
char name[21];
short age;
double salary;
} employees[MAX_EMPLOYEES];
A Structure with a Tag and No Body
The syntax of a C structure declaration with a tag and no body is:
struct tag_name
In the context of a simple variable declaration, the syntax is:
struct tag_name structure_variable_name;
In the context of a type declaration, the syntax is:
typedef struct tag_name structure_type_name;
Syntax Notes:
• All common clauses have the same rules as in the previous section. For example, struct and union are treated as equivalent, and you can initialize the structure without the preprocessor checking for a structure aggregate.
• The tag_name must refer to a previously defined structure or union. The preprocessor does not support forward structure declarations. Therefore, when referencing a structure tag in this type of declaration, you must have already defined the tag. In the declaration below, the tag new_struct must have been previously declared:
typedef struct new_struct *NEW_TYPE;
Example: Structure with tag and no body
union a_name
{
char nm_full[30];
struct
{
char nm_first[10];
char nm_mid[2];
char nm_last[18];
} nm_parts;
};
union a_name empnames[MAX_EMPLOYEES];
Enumerated Integer Types
An enumerated type declaration, enum, is treated as an integer declaration. The syntax of an enumerated type declaration is:
enum [enum_tag]
{ enumerator [= integer_literal]
{, enumerator [= integer_literal]} } [enum_vars];
The outermost braces ({ and }) represent braces that you have to type.
Syntax Notes:
• If you use the enum_tag, the list of enumerated literals (enumerators) and enum variables (enum_vars) is optional, like a structure tag without a body. The two declarations that follow are equivalent. The first declaration declares an enum_tag, while the second declaration uses that tag to declare a variable.
First declaration:
enum color {RED, WHITE, BLUE};/* Tag,
no variable */
enum color col; /* Tag, no body,
has variable */
Second declaration:
enum color {RED, WHITE, BLUE} col;/* Tag, body,
has variable */
If you do not use the enum_tag, the declaration must include a list of enumerators, in the same way as a structure declaration.
• You can use the enum declaration with any other variable declaration, type declaration, or storage class. For example, the following declarations are all legal:
typedef enum {dbTABLE, dbCOLUMN, dbROW, dbVIEW,
dbGRANT} dbOBJ;
dbOBJ obj, objs[10];
extern dbOBJ *obj_ptr;
• Enumerated variables are treated as integer variables and enumerated literals are treated as integer constants.
Varying Length String Type
As mentioned in the section describing character strings, all C character strings are null-terminated. Ingres data of type char or varchar can contain random binary data including the zero-valued byte (the null byte or \0 in C terms). If a program uses a C char variable to retrieve or set binary data that includes nulls, the runtime system is not able to differentiate between embedded nulls and the null terminator.
In order to set and retrieve binary data that can include nulls, a new C storage class, varchar, has been provided for varying length string variables. varchar identifies the following variable declaration as a structure that describes a varying length string, namely, a 2-byte integer representing the count, and a fixed length character array. Like other storage classes, described in a previous section, the keyword varchar must appear before the variable declaration:
varchar struct {
short current_length;
char data_buffer[MAX_LENGTH];
} varchar_structure;
Syntax Notes:
• The word varchar is reserved and can be in uppercase or lowercase.
• The varchar keyword is not generated to the output C file.
• The varchar storage class can only refer to a variable declaration, not to a type declaration. For example, the following declaration is legal because it declares the variable vch:
varchar struct {
short buf_size;
char buf[100];
} vch;
But the varchar declaration of the structure tag vch (without a variable) is not legal and generates an error:
varchar struct vch {
short buf_size;
char buf[100];
};
• You can replace the structure definition of a varchar variable declaration by a structure tag or typedef reference.
Example: Legal typedef and varchar declarations
typedef struct vch_ {
short vch_count;
char vch_data[VCH_MAX];
} VCH;
varchar VCH vch_1; /* Typedef referenced */
varchar struct vch_ vch_2; /* Structure tag */
/* referenced */
• You can use the varchar storage class for any type of variable declaration, including external and static variables, and to qualify nested structure members.
Example: Legal declarations
static varchar struct _txt {
short tx_len;
char tx_data[TX_MAX];
} txt_var, *txt_ptr, txt_arr[10];
struct {
char ename[20];
int eage;
varchar struct _txt ecomments;
} emp;
typedef short buf_size;
typedef char buf[512];
varchar struct {
buf_size len;
buf data;
} vchar;
• Caution! The nvarchar struct is a Unicode version of the varchar struct. Using a pack pragma for nvarchar structures on platforms where sizeof(wchar_t) == 4 causes data corruption. Do not use a pack pragma in this case. Use the following syntax to ensure proper compiler padding:
nvarchar struct {
short len;
wchar_t text[MAX_LENGTH];
} rmy_nvarchar ;
The following is an example for ESQL/C, using the demodb database included with Ingres:
exec sql begin declare section;
nvarchar struct {
short len;
wchar_t text[31];
} res_nvarchar \;
exec sql end declare section;
...
exec sql select up_first into :res_nvarchar
from user_profile
where up_email = 'ac.fan@cool-hvac.net';
(res_nvarchar).text[(res_nvarchar).len] = L'\0';
/* Requires Locale to be set up to display Unicode, for example,
UTF-8 encoding. */
printf("nvarchar col = <%S>\n", res_nvarchar.text);
...
Varying Length Binary Type
The Ingres data type varbyte behaves just like varchar except that it bypasses character set translation when transmitted across Heterogeneous Ingres/Net.
A special varbyte structure type exists, which behaves exactly like the varchar structure type except that the associated internal data type is varbyte instead of varchar. Typedefs and struct tag declarations are supported in exactly the same way as for varchar.
Note that when a retrieved byte value does not fit into the embedded variable provided it will be truncated and a "Warning - string data, right truncation" condition is set via SQLSTATE and sqlca.sqlwarn1. This is identical to the handling of string truncation for character data.
Syntax Notes:
• The word varbyte is reserved and can be in uppercase or lowercase.
• The varbyte keyword is not generated to the output C file.
• The varbyte storage class can only refer to a variable declaration, not to a type declaration. For example, the following declaration is legal because it declares the variable vbyt:
varbyte struct {
short buf_size;
char buf[100];
} vbyt;
But the varbyte declaration of the structure tag vbyt (without a variable) is not legal and generates an error:
varbyte struct vbyt {
short buf_size;
char buf[100];
};
• You can replace the structure definition of a varbyte variable declaration by a structure tag or typedef reference.
Example: Legal typedef and varbyte declarations
typedef struct vbyt_ {
short vbyt_count;
char vbyt_data[VCH_MAX];
} VBYT;
varbyte VBYT vbyt 1; /* Typedef referenced */
varbyte struct vbyt_ vch_2; /* Structure tag */
/* referenced */
• You can use the varbyte storage class for any type of variable declaration, including external and static variables, and to qualify nested structure members.
Example: Legal declarations
static varbyte struct _txt {
short tx_len;
char tx_data[TX_MAX];
} txt_var, *txt_ptr, txt_arr[10];
struct v_ {
short length;
char data[MAXLEN];
};
VARBYTE struct v_ my_varbyte;
typedef short buf_size;
typedef char buf[512];
varbyte struct {
buf_size len;
buf data;
} vbyte;
DCLGEN Utility
The DCLGEN (Declaration Generator) utility is a structure-generating utility that maps the columns of a database table into a structure that you can include in a declaration section.
The DCLGEN utility can be invoked from the operating system level by executing the following command:
dclgen language dbname tablename filename structurename [-n] [-q]
language
Defines the embedded SQL host language, in this case, C.
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 structure declaration is placed.
structurename
Defines the name of the host language structure that the command generates. The structure tag is the structure name followed by an underscore character (_).
-n
Does not print the DECLARE TABLE statement.
-q
Creates output in QUEL format.
This command creates the declaration file filename, containing a structure corresponding to the database table. The file also includes a declare table statement that serves as a comment and identifies the database table and columns from which the structure was generated.
When the file is generated, use an embedded SQL include statement to incorporate it into the variable declaration section. The following example demonstrates how to use DCLGEN in a C 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(14,2) not null,
dept smallint)
with journaling;
Also, assume the DCLGEN system-level command is:
dclgen c personnel employee employee.dcl emprec
This command creates the employee.dcl file, which contains a comment and two statements. The first statement is the declare table description of employee, which serves as a comment. The second statement is a declaration of the C structure emprec. The contents of the employee.dcl file are:
/* Table employee description from database personnel */
exec sql declare employee table
(eno smallint not null,
ename char(20) not null,
age integer1,
job smallint,
sal decimal(14,2) not null,
dept smallint);
struct emprec_ {
short eno;
char ename[21];
short age;
short job;
double sal;
short dept;
} emprec;
The length of the ename buffer is increased by one byte to accommodate the C null terminator. Also, the integer1 data type is mapped to short rather than char.
To include this file in an embedded SQL declaration section, use the embedded SQL include statement:
exec sql begin declare section;
exec sql include 'employee.dcl';
exec sql end declare section;
You can then use the emprec structure in a select, fetch, or insert statement.
The field names in the structure that DCLGEN generates are identical to the column names in the specified table. Therefore, if the column names in the table contain any characters that are illegal for host language variable names, you must modify the name of the field before attempting to use the variable in an application.
DCLGEN and Large Objects
When a table contains a large object column, DCLGEN will issue a warning message and map the column to a zero length character string variable. You must modify the length of the generated variable before attempting to use the variable in an application.
For example, assume that the job_description table was created in the personnel database as:
create table job_description (job smallint,
description long varchar);
Also, assume the DCLGEN system-level command is:
dclgen c personnel job_description jobs.dcl jobs_rec
The contents of the jobs.dcl file would be:
/*Table job_description description from database
personnel*/
exec sql declare job_description table
(job smallint,
description long varchar);
struct jobs_rec_ {
short job;
char description[0];
} jobs_rec;
Indicator Variables
An indicator variable is a 2-byte integer variable. You can use an indicator variable in an application in three ways:
• In a statement that retrieves data from the database, you can use an indicator variable to determine if its associated host variable was assigned a null.
• In a statement that writes data to the database, or to a form field, 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 (or byte) data, 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 string. However you can also use SQLSTATE to do this and it is the preferred method.
The base type for a null indicator variable must be the integer type short. Any type specification built up from short is legal.
Example: Type specification built from short
short ind; /* Indicator variable */
typedef short IND;
IND ind_arr[10]; /* Array of indicators */
IND *ind_ptr; /* Pointer to indicator */
The word indicator is reserved and cannot be used to define a type in a typedef statement.
When using an indicator array with a host structure, as described in Indicator Variables Usage, you must declare the indicator array as an array of short integers (or a type built up from short). In the above example, you can use the variable ind_arr as an indicator array with a structure assignment.
How to Declare External Compiled Forms
You can precompile your forms in the Visual-Forms Editor (VIFRED). By doing so, you save 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 C language. The following system specific section contains the remaining information you will need to declare your forms.
Windows Forms
VIFRED prompts you for the name of the file with the description. After creating the file, you can use the following cl command to compile it into linkable object code:
cl -c filename
The C compiler usually returns warning messages during this operation. You can suppress these, if you wish, with the -w flag on the cl command line. This command results in an object file that contains a global symbol with the same name as your form.
Before the embedded SQL/FORMS statement addform can refer to this global object, you must declare it in an embedded SQL declaration section, with the following syntax:
extern int *formname;
Syntax Notes:
• 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 embedded SQL/FORMS statements.
• The extern storage class associates the object with the external form definition.
• Although you declare formname as a pointer, you should not precede it with an asterisk when using it in the addform statement.
The example below shows a typical form declaration and illustrates the difference between using the form's object definition and the form's name.
Example: Form declaration
exec sql begin declare section;
extern int *empform;
...
exec sql end declare section;
...
exec frs addform :empform; /* the global object */
exec frs display empform; /* the name of the form */
...
Linux Forms
VIFRED prompts you for the name of the file with the description. After creating the file, you can use the following cc command to compile it into linkable object code:
cc -c filename
The C compiler usually returns warning messages during this operation. You can suppress these, if you wish, with the -w flag on the cc command line. This command results in an object file that contains a global symbol with the same name as your form.
Before the embedded SQL/FORMS statement addform can refer to this global object, you must declare it in an embedded SQL declaration section, with the following syntax:
extern int *formname;
Syntax Notes:
• 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 embedded SQL/FORMS statements.
• The extern storage class associates the object with the external form definition.
• Although you declare formname as a pointer, you should not precede it with an asterisk when using it in the addform statement.
The example below shows a typical form declaration and illustrates the difference between using the form's object definition and the form's name.
Example: Form declaration
exec sql begin declare section;
extern int *empform;
...
exec sql end declare section;
...
exec frs addform :empform; /* the global object */
exec frs display empform; /* The name of the form */
...
Embedded SQL/C Declarations Example
The following example demonstrates some simple embedded SQL/C declarations:
exec sql include sqlca; /* include error handling */
exec sql begin declare section;
# define max_persons 1000
typedef struct datatypes_/* Structure of all types */
{
char d_byte;
short d_word;
long d_long;
float d_single;
double d_double;
char *d_string;
} datatypes;
datatypes d_rec;
char *dbname = "personnel";
char *formname, *tablename, *columnname;
varchar struct {
short len;
char binary_data[512];
} binary_chars;
enum color {RED, WHITE, BLUE} col;
unsigned int empid;
short int vac_balance;
struct person_ /* Structure with a union */
{
char age;
long flags;
union
{
char full_name[30];
struct {
char firstname[12], lastname[18];
} name_parts;
} person_name;
} person, *newperson, person_store[MAX_PERSONS];
exec sql include 'employee.dcl'; /* From DCLGEN */
Windows:
extern int *empform, *deptform; /* Compiled forms */
exec sql end declare section;
Linux:
extern int *empform, *deptform; /* Compiled forms */
exec sql end declare section;