IBM Books

Call Level Interface Guide and Reference


Initialization and Termination

Figure 2. Conceptual View of Initialization and Termination Tasks


Conceptual View of Initialization and Termination Tasks

Figure 2 shows the function call sequences for both the initialization and termination tasks. The transaction processing task in the middle of the diagram is shown in Figure 3.

Handles

The initialization task consists of the allocation and initialization of environment and connection handles (which are later freed in the termination task). An application then passes the appropriate handle when it calls other DB2 CLI functions. A handle is a variable that refers to a data object controlled by DB2 CLI. Using handles relieves the application from having to allocate and manage global variables or data structures, such as the SQLDA or SQLCA, used in IBM's embedded SQL interfaces.

The SQLAllocHandle() function is called with a handle type and parent handle arguments to create environment, connection, statement, or descriptor handles. The function SQLFreeHandle() is used to free the resources allocated to a handle.

There are four types of handles:

Environment Handle
The environment handle refers to the data object that contains information regarding the global state of the application, such as attributes and connections. An environment handle must be allocated before a connection handle can be allocated.

Connection Handle
A connection handle refers to a data object that contains information associated with a connection to a particular data source (database). This includes connection attributes, general status information, transaction status, and diagnostic information.

An application can be connected to several servers at the same time, and can establish several distinct connections to the same server. An application requires a connection handle for each concurrent connection to a database server. For information on multiple connections, refer to Connecting to One or More Data Sources.

Call SQLGetInfo() to determine if a user imposed limit on the number of connector handles has been set.

Statement Handle(s)
Statement handles are discussed in the next section, Transaction Processing.

Descriptor Handle(s)
A descriptor handle refers to a data object that contains information about:

Descriptors and descriptor handles are discussed in the section Using Descriptors.

Connecting to One or More Data Sources

In order to connect concurrently to one or more data sources (or multiple concurrent connections to the same data source), an application calls SQLAllocHandle(), with a HandleType of SQL_HANDLE_DBC, once for each connection. The subsequent connection handle is used with SQLConnect() to request a database connection and with SQLAllocHandle(), with a HandleType of SQL_HANDLE_STMT, to allocate statement handles for use within that connection. There is also an extended connect function, SQLDriverConnect(), which allows for additional connect options, and the ability to directly open a connection dialog box in environments that support a Graphical User Interface. The function SQLBrowseConnect() can be used to discover all of the attributes and attribute values required to connect to a data source.

The use of connection handles ensures that multi-threaded applications that utilize one connection per thread are thread-safe since separate data structures are allocated and maintained by DB2 CLI for each connection.

Unlike the distributed unit of work connections described in Multisite Updates (Two Phase Commit), there is no coordination between the statements that are executed on different connections.

Initialization and Connection Example

/* From CLI sample basiccon.c */
/* ... */
#include <stdio.h>
#include <stdlib.h>
#include <sqlcli1.h>
 
/* ... */
 
SQLRETURN
prompted_connect( SQLHANDLE henv,
                  SQLHANDLE * hdbc);
 
#define MAX_UID_LENGTH   18
#define MAX_PWD_LENGTH   30
#define MAX_CONNECTIONS  2
 
#define MAX_CONNECTIONS 2
 
/* extern SQLCHAR server[SQL_MAX_DSN_LENGTH + 1] ;
extern SQLCHAR uid[MAX_UID_LENGTH + 1] ;
extern SQLCHAR pwd[MAX_PWD_LENGTH + 1] ;
*/
 
int main( ) {
 
    SQLHANDLE henv;
    SQLHANDLE hdbc[MAX_CONNECTIONS] ;
 
/* ... */
 
    /* allocate an environment handle */
    SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &henv ) ;
 
    /* Connect to first data source */
    prompted_connect( henv, &hdbc[0] ) ;
 
    /* Connect to second data source */
    prompted_connect( henv, &hdbc[1] ) ;
 
    /*********   Start Processing Step  *************************/
    /* allocate statement handle, execute statement, etc.       */
    /*********   End Processing Step  ***************************/
 
    printf( "\nDisconnecting .....\n" ) ;
    SQLDisconnect( hdbc[0] ) ;  /* disconnect first connection */
    SQLDisconnect( hdbc[1] ) ;  /* disconnect second connection */
 
    /* free first connection handle */
    SQLFreeHandle( SQL_HANDLE_DBC, hdbc[0] ) ;
 
    /* free second connection handle */
    SQLFreeHandle( SQL_HANDLE_DBC, hdbc[1] ) ;
 
    /* free environment handle */
    SQLFreeHandle( SQL_HANDLE_ENV, henv ) ;
 
    return ( SQL_SUCCESS ) ;
 
}
 
/* prompted_connect - prompt for connect options and connect */
SQLRETURN prompted_connect( SQLHANDLE henv,
                            SQLHANDLE * hdbc
                          ) {
 
    SQLCHAR server[SQL_MAX_DSN_LENGTH + 1] ;
    SQLCHAR uid[MAX_UID_LENGTH + 1] ;
    SQLCHAR pwd[MAX_PWD_LENGTH + 1] ;
 
    /* allocate a connection handle     */
    if ( SQLAllocHandle( SQL_HANDLE_DBC,
                         henv,
                         hdbc
                       ) != SQL_SUCCESS ) {
        printf( ">---ERROR while allocating a connection handle-----\n" ) ;
        return( SQL_ERROR ) ;
    }
 
    /* Set AUTOCOMMIT OFF */
    if ( SQLSetConnectAttr( * hdbc,
                            SQL_ATTR_AUTOCOMMIT,
                            ( void * ) SQL_AUTOCOMMIT_OFF, SQL_NTS
                          ) != SQL_SUCCESS ) {
       printf( ">---ERROR while setting AUTOCOMMIT OFF ------------\n" ) ;
       return( SQL_ERROR ) ;
    }
 
    printf( ">Enter Server Name:\n" ) ;
    gets( ( char * ) server ) ;
    printf( ">Enter User Name:\n" ) ;
    gets( ( char * ) uid ) ;
    printf( ">Enter Password:\n" ) ;
    gets( ( char * ) pwd ) ;
 
    if ( SQLConnect( * hdbc,
                     server, SQL_NTS,
                     uid,    SQL_NTS,
                     pwd,    SQL_NTS
                   ) != SQL_SUCCESS ) {
        printf( ">--- ERROR while connecting to %s -------------\n",
                server
              ) ;
 
        SQLDisconnect( * hdbc ) ;
        SQLFreeHandle( SQL_HANDLE_DBC, * hdbc ) ;
        return( SQL_ERROR ) ;
    }
    else              /* Print Connection Information */
        printf( "Successful Connect to %s\n", server ) ;
 
    return( SQL_SUCCESS ) ;
 
}
 
 
 

Transaction Processing

The following figure shows the typical order of function calls in a DB2 CLI application. Not all functions or possible paths are shown.

Figure 3. Transaction Processing


Transaction Processing

Figure 3 shows the steps and the DB2 CLI functions in the transaction processing task. This task contains five steps:

Allocating Statement Handle(s)

SQLAllocHandle() is called with a HandleType of SQL_HANDLE_STMT to allocate a statement handle. A statement handle refers to the data object that is used to track the execution of a single SQL statement. This includes information such as statement attributes, SQL statement text, dynamic parameters, cursor information, bindings for dynamic arguments and columns, result values and status information (these are discussed later). Each statement handle is associated with a connection handle.

A statement handle must be allocated before a statement can be executed.

The maximum number of statement handles that may be allocated at any one time is limited by overall system resources (usually stack size). The maximum number of statement handles that may actually be used, however, is defined by DB2 CLI: 5500. An HY014 SQLSTATE will be returned on the call to SQLPrepare() or SQLExecDirect() if the application exceeds these limits.

Preparation and Execution

Once a statement handle has been allocated, there are two methods of specifying and executing SQL statements:

  1. Prepare then execute
    1. Call SQLPrepare() with an SQL statement as an argument.
    2. Call SQLBindParameter() if the SQL statement contains parameter markers.
    3. Call SQLExecute()

  2. Execute direct
    1. Call SQLBindParameter() if the SQL statement contains parameter markers.
    2. Call SQLExecDirect() with an SQL statement as an argument.

The first method splits the preparation of the statement from the execution. This method is used when:

The second method combines the prepare step and the execute step into one. This method is used when:

Note:SQLGetTypeInfo() and the schema (catalog) functions discussed in Chapter 3, Using Advanced Features, execute their own query statements, and generate a result set. Calling a schema function is equivalent to executing a query statement, the result set is then processed as if a query statement had been executed.

DB2 Universal Database version 5 or later has a global dynamic statement cache stored on the server. This cache is used to store the most popular access plans for prepared SQL statements. Before each statement is prepared, the server searches this cache to see if an access plan has already been created for this exact SQL statement (by this application or any other application or client). If so, the server does not need to generate a new access plan, but will use the one in the cache instead. There is now no need for the application to cache connections at the client unless connecting to a server that does not have a global dynamic statement cache (such as DB2 Common Server v2). For information on caching connections at the client see Caching Statement Handles on the Client in the Migration section.

Binding Parameters in SQL Statements 

Both of the execution methods described above allow the use of parameter markers in place of an expression (or host variable in embedded SQL) in an SQL statement.

Parameter markers are represented by the '?' character and indicate the position in the SQL statement where the contents of application variables are to be substituted when the statement is executed. The parameter markers are referenced sequentially, from left to right, starting at 1. SQLNumParams() can be used to determine the number of parameters in a statement.

When an application variable is associated with a parameter marker it is bound to the parameter marker. The application must bind an application variable to each parameter marker in the SQL statement before it executes that statement. Binding is carried out by calling the SQLBindParameter() function with a number of arguments to indicate, the numerical position of the parameter, the SQL type of the parameter, the data type of the variable, a pointer to the application variable, and length of the variable.

The bound application variable and its associated length are called deferred input arguments since only the pointers are passed when the parameter is bound; no data is read from the variable until the statement is executed. Deferred arguments allow the application to modify the contents of the bound parameter variables, and repeat the execution of the statement with the new values.

Information for each parameter remains in effect until overridden, or until the application unbinds the parameter or drops the statement handle. If the application executes the SQL statement repeatedly without changing the parameter binding, then DB2 CLI uses the same pointers to locate the data on each execution. The application can also change the parameter binding to a different set of deferred variables. The application must not de-allocate or discard variables used for deferred input fields between the time it binds the fields to parameter markers and the time DB2 CLI accesses them at execution time.

It is possible to bind the parameters to a variable of a different type from that required by the SQL statement. The application must indicate the C data type of the source, and the SQL type of the parameter marker, and DB2 CLI will convert the contents of the variable to match the SQL data type specified. For example, the SQL statement may require an integer value, but your application has a string representation of an integer. The string can be bound to the parameter, and DB2 CLI will convert the string to the corresponding integer value when you execute the statement.

By default, DB2 CLI does not verify the type of the parameter marker. If the application indicates an incorrect type for the parameter marker, it could cause either an extra conversion by the DBMS, or an error. Refer to Data Types and Data Conversion for more information about data conversion.

Information about the parameter markers can be accessed using descriptors. If you enable automatic population of the implementation parameter descriptor (IPD) then information about the parameter markers will be collected. The statement attribute SQL_ATTR_ENABLE_AUTO_IPD must be set to SQL_TRUE for this to work. See Using Descriptors for more information.

If the parameter marker is part of a predicate on a query and is associated with a User Defined Type, then the parameter marker must be cast to the built-in type in the predicate portion of the statement; otherwise, an error will occur. For an example, refer to User Defined Types in Predicates.

The global dynamic statement cache was introduced in an earlier section. The access plan will only be shared between statements if they are exactly the same. For SQL statements with parameter markers, the specific values that are bound to the parameters do not have to be the same, only the SQL statement itself.

For information on more advanced methods for binding application storage to parameter markers, refer to:

Processing Results

The next step after the statement has been executed depends on the type of SQL statement.

Processing Query (SELECT, VALUES) Statements 

If the statement is a query statement, the following steps are generally needed in order to retrieve each row of the result set:

  1. Establish (describe) the structure of the result set, number of columns, column types and lengths
  2. (Optionally) bind application variables to columns in order to receive the data
  3. Repeatedly fetch the next row of data, and receive it into the bound application variables
  4. (Optionally) retrieve columns that were not previously bound, by calling SQLGetData() after each successful fetch.

Step 1
The first step requires analyzing the executed or prepared statement. The application will need to query the number of columns, the type of each column, and perhaps the names of each column in the result set. This information can be obtained by calling SQLNumResultCols() and SQLDescribeCol() (or SQLColAttributes()) after preparing or after executing the statement.

Step 2
The second step allows the application to retrieve column data directly into an application variable on the next call to SQLFetch(). For each column to be retrieved, the application calls SQLBindCol() to bind an application variable to a column in the result set. The application may use the information obtained from Step 1 to determine the C data type of the application variable and to allocate the maximum storage the column value could occupy. Similar to variables bound to parameter markers using SQLBindParameter(), columns are bound to deferred arguments. This time the variables are deferred output arguments, as data is written to these storage locations when SQLFetch() is called.

If the application does not bind any columns, as in the case when it needs to retrieve columns of long data in pieces, it can use SQLGetData(). Both the SQLBindCol() and SQLGetData() techniques can be combined if some columns are bound and some are unbound. The application must not de-allocate or discard variables used for deferred output fields between the time it binds them to columns of the result set and the time DB2 CLI writes the data to these fields.

Step 3
The third step is to call SQLFetch() to fetch the first or next row of the result set. If any columns have been bound, the application variable will be updated. SQLFetchScroll() can also be used for added flexibility when moving through the result set, refer to Scrollable Cursors for more information. SQLFetchScroll() can also be used by the application to fetch multiple rows of the result set into an array. Refer to Retrieving a Result Set into an Array for more information.

If data conversion was indicated by the data types specified on the call to SQLBindCol(), the conversion will occur when SQLFetch() is called. Refer to Data Types and Data Conversion for an explanation.

Step 4 (Optional)
The last (optional) step, is to call SQLGetData() to retrieve any unbound columns. All columns can be retrieved this way, provided they were not bound. SQLGetData() can also be called repeatedly to retrieve large columns in smaller pieces, which cannot be done with bound columns.

Data conversion can also be indicated here, as in SQLBindCol(), by specifying the desired target C data type of the application variable. Refer to Data Types and Data Conversion for more information.

To unbind a particular column of the result set, use SQLBindCol() with a null pointer for the application variable argument (TargetValuePtr). To unbind all of the columns with one function call, use SQLFreeStmt() with an Option of SQL_UNBIND.

Applications will perform better if columns are bound, rather than having them retrieved as unbound columns using SQLGetData(). However, an application may be constrained in the amount of long data that it can retrieve and handle at one time. If this is a concern, then SQLGetData() may be the better choice. See Using Large Objects for additional techniques to handle long data.

For information on more advanced methods for binding application storage to result set columns, refer to:

Processing UPDATE, DELETE and INSERT Statements  If the statement is modifying data (UPDATE, DELETE or INSERT), no action is required, other than the normal check for diagnostic messages. In this case, SQLRowCount() can be used to obtain the number of rows affected by the SQL statement.

If the SQL statement is a Positioned UPDATE or DELETE, it will be necessary to use a cursor. A cursor is a moveable pointer to a row in the result table of an active query statement. (This query statement must contain the FOR UPDATE OF clause to ensure that the query is not opened as readonly.) In embedded SQL, cursors names are used to retrieve, update or delete rows. In DB2 CLI, a cursor name is needed only for Positioned UPDATE or DELETE SQL statements as they reference the cursor by name. Furthermore, a cursor name is automatically generated when SQLAllocHandle() is called with a HandleType of SQL_HANDLE_STMT.

To update a row that has been fetched, the application uses two statement handles, one for the fetch and one for the update. The application calls SQLGetCursorName() to obtain the cursor name. The application generates the text of a Positioned UPDATE or DELETE, including this cursor name, and executes that SQL statement using a second statement handle. The application cannot reuse the fetch statement handle to execute a Positioned UPDATE or DELETE as it is still in use. You can also define your own cursor name using SQLSetCursorName(), but it is best to use the generated name, since all error messages will reference the generated name, and not the one defined by SQLSetCursorName().

Processing Other Statements  If the statement neither queries nor modifies the data, then there is no further action other than the normal check for diagnostic messages.

Commit or Rollback

A transaction is a recoverable unit of work, or a group of SQL statements that can be treated as one atomic operation. This means that all the operations within the group are guaranteed to be completed (committed) or undone (rolled back), as if they were a single operation. A transaction can also be referred to as a Unit of Work or a Logical Unit of Work. When the transaction spans multiple connections, it is referred to as a Distributed Unit of Work.

DB2 CLI supports two commit modes:

auto-commit
In auto-commit mode, every SQL statement is a complete transaction, which is automatically committed. For a non-query statement, the commit is issued at the end statement execution. For a query statement, the commit is issued after the cursor has been closed. The application must not start a second query before the cursor of the first query has been closed.

manual-commit
In manual-commit mode, transactions are started implicitly with the first access to the database using SQLPrepare(), SQLExecDirect(), SQLGetTypeInfo(), or any function that returns a result set, such as those described in Querying System Catalog Information. At this point a transaction has begun, even if the call failed. The transaction ends when you use SQLEndTran() to either rollback or commit the transaction. This means that any statements executed (on the same connection) between these are treated as one transaction.

The default commit mode is auto-commit (except when participating in a coordinated transaction, see Multisite Updates (Two Phase Commit)). An application can switch between manual-commit and auto-commit modes by calling SQLSetConnectAttr(). Typically, a query-only application may wish to stay in auto-commit mode. Applications that need to perform updates to the database should turn off auto-commit as soon as the database connection has been established.

When multiple connections exist to the same or different databases, each connection has its own transaction. Special care must be taken to call SQLEndTran() with the correct connection handle to ensure that only the intended connection and related transaction is affected. It is also possible to rollback or commit all the connections by specifying a valid environment handle, and a NULL connection handle on the SQLEndTran() call. Unlike distributed unit of work connections (described in Multisite Updates (Two Phase Commit)), there is no coordination between the transactions on each connection.

When to Call SQLEndTran() 

If the application is in auto-commit mode, it never needs to call SQLEndTran(). A commit is issued implicitly at the end of each statement execution.

In manual-commit mode, SQLEndTran() must be called before calling SQLDisconnect(). If Distributed Unit of Work is involved, additional rules may apply, refer to Multisite Updates (Two Phase Commit) for details.

It is recommended that an application that performs updates should not wait until the disconnect before committing or rolling back the transaction. The other extreme is to operate in auto-commit mode, which is also not recommended as this adds extra processing. Refer to the Environment, Connection, and Statement Attributes and SQLSetConnectAttr - Set Connection Attributes for information about switching between auto-commit and manual-commit.

Consider the following when deciding where in the application to end a transaction:

Effects of calling SQLEndTran()   

When a transaction ends:

For more information and an example refer to SQLEndTran - End Transactions of a Connection.

Freeing Statement Handles

Call SQLFreeStmt() to end processing for a particular statement handle. This function can be used to do one or more of the following:

Call SQLFreeHandle() with a HandleType of SQL_HANDLE_STMT to:

The columns and parameters should always be unbound before using the handle to process a statement with a different number or type of parameters or a different result set; otherwise application programming errors may occur.

Diagnostics

Diagnostics refers to dealing with warning or error conditions generated within an application. There are two levels of diagnostics returned when calling DB2 CLI functions :

Each CLI function returns the function return code as a basic diagnostic. Both SQLGetDiagRec() and SQLGetDiagField() functions provide more detailed diagnostic information. The SQLGetSQLCA() function provides access to the SQLCA, if the diagnostic is reported by the data source. This arrangement lets applications handle the basic flow control based on Return Codes, and the SQLSTATES allow determination of the specific causes of failure and specific error handling.

Both SQLGetDiagRec() and SQLGetDiagField() return three pieces of information:

For the detailed function information and example usage, refer to SQLGetDiagRec - Get Multiple Fields Settings of Diagnostic Record and SQLGetDiagField - Get a Field of Diagnostic Data.

SQLGetSQLCA() returns the SQLCA for access to specific fields, but should never be used as a substitute for SQLGetDiagRec() or SQLGetDiagField().

Function Return Codes

The following table lists all possible return codes for DB2 CLI functions. Each function description in Chapter 5, DB2 CLI Functions lists the possible codes returned for each function.

Table 1. DB2 CLI Function Return Codes
Return Code Explanation
SQL_SUCCESS The function completed successfully, no additional SQLSTATE information is available.
SQL_SUCCESS_WITH_INFO The function completed successfully, with a warning or other information. Call SQLGetDiagRec() to receive the SQLSTATE and any other informational messages or warnings. The SQLSTATE will have a class of '01', see SQLState Cross Reference table.
SQL_STILL_EXECUTING The function is running asynchronously and has not yet completed. The DB2 CLI driver has returned control to the application after calling the function, but the function has not yet finished executing. See Asynchronous Execution of CLI for complete details.
SQL_NO_DATA_FOUND The function returned successfully, but no relevant data was found. When this is returned after the execution of an SQL statement, additional information may be available and can be obtained by calling SQLGetDiagRec().
SQL_NEED_DATA The application tried to execute an SQL statement but DB2 CLI lacks parameter data that the application had indicated would be passed at execute time. For more information, refer to Sending/Retrieving Long Data in Pieces.
SQL_ERROR The function failed. Call SQLGetDiagRec() to receive the SQLSTATE and any other error information.
SQL_INVALID_HANDLE The function failed due to an invalid input handle (environment, connection or statement handle). This is a programming error. No further information is available.

SQLSTATEs

SQLSTATEs are alphanumeric strings of 5 characters (bytes) with a format of ccsss, where cc indicates class and sss indicates subclass. Any SQLSTATE that has a class of:

Note:Previous versions of DB2 CLI returned SQLSTATEs with a class of 'S1' rather than 'HY'. To force the CLI driver to return 'S1' SQLSTATEs, the application should set the environment attribute SQL_ATTR_ODBC_VERSION to the value SQL_OV_ODBC2. See SQLSetEnvAttr - Set Environment Attribute and Appendix B, Migrating Applications for more information.

DB2 CLI SQLSTATEs include both additional IBM defined SQLSTATEs that are returned by the database server, and DB2 CLI defined SQLSTATEs for conditions that are not defined in the ODBC v3 and ISO SQL/CLI specification. This allows for the maximum amount of diagnostic information to be returned. When running applications in a ODBC environment, it is also possible to receive ODBC defined SQLSTATEs.

Follow these guidelines for using SQLSTATEs within your application:

Refer to SQLState Cross Reference table for a listing and description of the SQLSTATEs explicitly returned by DB2 CLI.

You can use the CLI/ODBC trace facility to gain a better understanding of how your application calls DB2, including any errors that may occur. Refer to Appendix K, Using the DB2 CLI/ODBC Trace Facility and the CLI/ODBC configuration keyword TRACE.

SQLCA

Embedded applications rely on the SQLCA for all diagnostic information. Although DB2 CLI applications can retrieve much of the same information by using SQLGetDiagRec(), there may still be a need for the application to access the SQLCA related to the processing of a statement. (For example, after preparing a statement, the SQLCA will contain the relative cost of executing the statement.) The SQLCA only contains meaningful information if there was an interaction with the data source on the previous request (for example: connect, prepare, execute, fetch, disconnect).

The SQLGetSQLCA() function is used to retrieve this structure. Refer to SQLGetSQLCA - Get SQLCA Data Structure for more information.

SQLGetSQLCA() should never be used as a substitute for SQLGetDiagRec() or SQLGetDiagField().

Data Types and Data Conversion

When writing a DB2 CLI application it is necessary to work with both SQL data types and C data types. This is unavoidable since the DBMS uses SQL data types, and the application must use C data types. This means the application must match C data types to SQL data types when transferring data between the DBMS and the application (when calling DB2 CLI functions).

To help address this, DB2 CLI provides symbolic names for the various data types, and manages the transfer of data between the DBMS and the application. It will also perform data conversion (from a C character string to an SQL INTEGER type, for example) if required. To accomplish this, DB2 CLI needs to know both the source and target data type. This requires the application to identify both data types using symbolic names.

C and SQL Data Types

Table 2 list each of the SQL data types, with its corresponding symbolic name, and the default C symbolic name.

SQL Data Type
This column contains the SQL data types as they would appear in an SQL CREATE DDL statement. The SQL data types are dependent on the DBMS.

Symbolic SQL Data Type
This column contains a SQL symbolic names that are defined (in sqlcli.h) as an integer value. These values are used by various functions to identify the SQL data types listed in the first column. Refer to Example for an example using these values.

Default C Symbolic Data Type
This column contains C symbolic names, also defined as an integer values. These values are used in various functions arguments to identify the C data type as shown in Table 3. The symbolic names are used by various functions, (such as SQLBindParameter(), SQLGetData(), SQLBindCol(), etc.) to indicate the C data types of the application variables. Instead of explicitly identifying the C data type when calling these functions, SQL_C_DEFAULT can be specified instead, and DB2 CLI will assume a default C data type based on the SQL data type of the parameter or column as shown by this table. For example, the default C data type of SQL_DECIMAL is SQL_C_CHAR.


Table 2. SQL Symbolic and Default Data Types
SQL Data Type Symbolic SQL Data Type Default Symbolic C Data Type
BIGINT SQL_BIGINT SQL_C_BIGINT
BLOB SQL_BLOB SQL_C_BINARY
BLOB LOCATOR a SQL_BLOB_LOCATOR SQL_C_BLOB_LOCATOR
CHAR SQL_CHAR SQL_C_CHAR
CHAR FOR BIT DATA b SQL_BINARY SQL_C_BINARY
CLOB SQL_CLOB SQL_C_CHAR
CLOB LOCATOR a SQL_CLOB_LOCATOR SQL_C_CLOB_LOCATOR
DATE SQL_TYPE_DATE d SQL_C__TYPE_DATE d
DBCLOB SQL_DBCLOB SQL_C_DBCHAR
DBCLOB LOCATOR a SQL_DBCLOB_LOCATOR SQL_C_DBCLOB_LOCATOR
DECIMAL SQL_DECIMAL SQL_C_CHAR
DOUBLE SQL_DOUBLE SQL_C_DOUBLE
FLOAT SQL_FLOAT SQL_C_DOUBLE
GRAPHIC SQL_GRAPHIC SQL_C_DBCHAR
INTEGER SQL_INTEGER SQL_C_LONG
LONG VARCHAR b SQL_LONGVARCHAR SQL_C_CHAR
LONG VARCHAR FOR BIT DATA b SQL_LONGVARBINARY SQL_C_BINARY
LONG VARGRAPHIC b SQL_LONGVARGRAPHIC SQL_C_DBCHAR
NUMERIC c SQL_NUMERIC c SQL_C_CHAR
REAL SQL_REAL SQL_C_FLOAT
SMALLINT SQL_SMALLINT SQL_C_SHORT
TIME SQL_TYPE_TIME d SQL_C_TYPE_TIME d
TIMESTAMP SQL_TYPE_TIMESTAMP d SQL_C_TYPE_TIMESTAMP d
VARCHAR SQL_VARCHAR SQL_C_CHAR
VARCHAR FOR BIT DATA b SQL_VARBINARY SQL_C_BINARY
VARGRAPHIC SQL_VARGRAPHIC SQL_C_DBCHAR

a LOB locator types are not persistent SQL data types, (columns can not be defined with a locator type, they are only used to describe parameter markers, or to represent a LOB value), refer to Using Large Objects
b LONG data types and FOR BIT DATA data types should be replaced by an appropriate LOB types whenever possible.
c NUMERIC is a synonym for DECIMAL on DB2 for MVS/ESA, DB2 for VSE & VM and DB2 Universal Database.
d See Appendix B, Migrating Applications for information on what data type was used in previous releases.

Note:The data types, DATE, DECIMAL, NUMERIC, TIME, and TIMESTAMP cannot be transferred to their default C buffer types without a conversion.

Table 3 shows the generic type definitions for each symbolic C type.

C Symbolic Data Type
This column contains C symbolic names, defined as integer values. These values are used in various functions arguments to identify the C data type shown in the last column. Refer to Example for an example using these values.

C Type
This column contains C defined types, defined in sqlcli.h using a C typedef statement. The values in this column should be used to declare all DB2 CLI related variables and arguments, in order to make the application more portable. Refer to Table 5 for a list of additional symbolic data types used for function arguments.

Base C type
This column is shown for reference only, all variables and arguments should be defined using the symbolic types in the previous column. Some of the values are C structures that are described in Table 4.


Table 3. C Data Types
C Symbolic Data Type C Type Base C type
SQL_C_CHAR SQLCHAR unsigned char
SQL_C_BIT SQLCHAR unsigned char or char (Value 1 or 0)
SQL_C_TINYINT SQLSCHAR signed char (Range -128 to 127)
SQL_C_SHORT SQLSMALLINT short int
SQL_C_LONG SQLINTEGER long int
SQL_C_DOUBLE SQLDOUBLE double
SQL_C_FLOAT SQLREAL float
SQL_C_SBIGINT SQLBIGINT _int64
SQL_C_UBIGINT SQLBIGINT unsigned _int64
SQL_C_NUMERIC c SQL_NUMERIC_STRUCT see Table 4
SQL_C_TYPE_DATE b DATE_STRUCT see Table 4
SQL_C_TYPE_TIME b TIME_STRUCT see Table 4
SQL_C_TYPE_TIMESTAMP b TIMESTAMP_STRUCT see Table 4
SQL_C_CLOB_LOCATOR a SQLINTEGER long int
SQL_C_BINARY SQLCHAR unsigned char
SQL_C_BLOB_LOCATOR a SQLINTEGER long int
SQL_C_DBCHAR SQLDBCHAR wchar_t
SQL_C_DBCLOB_LOCATOR SQLINTEGER long int
a LOB Locator Types.
b See Appendix B, Migrating Applications for information on what data type was used in previous releases.
c 32-bit Windows only.

Note:fcSQL file reference data types (used in embedded SQL) are not needed in DB2 CLI, refer to Using Large Objects


Table 4. C Structures
C Type Generic Structure Windows Structure
DATE_STRUCT
 
typedef struct DATE_STRUCT
  {
    SQLSMALLINT   year;
    SQLUSMALLINT   month;
    SQLUSMALLINT   day;
  } DATE_STRUCT;

 
typedef struct tagDATE_STRUCT
  {
    SWORD   year;
    UWORD   month;
    UWORD   day;
  } DATE_STRUCT;

TIME_STRUCT
 
typedef struct TIME_STRUCT
  {
    SQLUSMALLINT   hour;
    SQLUSMALLINT   minute;
    SQLUSMALLINT   second;
  } TIME_STRUCT;

 
typedef struct tagTIME_STRUCT
  {
    UWORD   hour;
    UWORD   minutes;
    UWORD   second;
  } TIME_STRUCT;

TIMESTAMP_STRUCT
 
typedef struct TIMESTAMP_STRUCT
  {
    SQLUSMALLINT   year;
    SQLUSMALLINT   month;
    SQLUSMALLINT   day;
    SQLUSMALLINT   hour;
    SQLUSMALLINT   minute;
    SQLUSMALLINT   second;
    SQLINTEGER    fraction;
  } TIMESTAMP_STRUCT;

 
typedef struct tagTIMESTAMP_STRUCT
  {
    SWORD   year;
    UWORD   month;
    UWORD   day;
    UWORD   hour;
    UWORD   minute;
    UWORD   second;
    UDWORD  fraction;
  } TIMESTAMP_STRUCT;

SQL_NUMERIC_STRUCT (None. Windows 32-bit only)
 
typedef struct tagSQL_NUMERIC_STRUCT
  {
    SQLCHAR   precision;
    SQLCHAR   scale;
    SQLCHAR   sign; a
    SQLCHAR   
        val[SQL_MAX_NUMERIC_LEN];b c
  } SQL_NUMERIC_STRUCT;

Refer to Table 5 for more information on the SQLUSMALLINT C data type.

a Sign field: 1 = positive, 2 = negative
b A number is stored in the val field of the SQL_NUMERIC_STRUCT structure as a scaled integer, in little endian mode (the leftmost byte being the least-significant byte). For example, the number 10.001 base 10, with a scale of 4, is scaled to an integer of 100010. Because this is 186AA in hexadecimal format, the value in SQL_NUMERIC_STRUCT would be "AA 86 01 00 00 ... 00", with the number of bytes defined by the SQL_MAX_NUMERIC_LEN #define.
c The precision and scale fields of the SQL_C_NUMERIC data type are never used for input from an application, only for output from the driver to the application. When the driver writes a numeric value into the SQL_NUMERIC_STRUCT, it will use its own default as the value for the precision field, and it will use the value in the SQL_DESC_SCALE field of the application descriptor (which defaults to 0) for the scale field. An application can provide its own values for precision and scale by setting the SQL_DESC_PRECISION and SQL_DESC_SCALE fields of the application descriptor.

Other C Data Types

As well as the data types that map to SQL data types, there are also C symbolic types used for other function arguments, such as pointers and handles. Both the generic and ODBC data types are shown below.

Table 5. C Data Types and Base C Data Types
Defined C Type Base C Type Typical Usage
SQLPOINTER void * Pointers to storage for data and parameters.
SQLHANDLE long int Handle used to reference all 4 types of handle information.
SQLHENV long int Handle referencing environment information.
SQLHDBC long int Handle referencing database connection information.
SQLHSTMT long int Handle referencing statement information.
SQLUSMALLINT unsigned short int Function input argument for unsigned short integer values.
SQLUINTEGER unsigned long int Function input argument for unsigned long integer values.
SQLRETURN short int Return code from DB2 CLI functions.

Versions of DB2 CLI prior to Version 2.1:

  • Defined SQLRETURN as a long (32-bit) integer.
  • Used SQLSMALLINT and SQLINTEGER instead of SQLUSMALLINT and SQLUINTEGER (signed instead of unsigned). Refer to Appendix B, Migrating Applications for more information.

Data Conversion

As mentioned previously, DB2 CLI manages the transfer and any required conversion of data between the application and the DBMS. Before the data transfer actually takes place, the source, target or both data types are indicated when calling SQLBindParameter(), SQLBindCol() or SQLGetData(). These functions use the symbolic type names shown in Table 2, to identify the data types involved.

For example, to bind a parameter marker that corresponds to an SQL data type of DECIMAL(5,3), to an application's C buffer type of double, the appropriate SQLBindParameter() call would look like:

     SQLBindParameter (hstmt, 1, SQL_PARAM_INPUT, SQL_C_DOUBLE,
                       SQL_DECIMAL, 5, 3, double_ptr, 0, NULL);

Table 2 shows only the default data conversions. The functions mentioned in the previous paragraph can be used to convert data to other types, but not all data conversions are supported or make sense. Table 6 shows all the conversions supported by DB2 CLI.

The first column in Table 6 contains the data type of the SQL data type. The remaining columns represent the C data types. If the C data type columns contains:

D
The conversion is supported and is the default conversion for the SQL data type.
X
all IBM DBMSs support the conversion,
blank
no IBM DBMS supports the conversion.

As an example, the table indicates that a CHAR (or a C character string as indicated in Table 6) can be converted into a SQL_C_LONG (a signed long). In contrast, a LONGVARCHAR cannot be converted to a SQL_C_LONG.

Refer to Appendix F, Data Conversion for information about the required formats and the results of converting between data types.

There are rules specified in the SQL Reference for limits on precision and scale, as well as truncation and rounding rules for type conversions. These rules apply in DB2 CLI, with the following exception: truncation of values to the right of the decimal point for numeric values may return a truncation warning, whereas truncation to the left of the decimal point returns an error. In cases of error, the application should call SQLGetDiagRec() to obtain the SQLSTATE and additional information on the failure. When moving and converting floating point data values between the application and DB2 CLI, no correspondence is guaranteed to be exact as the values may change in precision and scale.

Table 6. Supported Data Conversions

SQL Data Type


S
Q
L
_
C
_
C
H
A
R


S
Q
L
_
C
_
L
O
N
G


S
Q
L
_
C
_
S
H
O
R
T


S
Q
L
_
C
_
T
I
N
Y
I
N
T



S
Q
L
_
C
_
F
L
O
A
T


S
Q
L
_
C
_
D
O
U
B
L
E


S
Q
L
_
C
_
T
Y
P
E
_
D
A
T
E


S
Q
L
_
C
_
T
Y
P
E
_
T
I
M
E


S
Q
L
_
C
_
T
Y
P
E
_
T
I
M
E
S
T
A
M
P


S
Q
L
_
C
_
B
I
N
A
R
Y


S
Q
L
_
C
_
B
I
T


S
Q
L
_
C
_
D
B
C
H
A
R


S
Q
L
_
C
_
C
L
O
B
_
L
O
C
A
T
O
R


S
Q
L
_
C
_
B
L
O
B
_
L
O
C
A
T
O
R


S
Q
L
_
C
_
D
B
C
L
O
B
_
L
O
C
A
T
O
R


S
Q
L
_
C
_
B
I
G
I
N
T


S
Q
L
_
C
_
N
U
M
E
R
I
C


BLOB


X


























D











X








CHAR


D


X


X


X


X


X


X


X


X


X


X













X


X


CLOB


D


























X








X











DATE


X

















D





X























DBCLOB





























X





D








X






DECIMAL


D


X


X


X


X


X











X


X













X


X


DOUBLE


X


X


X


X


X


D














X













X


X


FLOAT


X


X


X


X


X


D














X













X


X


GRAPHIC


X
































D














INTEGER


X


D


X


X


X


X














X













X


X


LONG
VARCHAR


D


























X




















LONG
VARGRAPHIC


X


























X





D














NUMERIC


D


X


X


X


X


X














X















X


REAL


X


X


X


X


D


X














X















X


SMALLINT


X


X


D


X


X


X














X













X


X


BIGINT


X


X


X


X


X


X











X


X













D


X


TIME


X




















D


X























TIMESTAMP


X

















X


X


D























VARCHAR


D


X


X


X


X


X


X


X


X


X


X













X


X


VARGRAPHIC


X
































D













Note:

  • Data is not converted to LOB Locator types, rather locators represent a data value, refer to Using Large Objects for more information.

  • REAL is not supported by DB2 Universal Database.

  • NUMERIC is a synonym for DECIMAL on DB2 for MVS/ESA, DB2 for VSE & VM, and DB2 Universal Database.

  • SQL_C_NUMERIC is only available on 32-bit Windows operating systems.

Working with String Arguments

The following conventions deal with the various aspects of working with string arguments in DB2 CLI functions.

Length of String Arguments

Input string arguments have an associated length argument. This argument indicates either the exact length of the argument (not including the null terminator), the special value SQL_NTS to indicate a null-terminated string, or SQL_NULL_DATA to pass a NULL value. If the length is set to SQL_NTS, DB2 CLI will determine the length of the string by locating the null terminator.

Output string arguments have two associated length arguments: an input length argument to specify the length of the allocated output buffer, and an output length argument to return the actual length of the string returned by DB2 CLI. The returned length value is the total length of the string available for return, regardless of whether it fits in the buffer or not.

For SQL column data, if the output is a null value, SQL_NULL_DATA is returned in the length argument and the output buffer is untouched. The descriptor field SQL_DESC_INDICATOR_PTR is set to SQL_NULL_DATA if the column value is a null value. For more information, including which other fields are set, see SQL_DESC_INDICATOR_PTR in SQLSetDescField().

If a function is called with a null pointer for an output length argument, DB2 CLI will not return a length, and assumes that the data buffer is large enough to hold the data. When the output data is a NULL value, DB2 CLI can not indicate that the value is NULL. If it is possible that a column in a result set can contain a NULL value, a valid pointer to the output length argument must always be provided. It is highly recommended that a valid output length argument always be used.

Null-Termination of Strings

By default, every character string that DB2 CLI returns is terminated with a null terminator (hex 00), except for strings returned from graphic and DBCLOB data types into SQL_C_CHAR application variables. Graphic and DBCLOB data types that are retrieved into SQL_C_DBCHAR application variables are null terminated with a double byte null terminator. This requires that all buffers allocate enough space for the maximum number of bytes expected, plus the null-terminator.

It is also possible to use SQLSetEnvAttr() and set an environment attribute to disable null termination of variable length output (character string) data. In this case, the application allocates a buffer exactly as long as the longest string it expects. The application must provide a valid pointer to storage for the output length argument so that DB2 CLI can indicate the actual length of data returned; otherwise, the application will not have any means to determine this. The DB2 CLI default is to always write the null terminator.

It is possible, using the PATCH1 CLI/ODBC configuration keyword, to force DB2 CLI to null terminate graphic and DBCLOB strings. This keyword can be set from the CLI/ODBC Settings notebook accessible from the Client Configuration Assistant (CCA). Refer to the Platform Specific Details for CLI/ODBC Access. The Configure the CLI/ODBC Driver section for your platform will provide the steps required to set the keywords. The description of PATCH1 in Configuration Keywords includes how to find the setting required to force the null termination of graphic and DBCLOB strings.

String Truncation

If an output string does not fit into a buffer, DB2 CLI will truncate the string to the size of the buffer, and write the null terminator. If truncation occurs, the function will return SQL_SUCCESS_WITH_INFO and an SQLSTATE of 01004 indicating truncation. The application can then compare the buffer length to the output length to determine which string was truncated.

For example, if SQLFetch() returns SQL_SUCCESS_WITH_INFO, and an SQLSTATE of 01004, at least one of the buffers bound to a column is too small to hold the data. For each buffer that is bound to a column, the application can compare the buffer length with the output length and determine which column was truncated.

Interpretation of Strings

Normally, DB2 CLI interprets string arguments in a case-sensitive manner and does not trim any spaces from the values. The one exception is the cursor name input argument on the SQLSetCursorName() function, where if the cursor name is not delimited (enclosed by double quotes) the leading and trailing blanks are removed and case is ignored.

Querying Environment and Data Source Information

There are many situations where an application requires information about the characteristics and capabilities of the current DB2 CLI driver or the data source that it is connected to. DB2 CLI provides a number of functions that return this information.

There are two common situations where the application requires this information:

The following DB2 CLI functions provide data source specific information:

Querying Environment Information Example

The getinfo.c sample, shown in Example generates the following output when connected to DB2.

       Server Name: SAMPLE
     Database Name: SAMPLE
     Instance Name: db2inst1
         DBMS Name: DB2/6000
      DBMS Version: 05.00.0000
    CLI Driver Name: libdb2.a
 CLI Driver Version: 05.00.0000
 ODBC SQL Conformance Level: Extended Grammar


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

[ DB2 List of Books | Search the DB2 Books ]