IBM Books

Application Development Guide


Characteristics and Reasons for Using Static SQL

When the syntax of embedded SQL statements is fully known at precompile time, the statements are referred to as static SQL. This is in contrast to dynamic SQL statements whose syntax is not known until run time.
Note:Static SQL is not supported in interpreted languages, such as REXX.

The structure of an SQL statement must be completely specified in order for a statement to be considered static. For example, the names for the columns and tables referenced in a statement must be fully known at precompile time. The only information that can be specified at run time are values for any host variables referenced by the statement. However, host variable information, such as data types, must still be precompiled.

When a static SQL statement is prepared, an executable form of the statement is created and stored in the package in the database. The executable form can be constructed either at precompile time, or at a later bind time. In either case, preparation occurs before run time. The authorization of the person binding the application is used, and optimization is based upon database statistics and configuration parameters that may not be current when the application runs.

Advantages of Static SQL

Programming using static SQL requires less effort than using embedded dynamic SQL. Static SQL statements are simply embedded into the host language source file, and the precompiler handles the necessary conversion to database manager run-time services API calls that the host language compiler can process.

Because the authorization of the person binding the application is used, the end user does not require direct privileges to execute the statements in the package. For example, an application could allow a user to update parts of a table without granting an update privilege on the entire table. This can be achieved by restricting the static SQL statements to allow updates only to certain columns or a range of values.

Static SQL statements are persistent, meaning that the statements last for as long as the package exists. Dynamic SQL statements are cached until they are either invalidated, freed for space management reasons, or the database is shut down. If required, the dynamic SQL statements are recompiled implicitly by the DB2 SQL compiler whenever a cached statement becomes invalid. For information on caching and the reasons for invalidation of a cached statement, refer to the SQL Reference.

The key advantage of static SQL, with respect to persistence, is that the static statements exist after a particular database is shut down, whereas dynamic SQL statements cease to exist when this occurs. In addition, static SQL does not have to be compiled by the DB2 SQL compiler at run time, while dynamic SQL must be explicitly compiled at run time (for example, by using the PREPARE statement). Because DB2 caches dynamic SQL statements, the statements do not need to be compiled often by DB2, but they must be compiled at least once when you execute the application.

There can be performance advantages to static SQL. For simple, short-running SQL programs, a static SQL statement executes faster than the same statement processed dynamically since the overhead of preparing an executable form of the statement is done at precompile time instead of at run time.
Note:The performance of static SQL depends on the statistics of the database the last time the application was bound. However, if these statistics change, the performance of equivalent dynamic SQL can be very different. If, for example, an index is added to a database at a later time, an application using static SQL cannot take advantage of the index unless it is re-bound to the database. In addition, if you are using host variables in a static SQL statement, the optimizer will not be able to take advantage of any distribution statistics for the table.

Example: Static SQL Program

This sample program shows examples of static SQL statements and database manager API calls in the following supported languages:

C
static.sqc

Java
Static.sqlj

COBOL
static.sqb

FORTRAN
static.sqf

The REXX language does not support static SQL, so a sample is not provided.

This sample program contains a query that selects a single row. Such a query can be performed using the SELECT INTO statement.

The SELECT INTO statement selects one row of data from tables in a database, and the values in this row are assigned to host variables specified in the statement. Host variables are discussed in detail in Using Host Variables. For example, the following statement will deliver the salary of the employee with the last name of 'HAAS' into the host variable empsal:

 
     SELECT SALARY 
       INTO :empsal 
       FROM EMPLOYEE 
       WHERE LASTNAME='HAAS' 

A SELECT INTO statement must be specified to return only one or zero rows. Finding more than one row results in an error, SQLCODE -811 (SQLSTATE 21000). If several rows can be the result of a query, a cursor must be used to process the rows. See Selecting Multiple Rows Using a Cursor for more information.

For more details on the SELECT INTO statement, refer to the SQL Reference.

For an introductory discussion on how to write SELECT statements, see Coding SQL Statements to Retrieve and Manipulate Data.

How the Static Program Works

  1. Include the SQLCA. The INCLUDE SQLCA statement defines and declares the SQLCA structure, and defines SQLCODE and SQLSTATE as elements within the structure. The SQLCODE field of the SQLCA structure is updated with diagnostic information by the database manager after every execution of SQL statements or database manager API calls.

  2. Declare host variables. The SQL BEGIN DECLARE SECTION and END DECLARE SECTION statements delimit the host variable declarations. These are variables that can be referenced in SQL statements. Host variables are used to pass data to the database manager or to hold data returned by it. They are prefixed with a colon (:) when referenced in an SQL statement. For more information, see Using Host Variables.

  3. Connect to database. The program connects to the sample database, and requests shared access to it. (It is assumed that a START DATABASE MANAGER API call or db2start command has been issued.) Other programs that connect to the same database using shared access are also granted access.

  4. Retrieve data. The SELECT INTO statement retrieves a single value based upon a query. This example retrieves the FIRSTNME column from the EMPLOYEE table where the value of the LASTNAME column is JOHNSON. The value SYBIL is returned and placed in the host variable firstname. The sample tables supplied with DB2 are listed in the appendix of the SQL Reference.

  5. Process errors. The CHECKERR macro/function is an error checking utility which is external to the program. The location of this error checking utility depends upon the programming language used:

    C
    check_error is redefined as CHECKERR and is located in the util.c file.

    Java
    Any SQL error is thrown as an SQLException and handled in the catch block of the application.

    COBOL
    CHECKERR is an external program named checkerr.cbl

    FORTRAN
    CHECKERR is a subroutine located in the util.f file.

    See Using GET ERROR MESSAGE in Example Programs for the source code for this error checking utility.

  6. Disconnect from database. The program disconnects from the database by executing the CONNECT RESET statement. Note that SQLJ programs automatically close the database connection when the program returns.

C Example: STATIC.SQC

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
 
#ifdef DB268K
/* Need to include ASLM for 68K applications */
#include <LibraryManager.h>
#endif
 
EXEC SQL INCLUDE SQLCA;  (1)
#define  CHECKERR(CE_STR)   if (check_error (CE_STR, &sqlca) != 0) return 1;
 
int main(int argc, char *argv[]) {
   EXEC SQL BEGIN DECLARE SECTION; (2)
      char firstname[13];
      char userid[9];
      char passwd[19];
   EXEC SQL END DECLARE SECTION;
 
#ifdef DB268K
   /* Before making any API calls for 68K environment,
      need to initial the Library Manager */
   InitLibraryManager(0,kCurrentZone,kNormalMemory);
   atexit(CleanupLibraryManager);
#endif
 
   printf( "Sample C program: STATIC\n" );
   if (argc == 1) {
      EXEC SQL CONNECT TO sample;
      CHECKERR ("CONNECT TO SAMPLE");
   }
   else if (argc == 3) { 
      strcpy (userid, argv[1]);
      strcpy (passwd, argv[2]);
      EXEC SQL CONNECT TO sample USER :userid USING :passwd; (3)
      CHECKERR ("CONNECT TO SAMPLE");
   }
   else {
      printf ("\nUSAGE: static [userid passwd]\n\n");
      return 1;
   } /* endif */
 
   EXEC SQL SELECT FIRSTNME INTO :firstname  (4)
            FROM employee
            WHERE LASTNAME = 'JOHNSON';
   CHECKERR ("SELECT statement");  (5)
   printf( "First name = %s\n", firstname );
   EXEC SQL CONNECT RESET;  (6)
   CHECKERR ("CONNECT RESET");
   return 0;
}
/* end of program : STATIC.SQC */

Java Example: Static.sqlj

import java.sql.*;
import sqlj.runtime.*;
import sqlj.runtime.ref.*;
 
class Static 
{   static
  {   try
    {   Class.forName ("COM.ibm.db2.jdbc.app.DB2Driver").newInstance ();
    } 
    catch (Exception e)
    {   System.out.println ("\n  Error loading DB2 Driver...\n");
      System.out.println (e);
      System.exit(1);
    }
  }
 
  public static void main(String argv[])
  {   try 
    {   System.out.println ("  Java Static Sample");
 
      String url = "jdbc:db2:sample";       // URL is jdbc:db2:dbname
      Connection con = null;          
 
      // Set the connection                 (3)
      if (argv.length == 0) 
      {   // connect with default id/password
                 con = DriverManager.getConnection(url);  
      }
      else if (argv.length == 2)
      {   String userid = argv[0];
                 String passwd = argv[1];
                 // connect with user-provided username and password
                 con = DriverManager.getConnection(url, userid, passwd); 
      }
      else 
      {   throw new Exception("\nUsage: java Static [username password]\n");
      } 
 
      // Set the default context
      DefaultContext ctx = new DefaultContext(con);            
      DefaultContext.setDefaultContext(ctx);
 
      String firstname = null;  (2)
      #sql { SELECT FIRSTNME INTO :firstname 
            FROM employee
            WHERE LASTNAME = 'JOHNSON' } ;   (4)
 
      System.out.println ("First name = " + firstname);
    }
    catch( Exception e )  (5)
    {   System.out.println (e);
    }
  }
}

COBOL Example: STATIC.SQB

       Identification Division.
       Program-ID. "static".
 
       Data Division.
       Working-Storage Section.
           copy "sql.cbl".
           copy "sqlca.cbl".                                            (1)
           EXEC SQL BEGIN DECLARE SECTION END-EXEC.                     (2)
       01 firstname         pic x(12).
       01 userid            pic x(8).
       01 passwd.
         49 passwd-length   pic s9(4) comp-5 value 0.
         49 passwd-name     pic x(18).
           EXEC SQL END DECLARE SECTION END-EXEC.
 
       77 errloc          pic x(80).
 
       Procedure Division.
       Main Section.
           display "Sample COBOL program: STATIC".
           display "Enter your user id (default none): " 
                with no advancing.
           accept userid.
 
           if userid = spaces
             EXEC SQL CONNECT TO sample END-EXEC
           else
             display "Enter your password : " with no advancing
             accept passwd-name.
 
      * Passwords in a CONNECT statement must be entered in a VARCHAR format
      * with the length of the input string.
           inspect passwd-name tallying passwd-length for characters
              before initial " ".
 
           EXEC SQL CONNECT TO sample USER :userid USING :passwd        (3)
              END-EXEC.
           move "CONNECT TO" to errloc.
           call "checkerr" using SQLCA errloc.
 
           EXEC SQL SELECT FIRSTNME INTO :firstname                     (4)
                    FROM EMPLOYEE
                    WHERE LASTNAME = 'JOHNSON' END-EXEC.
           move "SELECT" to errloc.
           call "checkerr" using SQLCA errloc.                          (5)
           display "First name = ", firstname.
 
           EXEC SQL CONNECT RESET END-EXEC.                             (6)
           move "CONNECT RESET" to errloc.
           call "checkerr" using SQLCA errloc.
 
       End-Prog.
           stop run.

FORTRAN Example: STATIC.SQF

      program static
      implicit none
 
      include 'sqlenv.f'
      EXEC SQL INCLUDE SQLCA (1)
 
      EXEC SQL BEGIN DECLARE SECTION (2)
        character*12   firstname
        character*8    userid
        character*18   passwd
      EXEC SQL END DECLARE SECTION
 
      character*80     errloc
 
      print *, 'Sample Fortran Program: STATIC'
 
      print *, 'Enter your user id (default none):'
      read 100, userid
100   format (a8)      
 
      if( userid(1:1) .eq. ' ' ) then
        EXEC SQL CONNECT TO sample 
      else
	print *, 'Enter your password :'
	read 100, passwd
	EXEC SQL CONNECT TO sample USER :userid USING :passwd
      end if (3)
      errloc = 'CONNECT' 
      call checkerr (sqlca, errloc, *999)
 
      EXEC SQL SELECT firstnme INTO :firstname
     c FROM employee WHERE lastname = 'JOHNSON' (4)
      errloc = 'SELECT'
      call checkerr (sqlca, errloc, *999) (5)
 
      print *, 'First name = ', firstname
 
      EXEC SQL CONNECT RESET (6)
      errloc = 'CONNECT RESET'
      call checkerr (sqlca, errloc, *999)
 
  999 stop
      end

Coding SQL Statements to Retrieve and Manipulate Data

The database manager provides application programmers with statements for retrieving and manipulating data; the coding task consists of embedding these statements into the host language code. This section shows how to code statements that will retrieve and manipulate data for one or more rows of data in DB2 tables. (It does not go into the details of the different host languages.) For the exact rules of placement, continuation, and delimiting SQL statements, see:

Retrieving Data

One of the most common tasks of an SQL application program is to retrieve data. This is done using the select-statement, which is a form of query that searches for rows of tables in the database that meet specified search conditions. If such rows exist, the data is retrieved and put into specified variables in the host program, where it can be used for whatever it was designed to do.

After you have written a select-statement, you code the SQL statements that define how information will be passed to your application.

You can think of the result of a select-statement as being a table having rows and columns, much like a table in the database. If only one row is returned, you can deliver the results directly into host variables specified by the SELECT INTO statement.

If more than one row is returned, you must use a cursor to fetch them one at a time. A cursor is a named control structure used by an application program to point to a specific row within an ordered set of rows. For information about how to code and use cursors, see the following sections:

Using Host Variables

Host variables are variables referenced by embedded SQL statements. They transmit data between the database manager and an application program. When you use a host variable in an SQL statement, you must prefix its name with a colon, (:). When you use a host variable in a host language statement, omit the colon.

Host variables are declared in compiled host languages, and are delimited by BEGIN DECLARE SECTION and END DECLARE SECTION statements. These statements enable the precompiler to find the declarations.
Note:Java JDBC and SQLJ programs do not use declare sections. Host variables in Java follow the normal Java variable declaration syntax.

Host variables are declared using a subset of the host language. For a description of the supported syntax for your host language, see:

The following rules apply to host variable declaration sections:

For further information on declaring host variables, see:

Declaration Generator - db2dclgn

The Declaration Generator speeds application development by generating declarations for a given table in a database. It creates embedded SQL declaration source files which you can easily insert into your applications. db2dclgn supports the C/C++, Java, COBOL, and FORTRAN languages.

To generate declaration files, enter the db2dclgn command in the following format:

db2dclgn -d database-name -t table-name [options]

For example, to generate the declarations for the STAFF table in the SAMPLE database in C in the output file staff.h, issue the following command:

db2dclgn -d sample -t staff -l C

The resulting staff.h file contains:

     struct
     {
       short id;
       struct
       {
         short length;
         char data[9];
       } name;
       short dept;
       char job[5];
       short years;
       double salary;
       double comm;
     } staff;

For detailed information on db2dclgn, refer to the Command Reference.

Table 4. Declaring Host Variables
Language Example Source Code
C/C++
EXEC SQL BEGIN DECLARE SECTION; 
  short     dept=38, age=26; 
  double    salary; 
  char      CH; 
  char      name1[9], NAME2[9]; 
  /* C comment */ 
  short     nul_ind; 
EXEC SQL END DECLARE SECTION;

Java
// Note that Java host variable declarations follow
// normal Java variable declaration rules, and have
// no equivalent of a DECLARE SECTION
  short     dept=38, age=26; 
  double    salary; 
  char      CH; 
  String    name1[9], NAME2[9]; 
  /* Java comment */ 
  short     nul_ind;

COBOL
 EXEC SQL BEGIN DECLARE SECTION END-EXEC. 
   01 age        PIC S9(4) COMP-5 VALUE 26. 
   01 DEPT       PIC S9(9) COMP-5 VALUE 38. 
   01 salary     PIC S9(6)V9(3) COMP-3. 
   01 CH         PIC X(1). 
   01 name1      PIC X(8). 
   01 NAME2      PIC X(8). 
*  COBOL comment 
   01 nul-ind    PIC S9(4) COMP-5. 
 EXEC SQL END DECLARE SECTION END-EXEC.

FORTRAN
       EXEC SQL BEGIN DECLARE SECTION
         integer*2     age   /26/
         integer*4     dept  /38/
         real*8        salary 
         character     ch 
         character*8   name1,NAME2 
C        FORTRAN comment 
         integer*2     nul_ind 
       EXEC SQL END DECLARE SECTION


Table 5. Referencing Host Variables
Language Example Source Code
C/C++
EXEC SQL FETCH C1 INTO :cm; 
printf( "Commission = %f\n", cm );

JAVA (SQLJ)
#SQL { FETCH :c1 INTO :cm };
System.out.println("Commission = " + cm);

COBOL
EXEC SQL FETCH C1 INTO :cm END-EXEC 
DISPLAY 'Commission = ' cm

FORTRAN
EXEC SQL FETCH C1 INTO :cm 
WRITE(*,*) 'Commission = ', cm

Using Indicator Variables

Applications written in languages other than Java must prepare for receiving null values by associating an indicator variable with any host variable that can receive a null. Java applications compare the value of the host variable with Java null to determine whether the received value is null. An indicator variable is shared by both the database manager and the host application; therefore, the indicator variable must be declared in the application as a host variable. This host variable corresponds to the SQL data type SMALLINT.

An indicator variable is placed in an SQL statement immediately after the host variable, and is prefixed with a colon. A space can separate the indicator variable from the host variable, but is not required. However, do not put a comma between the host variable and the indicator variable. You can also specify an indicator variable by using the optional INDICATOR keyword, which you place between the host variable and its indicator.

Indicator Variables shows indicator variable usage in the supported host languages using the INDICATOR keyword.

Language
Example Source Code

C/C++
EXEC SQL FETCH C1 INTO :cm INDICATOR :cmind; 
if ( cmind < 0 ) 
   printf( "Commission is NULL\n" );

Java (SQLJ)
#SQL { FETCH :c1 INTO :cm }; 
if ( cm == null ) 
   System.out.println( "Commission is NULL\n" );

COBOL
EXEC SQL FETCH C1 INTO :cm INDICATOR :cmind END-EXEC 
IF cmind LESS THAN 0 
   DISPLAY 'Commission is NULL'

FORTRAN
EXEC SQL FETCH C1 INTO :cm INDICATOR :cmind 
IF ( cmind .LT. 0 ) THEN 
   WRITE(*,*) 'Commission is NULL' 
ENDIF

In the figure, cmind is examined for a negative value. If it is not negative, the application can use the returned value of cm. If it is negative, the fetched value is NULL and cm should not be used. The database manager does not change the value of the host variable in this case.
Note:If the database configuration parameter DFT_SQLMATHWARN is set to 'YES', the value of cmind may be -2. This indicates a NULL that was caused by evaluating an expression with an arithmetic error or by an overflow while attempting to convert the numeric result value to the host variable.

If the data type can handle NULLs, the application must provide a NULL indicator. Otherwise, an error may occur. If a NULL indicator is not used, an SQLCODE -305 (SQLSTATE 22002) is returned.

If the SQLCA structure indicates a truncation warning, the indicator variables can be examined for truncation. If an indicator variable has a positive value, a truncation occurred.

When processing INSERT or UPDATE statements, the database manager checks the indicator variable if one exists. If the indicator variable is negative, the database manager sets the target column value to NULL if NULLs are allowed. If the indicator variable is zero or positive, the database manager uses the value of the associated host variable.

The SQLWARN1 field in the SQLCA structure may contain an 'X' or 'W' if the value of a string column is truncated when it is assigned to a host variable. It contains an 'N' if a null terminator is truncated.

A value of 'X' is returned by the database manager only if all of the following conditions are met:

The value returned in the indicator variable will be the length of the resultant character string in the application's code page.

In all other cases involving data truncation, (as opposed to NULL terminator truncation), the database manager returns a 'W'. In this case, the database manager returns a value in the indicator variable to the application that is the length of the resultant character string in the code page of the select list item (either the application code page, the data base code page, or nothing). For related information, refer to the SQL Reference.

Data Types

Each column of every DB2 table is given an SQL data type when the column is created. For information about how these types are assigned to columns, refer to the CREATE TABLE statement in the SQL Reference. The database manager supports the following column data types:

SMALLINT
16-bit signed integer.

INTEGER
32-bit signed integer. INT can be used as a synonym for this type.

BIGINT
64-bit signed integer.

DOUBLE
Double-precision floating point. DOUBLE PRECISION and FLOAT(n) (where n is greater than 24) are synonyms for this type.

REAL
Single-precision floating point. FLOAT(n) (where n is less than 24) is a synonym for this type.

DECIMAL
Packed decimal. DEC, NUMERIC, and NUM are synonyms for this type.

CHAR
Fixed-length character string of length 1 byte to 254 bytes. CHARACTER can be used as a synonym for this type.

VARCHAR
Variable-length character string of length 1 byte to 32672 bytes. CHARACTER VARYING and CHAR VARYING are synonyms for this type.

LONG VARCHAR
Long variable-length character string of length 1 byte to 32 700 bytes.

CLOB
Large object variable-length character string of length 1 byte to 2 gigabytes.

BLOB
Large object variable-length binary string of length 1 byte to 2 gigabytes.

DATE
Character string of length 10 representing a date.

TIME
Character string of length 8 representing a time.

TIMESTAMP
Character string of length 26 representing a timestamp.

The following data types are supported only in double-byte character set (DBCS) and Extended UNIX Code (EUC) character set environments:

GRAPHIC
Fixed-length graphic string of length 1 to 127 double-byte characters.

VARGRAPHIC
Variable-length graphic string of length 1 to 16336 double-byte characters.

LONG VARGRAPHIC
Long variable-length graphic string of length 1 to 16 350 double-byte characters.

DBCLOB
Large object variable-length graphic string of length 1 to 1 073 741 823 double-byte characters.

Notes:

  1. Every supported data type can have the NOT NULL attribute. This is treated as another type.

  2. The above set of data types can be extended by defining user-defined distinct types (UDT). UDTs are separate data types which use the representation of one of the built-in SQL types.

Supported host languages have data types that correspond to the majority of the database manager data types. Only these host language data types can be used in host variable declarations. When the precompiler finds a host variable declaration, it determines the appropriate SQL data type value. The database manager uses this value to convert the data exchanged between itself and the application.

As the application programmer, it is important for you to understand how the database manager handles comparisons and assignments between different data types. Simply put, data types must be compatible with each other during assignment and comparison operations, whether the database manager is working with two SQL column data types, two host-language data types, or one of each.

The general rule for data type compatibility is that all supported host-language numeric data types are comparable and assignable with all database manager numeric data types, and all host-language character types are compatible with all database manager character types; numeric types are incompatible with character types. However, there are also some exceptions to this general rule depending on host language idiosyncrasies and limitations imposed when working with large objects.

Within SQL statements, DB2 provides conversions between compatible data types. For example, in the following SELECT statement, SALARY and BONUS are DECIMAL columns; however, each employee's total compensation is returned as DOUBLE data:

   SELECT EMPNO, DOUBLE(SALARY+BONUS) FROM EMPLOYEE

Note that the execution of the above statement includes conversion between DECIMAL and DOUBLE data types. To make the query results more readable on your screen, you could use the following SELECT statement:

   SELECT EMPNO, DIGIT(SALARY+BONUS) FROM EMPLOYEE

To convert data within your application, contact your compiler vendor for additional routines, classes, built-in types, or APIs that supports this conversion.

Character data types may also be subject to character conversion. If your application code page is not the same as your database code page, see Conversion Between Different Code Pages.

For the list of supported SQL data types and the corresponding host language data types, see the following:

For more information about SQL data types, the rules of assignments and comparisons, and data conversion and conversion errors, refer to the SQL Reference.

Using an Indicator Variable in the STATIC program

The following code segments show the modification to the corresponding segments in the C version of the sample STATIC program, listed in C Example: STATIC.SQC. They show the implementation of indicator variables on data columns that are nullable. In this example. the STATIC program is extended to select another column, WORKDEPT. This column can have a null value. An indicator variable needs to be declared as a host variable before being used.

 
  .
  .
  .
EXEC SQL BEGIN DECLARE SECTION; 
  char  wd[3]; 
  short wd_ind; 
  char firstname[13]; 
  .
  .
  .
 
EXEC SQL END DECLARE SECTION; 
  .
  .
  .
/* CONNECT TO SAMPLE DATABASE */ 
  .
  .
  .
EXEC SQL SELECT FIRSTNME, WORKDEPT INTO :firstname, :wd:wdind 
  FROM EMPLOYEE 
  WHERE LASTNAME = 'JOHNSON'; 
  .
  .
  .


[ Top of Page | Previous Page | Next Page | Table of Contents | Index ]

[ DB2 List of Books | Search the DB2 Books ]