ODBC applications perform almost all database access by executing SQL statements. The general sequence of events in this step is to allocate a statement handle and set any statement attributes.
In some cases, an application may want to probe the driver to discover its capabilities. This can be done by calling subroutines f90SQLGetInfo and f90SQLGetFunctions.
To allocate a statement handle, an application calls f90SQLAllocHandle with the option SQL_HANDLE_STMT. The following is an example of a call to f90SQLAllocHandle, in which a statement is allocated under the context of the connection ConnHndl. The handle (address) for the statement space is stored in variable StmtHndl:
|
Once a statement has been allocated, some of its attributes can also be set. Attributes are characteristics of the statement. For example, whether to use bookmarks and what kind of cursor to use with the statements result set are statement attributes.
Statement attributes are set with f90SQLSetStmtAttr and their current settings retrieved with f90SQLGetStmtAttr. There is no requirement that an application must set any statement attributes. All statement attributes have defaults, some of which are driver-specific.
When a statement attribute can be set depends on the attribute itself. The SQL_ATTR_CONCURRENCY, SQL_ATTR_CURSOR_TYPE, SQL_ATTR_SIMULATE_CURSOR, and SQL_ATTR_USE_BOOKMARKS statement attributes must be set before the statement is executed. The SQL_ATTR_ASYNC_ENABLE and SQL_ATTR_NOSCAN statement attributes can be set at any time, but are not applied until the statement is used again. SQL_ATTR_MAX_LENGTH, SQL_ATTR_MAX_ROWS, and SQL_ATTR_QUERY_TIMEOUT statement attributes can be set at any time, but it is driver-specific whether they are applied before the statement is used again. The remaining statement attributes can be set at any time.
Most statement attributes introduced in ODBC 3.5 (except for SQL_ATTR_METADATA_ID) can also be set at the connection level.
The next example, shows how to use f90SQLGetInfo to probe the driver for a feature support. We want to obtain a list of publishers and their cities, ordered by state. But we do not want the state to be part of the output. Some DBMSs support the use of the SQL ORDER BY clause (to order a record set) using a column that is not a part of the SELECT statement. Others do not support this feature.
If the driver supports the feature, then we prepare the statement
SELECT Name, City
FROM Publishers
WHERE State='NY' OR State='CA' OR STATE='MA'
ORDER BY State
If the driver does not support the feature, then we use the following SQL statement instead:
SELECT Name, City, State
FROM Publishers
WHERE State='NY' OR State='CA' OR STATE='MA'
ORDER BY State
Note that the second statement will also return the state as a column in the recordset. We do not want this column, so we only bind columns Name and City to variables in the application. Binding a column simply means that we assign an application variable, which act as a buffer, to receive the value of that column in the resulting recordset. To bind a column, an application uses subroutine f90SQLBindCol. A more detailed explanation of this subroutine is given later in this chapter (see section Binding Resultset Columns). In the mean time, the next explanation should allow you to follow the program in example 5.2.
A typical call to f90SQLBindCol takes this form:
| call f90SQLBindCol | (StmtHandle, ColumnNumber, TargetType, TargetVar, StrLenIndPtr, iRet) |
where StmtHandle is a statement handle, ColumnNumber is an integer*2 argument indicating the column number of the result set that will be bound to the variable passed in TargetVar. TargetType is the type of variable TargetVar. f90SQL defines constants that identify the different types. For example, constant SQL_F_CHAR tells f90SQLBindCol that variable TargetVar is a character variable. Argument StrLenIndPtr is a pointer to an integer variable. This variable will contain the length of the data stored in variable TargetVar when the rows of the recordset are fetched. In Fortran, to pass a pointer you use the function loc(var). If your are not interested in this value, you can pass a null pointer (a 0 or the constant f90SQL_NULL_PTR).
Example 5.2 also illustrates how to allocate a statement handle and some of the steps presented in the flowchart of Figure 5.1.
|