Buffers are one of the most important components in the interaction between your application and the ODBC API. A buffer is any portion of application memory used to transfer data between the application and the driver. In the previous example, we saw how a buffer can be associated (bound) to a column in a result set using f90SQLBindCol. This type of buffer is called output buffer. Output buffers receive data from the driver and make it available to the application. Input buffers, on the other hand, are used to transfer data from the application to the driver.
Many ODBC buffers are paired. One buffer is used to transfer the data (data buffer), while another buffer is used to indicate the size of the data stored in the data buffer. In some cases, this second buffer gives additional information about the nature of the data. This buffer is called the length/indicator buffer. It is important not to confuse the length of the data in a buffer with the length of the buffer itself. The next figure clarifies these concepts.
Figure 4.1. Schematic representation of ODBC buffers

The length of a buffer and the size of the data it contains are always indicated in bytes, as opposed to characters. This distinction is unimportant for programs that use ANSI strings because lengths in bytes and characters are the same.
A length/indicator buffer is required any time the data buffer contains variable-length data, such as character strings or binary data. If the data buffer contains fixed-length data like an integer or date structure, a length/indicator buffer is only needed to pass indicator values, since the length of the data is already known. If an application uses a length/indicator buffer with fixed-length data, the driver ignores any lengths passed in it.
f90SQL has overloaded most ODBC functions that receive/return character string buffers, so Fortran programmers do not need to indicate the length of the data they contain.
The ODBC-API functions do not pass or receive the data in a buffer directly. Instead, the API passes and receives a pointer to the address where the buffer resides. This is very convenient in languages like C, which have colorful capabilities to handle pointers. However, it may present a real problem in Fortran, which offers pointers in a more restricted format. f90SQL will allow you to pass a variable name instead of a pointer. In most cases, this makes it easier for your Fortran program to deal with buffers. f90SQL will also allow you to pass a pointer to the buffer, if you desired to do so, by using Pointer-Format calls (see Appendix 2).
Some buffers are not used immediately when you pass them to an ODBC-API function. These buffers are called deferred buffers. For example, in the previous section, when you called the subroutine f90SQLBindCol and passed the variable AuthorsStr, ODBC did not put information in that buffer immediately. Instead, it stored the address of the variable so that the buffer could be used later when fetching records from the result set (by calling the subroutine f90SQLFetch). This case represents a deferred output buffer. ODBC also makes use of deferred input buffers, in which the application passes a buffer that contains data that will be used later by the driver.
A common error when programming the ODBC-API is to pass buffers which permanence cannot be ensured when the driver needs the buffer. The following code is an example of such a mistake:
|
You should notice that the buffer AutStr only exists in the context of the subroutine BindAColumn. As soon as the program leaves the subroutine, the variable AutStr is not defined anymore. When the main program fetches records from the result set, the ODBC driver will attempt to return data to AutStr, which by now has disappeared. The results of this action are unpredictable, usually resulting in a crashed application. Neither ODBC nor f90SQL will be able to detect this programmatic error. As a programmer you have the responsibility to ensure that deferred buffers will be available to ODBC when required. The best way to do so is to make sure the variables that will act as buffers are defined in the same program unit which fetches the records.
The following table summarizes the uses of deferred buffers. Note that deferred buffers bound to resultset columns are specified with f90SQLBindCol, and deferred buffers bound to SQL statement parameters are specified with f90SQLBindParameter.
Table 4.1. Deferred buffers and the subroutines that use them.
| Buffer use | Type | Specified with | Used by |
| Sending data for input parameters | Deferred input | f90SQLBindParameter | f90SQLExecutef90SQLExecDirect |
| Sending data to update or insert a row in a result set | Deferred input | f90SQLBindCol | f90SQLSetPos |
| Returning data for output and input/output parameters | Deferred output | f90SQLBindParameter | f90SQLExecutef90SQLExecDirect |
| Returning result set data | Deferred output | f90SQLBindCol | f90SQLFetchf90SQLFetchScroll f90SQLSetPos |