SQLFetch

Conformance

Version Introduced:ODBC 1.0
Standards Compliance:ISO 92

Summary

SQLFetch fetches the next rowset of data from the result set and returns data for all bound columns.

Syntax

SQLRETURN SQLFetch(
SQLHSTMTStatementHandle);

Arguments

StatementHandle

[Input]
Statement handle.

Returns

SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_STILL_EXECUTING, SQL_ERROR, or SQL_INVALID_HANDLE.

Diagnostics

When SQLFetch returns either SQL_ERROR or SQL_SUCCESS_WITH_INFO, an associated SQLSTATE value can be obtained by calling SQLGetDiagRec with a HandleType of SQL_HANDLE_STMT and a Handle of StatementHandle. The following table lists the SQLSTATE values commonly returned by SQLFetch and explains each one in the context of this function; the notation “(DM)” precedes the descriptions of SQLSTATEs returned by the Driver Manager. The return code associated with each SQLSTATE value is SQL_ERROR, unless noted otherwise. If an error occurs on a single column, SQLGetDiagField can be called with a DiagIdentifier of SQL_DIAG_COLUMN_NUMBER to determine the column the error occurred on; and SQLGetDiagField can be called with a DiagIdentifier of SQL_DIAG_ROW_NUMBER to determine the row containing that column.

For all those SQLSTATEs that can return SQL_SUCCESS_WITH_INFO or SQL_ERROR (except 01xxx SQLSTATEs), SQL_SUCCESS_WITH_INFO is returned if an error occurs on one or more, but not all, rows of a multirow operation, and SQL_ERROR is returned if an error occurs on a single-row operation.

SQLSTATE Error Description
01000 General warning Driver-specific informational message. (Function returns SQL_SUCCESS_WITH_INFO.)
01004 String data, right truncated String or binary data returned for a column resulted in the truncation of non-blank character or non-NULL binary data. If it was a string value, it was right truncated.
01S01 Error in row An error occurred while fetching one or more rows.

(If this SQLSTATE is returned when an ODBC 3.x application is working with an ODBC 2.x driver, it can be ignored.)

01S07 Fractional truncation The data returned for a column was truncated. For numeric data types, the fractional part of the number was truncated. For time, timestamp, and interval data types containing a time component, the fractional portion of the time was truncated.

(Function returns SQL_SUCCESS_WITH_INFO.)

07006 Restricted data type attribute violation The data value of a column in the result set could not be converted to the data type specified by TargetType in SQLBindCol.

Column 0 was bound with a data type of SQL_C_BOOKMARK and the SQL_ATTR_USE_BOOKMARKS statement attribute was set to SQL_UB_VARIABLE.

Column 0 was bound with a data type of SQL_C_VARBOOKMARK and the SQL_ATTR_USE_BOOKMARKS statement attribute was not set to SQL_UB_VARIABLE.

07009 Invalid descriptor index The driver was an ODBC 2.x driver that does not support SQLExtendedFetch, and a column number specified in the binding for a column was 0.

Column 0 was bound and the SQL_ATTR_USE_BOOKMARKS statement attribute was set to SQL_UB_OFF.

08S01 Communication link failure The communication link between the driver and the data source to which the driver was connected failed before the function completed processing.
22001 String data, right truncated A variable-length bookmark returned for a column was truncated.
22002 Indicator variable required but not supplied NULL data was fetched into a column whose StrLen_or_IndPtr set by SQLBindCol (or SQL_DESC_INDICATOR_PTR set by SQLSetDescField or SQLSetDescRec) was a null pointer.
22003 Numeric value out of range Returning the numeric value (as numeric or string) for one or more bound columns would have caused the whole (as opposed to fractional) part of the number to be truncated.

For more information, see “Converting Data from SQL to C Data Types” in Appendix D, “Data Types.”

22007 Invalid datetime format A character column in the result set was bound to a date, time, or timestamp C structure, and a value in the column was, respectively, an invalid date, time, or timestamp.
22012 Division by zero A value from an arithmetic expression was returned, which resulted in division by zero.
22015 Interval field overflow Assigning from an exact numeric or interval SQL type to an interval C type caused a loss of significant digits in the leading field.

When fetching data to an interval C type, there was no representation of the value of the SQL type in the interval C type.

22018 Invalid character value for cast specification A character column in the result set was bound to a character C buffer, and the column contained a character for which there was no representation in the character set of the buffer.

The C type was an exact or approximate numeric, a datetime, or an interval data type; the SQL type of the column was a character data type; and the value in the column was not a valid literal of the bound C type.

24000 Invalid cursor state The StatementHandle was in an executed state but no result set was associated with the StatementHandle.
40001 Serialization failure The transaction in which the fetch was executed was terminated to prevent deadlock.
40003 Statement completion unknown The associated connection failed during the execution of this function and the state of the transaction cannot be determined.
HY000 General error An error occurred for which there was no specific SQLSTATE and for which no implementation-specific SQLSTATE was defined. The error message returned by SQLGetDiagRec in the *MessageText buffer describes the error and its cause.
HY001 Memory allocation
error
The driver was unable to allocate memory required to support execution or completion of the function.
HY008 Operation canceled Asynchronous processing was enabled for the StatementHandle. The function was called and, before it completed execution, SQLCancel was called on the StatementHandle. Then the function was called again on the StatementHandle.

The function was called and, before it completed execution, SQLCancel was called on the StatementHandle from a different thread in a multithread application.

HY010 Function sequence error (DM) The specified StatementHandle was not in an executed state. The function was called without first calling SQLExecDirect, SQLExecute, or a catalog function.

(DM) An asynchronously executing function (not this one) was called for the StatementHandle and was still executing when this function was called.

(DM) SQLExecute, SQLExecDirect, SQLBulkOperations, or SQLSetPos was called for the StatementHandle and returned SQL_NEED_DATA. This function was called before data was sent for all data-at-execution parameters or columns.

(DM) SQLFetch was called for the StatementHandle after SQLExtendedFetch was called and before SQLFreeStmt with the SQL_CLOSE option was called.

HY013 Memory management error The function call could not be processed because the underlying memory objects could not be accessed, possibly because of low memory conditions.
HY090 Invalid string or buffer length The SQL_ATTR_USE_BOOKMARK statement attribute was set to SQL_UB_VARIABLE, and column 0 was bound to a buffer whose length was not equal to the maximum length for the bookmark for this result set. (This length is available in the SQL_DESC_OCTET_LENGTH field of the IRD, and can be obtained by calling SQLDescribeCol, SQLColAttribute, or SQLGetDescField.)
HY107 Row value out of range The value specified with the SQL_ATTR_CURSOR_TYPE statement attribute was SQL_CURSOR_KEYSET_DRIVEN, but the value specified with the SQL_ATTR_KEYSET_SIZE statement attribute was greater than 0 and less than the value specified with the SQL_ATTR_ROW_ARRAY_SIZE statement attribute.
HYC00 Optional feature not implemented The driver or data source does not support the conversion specified by the combination of the TargetType in SQLBindCol and the SQL data type of the corresponding column.
HYT01 Connection timeout expired The connection timeout period expired before the data source responded to the request. The connection timeout period is set through SQLSetConnectAttr, SQL_ATTR_CONNECTION_TIMEOUT.
IM001 Driver does not support this function (DM) The driver associated with the StatementHandle does not support the function.

Comments

SQLFetch returns the next rowset in the result set. It can be called only while a result set exists — that is, after a call that creates a result set and before the cursor over that result set is closed. If any columns are bound, it returns the data in those columns. If the application has specified a pointer to a row status array or a buffer in which to return the number of rows fetched, SQLFetch returns this information as well. Calls to SQLFetch can be mixed with calls to SQLFetchScroll but cannot be mixed with calls to SQLExtendedFetch. For more information, see “Fetching a Row of Data” in Chapter 10, “Retrieving Results (Basic).”

If an ODBC 3.x application works with an ODBC 2.x driver, the Driver Manager maps SQLFetch calls to SQLExtendedFetch for an ODBC 2.x driver that supports SQLExtendedFetch. If the ODBC 2.x driver does not support SQLExtendedFetch, the Driver Manager maps SQLFetch calls to SQLFetch in the ODBC 2.x driver, which can only fetch a single row.

For more information, see “Block Cursors, Scrollable Cursors, and Backward Compatibility” in Appendix G, “Driver Guidelines for Backward Compatibility.”

Positioning the Cursor

When the result set is created, the cursor is positioned before the start of the result set. SQLFetch fetches the next rowset. It is equivalent to calling SQLFetchScroll with FetchOrientation set to SQL_FETCH_NEXT. For more information about cursors, see “Cursors” in Chapter 10, “Retrieving Results (Basic)” and “Block Cursors” in Chapter 11, “Retrieving Results (Advanced).”

The SQL_ATTR_ROW_ARRAY_SIZE statement attribute specifies the number of rows in the rowset. If the rowset being fetched by SQLFetch overlaps the end of the result set, SQLFetch returns a partial rowset. That is, if S + R – 1 is greater than L, where S is the starting row of the rowset being fetched, R is the rowset size, and L is the last row in the result set, then only the first L – S+1 rows of the rowset are valid. The remaining rows are empty and have a status of SQL_ROW_NOROW.

After SQLFetch returns, the current row is the first row of the rowset.

The following rules describe cursor positioning after a call to SQLFetch:

Condition First row of new rowset
Before start 1
CurrRowsetStart <= LastResultRow – RowsetSize 1 CurrRowsetStart + RowsetSize 2
CurrRowsetStart > LastResultRow – RowsetSize 1 After end
After end After end
1If the rowset size is changed between fetches, this is the rowset size that was used with the previous fetch.

2If the rowset size is changed between fetches, this is the rowset size that was used with the new fetch.


where:

Notation Meaning
Before start The block cursor is positioned before the start of the result set. If the first row of the new rowset is before the start of the result set, SQLFetch returns SQL_NO_DATA.
After end The block cursor is positioned after the end of the result set. If the first row of the new rowset is after the end of the result set, SQLFetch returns SQL_NO_DATA.
CurrRowsetStart The number of the first row in the current rowset.
LastResultRow The number of the last row in the result set.
RowsetSize The rowset size.

For example, suppose a result set has 100 rows and the rowset size is 5. The following table shows the rowset and return code returned by SQLFetch for different starting positions.


Current rowset

Return code

New rowset
# of rows fetched
Before start SQL_SUCCESS 1 to 5 5
1 to 5 SQL_SUCCESS 6 to 10 5
52 to 56 SQL_SUCCESS 57 to 61 5
91 to 95 SQL_SUCCESS 96 to 100 5
93 to 97 SQL_SUCCESS 98 to 100. Rows 4 and 5
of the row status array
are set to
SQL_ROW_NOROW.
3
96 to 100 SQL_NO_DATA None. 0
99 to 100 SQL_NO_DATA None. 0
After end SQL_NO_DATA None. 0

Returning Data in Bound Columns

As SQLFetch returns each row, it places the data for each bound column in the buffer bound to that column. If no columns are bound, SQLFetch does not return any data but does move the block cursor forward. The data can still be retrieved with SQLGetData. If the cursor is a multirow cursor (that is, the SQL_ATTR_ROW_ARRAY_SIZE is greater than 1), SQLGetData can be called only if SQL_GD_BLOCK is returned when SQLGetInfo is called with an InfoType of SQL_GETDATA_EXTENSIONS. (For more information, see SQLGetData.)

For each bound column in a row, SQLFetch does the following:

  1. Sets the length/indicator buffer to SQL_NULL_DATA and proceeds to the next column if the data is NULL. If the data is NULL and no length/indicator buffer was bound, SQLFetch returns SQLSTATE 22002 (Indicator variable required but not supplied) for the row and proceeds to the next row. For information about how to determine the address of the length/indicator buffer, see “Buffer Addresses” in SQLBindCol.

    If the data for the column is not NULL, SQLFetch proceeds to step 2.

  2. If the SQL_ATTR_MAX_LENGTH statement attribute is set to a nonzero value and the column contains character or binary data, the data is truncated to SQL_ATTR_MAX_LENGTH bytes.

    Note The SQL_ATTR_MAX_LENGTH statement attribute is intended to reduce network traffic. It is generally implemented by the data source, which truncates the data before returning it across the network. Drivers and data sources are not required to support it. Therefore, to guarantee that data is truncated to a particular size, an application should allocate a buffer of that size and specify the size in the cbValueMax argument in SQLBindCol.

  3. Converts the data to the type specified by TargetType in SQLBindCol.

  4. If the data was converted to a variable-length data type, such as character or binary, SQLFetch checks whether the length of the data exceeds the length of the data buffer. If the length of character data (including the null-termination character) exceeds the length of the data buffer, SQLFetch truncates the data to the length of the data buffer less the length of a null-termination character. It then null-terminates the data. If the length of binary data exceeds the length of the data buffer, SQLFetch truncates it to the length of the data buffer. The length of the data buffer is specified with BufferLength in SQLBindCol.

    SQLFetch never truncates data converted to fixed-length data types; it always assumes that the length of the data buffer is the size of the data type.

  5. Places the converted (and possibly truncated) data in the data buffer. For information about how to determine the address of the data buffer, see “Buffer Addresses” in SQLBindCol.

  6. Places the length of the data in the length/indicator buffer. If the indicator pointer and the length pointer were both set to the same buffer (as a call to SQLBindCol does), the length is written in the buffer for valid data and SQL_NULL_DATA is written in the buffer for NULL data. If no length/indicator buffer was bound, SQLFetch does not return the length.
    • For character or binary data, this is the length of the data after conversion and before truncation due to the data buffer being too small. If the driver cannot determine the length of the data after conversion, as is sometimes the case with long data, it sets the length to SQL_NO_TOTAL. If data was truncated due to the SQL_ATTR_MAX_LENGTH statement attribute, the value of this attribute — as opposed to the actual length — is placed in the length/indicator buffer. This is because this attribute is designed to truncate data on the server before conversion, so the driver has no way of figuring out what the actual length is.

    • For all other data types, this is the length of the data after conversion; that is, it is the size of the type to which the data was converted.

    For information about how to determine the address of the length/indicator buffer, see “Buffer Addresses” in SQLBindCol.

  7. If the data is truncated during conversion without a loss of significant digits (for example, the real number 1.234 is truncated when converted to the integer 1) and SQLFetch returns SQLSTATE 01S07 (Fractional truncation) and SQL_SUCCESS_WITH_INFO: If the data is truncated because the length of the data buffer is too small (for example, the string “abcdef” is placed in a 4-byte buffer), SQLFetch returns SQLSTATE 01004 (Data truncated) and SQL_SUCCESS_WITH_INFO. If data is truncated due to the SQL_ATTR_MAX_LENGTH statement attribute, SQLFetch returns SQL_SUCCESS and does not return SQLSTATE 01S07 (Fractional truncation) or SQLSTATE 01004 (Data truncated). If data is truncated during conversion with a loss of significant digits (for example, if an SQL_INTEGER value greater than 100,000 were converted to an SQL_C_TINYINT), SQLFetch returns SQLSTATE 22003 (Numeric value out of range) and SQL_ERROR (if the rowset size is 1) or SQL_SUCCESS_WITH_INFO (if the rowset size is greater than 1).

The contents of the bound data buffer and the length/indicator buffer are undefined if SQLFetch or SQLFetchScroll does not return SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.

Row Status Array

The row status array is used to return the status of each row in the rowset. The address of this array is specified with the SQL_ATTR_ROW_STATUS_PTR statement attribute. The array is allocated by the application and must have as many elements as are specified by the SQL_ATTR_ROW_ARRAY_SIZE statement attribute. Its values are set by SQLFetch, SQLFetchScroll, and SQLBulkOperations or SQLSetPos (except when they have been called after the cursor has been positioned by SQLExtendedFetch). If the value of the SQL_ATTR_ROW_STATUS_PTR statement attribute is a null pointer, these functions do not return the row status.

The contents of the row status array buffer are undefined if SQLFetch or SQLFetchScroll does not return SQL_SUCCESS or SQL_SUCCESS_WITH_INFO.

The following values are returned in the row status array.

Row status array value Description
SQL_ROW_SUCCESS The row was successfully fetched and has not changed since it was last fetched from this result set.
SQL_ROW_SUCCESS_
WITH_INFO
The row was successfully fetched and has not changed since it was last fetched from this result set. However, a warning was returned about the row.
SQL_ROW_ERROR An error occurred while fetching the row.
SQL_ROW_UPDATED 1,2, and 3 The row was successfully fetched and has changed since it was last fetched from this result set. If the row is fetched again from this result set, or is refreshed by SQLSetPos, the status changed to the row’s new status.
SQL_ROW_DELETED 3 The row has been deleted since it was last fetched from this result set.
SQL_ROW_ADDED 4 The row was inserted by SQLBulkOperations. If the row is fetched again from this result set, or is refreshed by SQLSetPos, its status is SQL_ROW_SUCCESS.
SQL_ROW_NOROW The rowset overlapped the end of the result set and no row was returned that corresponded to this element of the row status array.
1For keyset, mixed, and dynamic cursors, if a key value is updated, the row of data is considered to have been deleted and a new row added.

2Some drivers cannot detect updates to data and therefore cannot return this value. To determine whether a driver can detect updates to refetched rows, an application calls SQLGetInfo with the SQL_ROW_UPDATES option.

3SQLFetch can return this value only when it is intermixed with calls to SQLFetchScroll. The reason for this is that SQLFetch moves forward through the result set and, when used exclusively, does not refetch any rows. Because no rows are refetched, SQLFetch does not detect changes made to previously fetched rows. However, if SQLFetchScroll positions the cursor before any previously fetched rows and SQLFetch is used to fetch those rows, SQLFetch can detect any changes to those rows.

4Returned by SQLBulkOperations only. Not set by SQLFetch or SQLFetchScroll.


Rows Fetched Buffer

The rows fetched buffer is used to return the number of rows fetched, including those rows for which no data was returned because an error occurred while they were being fetched. In other words, it is the number of rows for which the value in the row status array is not SQL_ROW_NOROW. The address of this buffer is specified with the SQL_ATTR_ROWS_FETCHED_PTR statement attribute. The buffer is allocated by the application. It is set by SQLFetch and SQLFetchScroll. If the value of the SQL_ATTR_ROWS_FETCHED_PTR statement attribute is a null pointer, these functions do not return the number of rows fetched. To determine the number of the current row in the result set, an application can call SQLGetStmtAttr with the SQL_ATTR_ROW_NUMBER attribute.

The contents of the rows fetched buffer are undefined if SQLFetch or SQLFetchScroll does not return SQL_SUCCESS or SQL_SUCCESS_WITH_INFO, except when SQL_NO_DATA is returned, in which case the value in the rows fetched buffer is set to 0.

Error Handling

Errors and warnings can apply to individual rows or to the entire function. For more information about diagnostic records, see Chapter 15, “Diagnostics,” and SQLGetDiagField.

Errors and Warnings on the Entire Function

If an error applies to the entire function, such as SQLSTATE HYT00 (Timeout expired) or SQLSTATE 24000 (Invalid cursor state), SQLFetch returns SQL_ERROR and the applicable SQLSTATE. The contents of the rowset buffers are undefined and the cursor position is unchanged.

If a warning applies to the entire function, SQLFetch returns SQL_SUCCESS_WITH_INFO and the applicable SQLSTATE. The status records for warnings that apply to the entire function are returned before the status records that apply to individual rows.

Errors and Warnings in Individual Rows

If an error (such as SQLSTATE 22012 (Division by zero)) or a warning (such as SQLSTATE 01004 (Data truncated)) applies to a single row, SQLFetch:

SQLFetch continues fetching rows until it has fetched all of the rows in the rowset. It returns SQL_SUCCESS_WITH_INFO unless an error occurs in every row of the rowset (not counting rows with status SQL_ROW_NOROW), in which case it returns SQL_ERROR. In particular, if the rowset size is 1 and an error occurs in that row, SQLFetch returns SQL_ERROR.

SQLFetch returns the status records in row number order. That is, it returns all status records for unknown rows (if any), then all status records for the first row (if any), then all status records for the second row (if any), and so on. The status records for each individual row are ordered according to the normal rules for ordering status records; for more information, see “Sequence of Status Records” in SQLGetDiagField.

Descriptors and SQLFetch

The following sections describe how SQLFetch interacts with descriptors.

Argument Mappings

The driver does not set any descriptor fields based on the arguments of SQLFetch.

Other Descriptor Fields

The following descriptor fields are used by SQLFetch.

Descriptor field Desc. Field in Set through
SQL_DESC_ARRAY_SIZE ARD header SQL_ATTR_ROW_ARRAY_SIZE statement attribute
SQL_DESC_ARRAY_STATUS_PTR IRD header SQL_ATTR_ROW_STATUS_PTR statement attribute
SQL_DESC_BIND_OFFSET_PTR ARD header SQL_ATTR_ROW_BIND_OFFSET_PTR statement attribute
SQL_DESC_BIND_TYPE ARD header SQL_ATTR_ROW_BIND_TYPE statement attribute
SQL_DESC_COUNT ARD header ColumnNumber argument of SQLBindCol
SQL_DESC_DATA_PTR ARD records TargetValuePtr argument of SQLBindCol
SQL_DESC_INDICATOR_PTR ARD records StrLen_or_IndPtr argument in SQLBindCol
SQL_DESC_OCTET_LENGTH ARD records BufferLength argument in SQLBindCol
SQL_DESC_OCTET_LENGTH_PTR ARD records StrLen_or_IndPtr argument in SQLBindCol
SQL_DESC_ROWS_
PROCESSED_PTR
IRD header SQL_ATTR_ROWS_FETCHED_PTR statement attribute
SQL_DESC_TYPE ARD records TargetType argument in SQLBindCol

All descriptor fields can also be set through SQLSetDescField.

Separate Length and Indicator Buffers

Applications can bind a single buffer or two separate buffers to be used to hold length and indicator values. When an application calls SQLBindCol, the driver sets the SQL_DESC_OCTET_LENGTH_PTR and SQL_DESC_INDICATOR_PTR fields of the ARD to the same address, which is passed in the StrLen_or_IndPtr argument. When an application calls SQLSetDescField or SQLSetDescRec, it can set these two fields to different addresses.

SQLFetch determines whether the application has specified separate length and indicator buffers. In this case, when the data is not NULL, SQLFetch sets the indicator buffer to 0 and returns the length in the length buffer. When the data is NULL, SQLFetch sets the indicator buffer to SQL_NULL_DATA and does not modify the length buffer.

Code Example

See SQLBindCol, SQLColumns, SQLGetData, and SQLProcedures.

Related Functions

For information about See
Binding a buffer to a column in a result set SQLBindCol
Canceling statement processing SQLCancel
Returning information about a column in a result set SQLDescribeCol
Executing an SQL statement SQLExecDirect
Executing a prepared SQL statement SQLExecute
Fetching a block of data or scrolling through a result set SQLFetchScroll
Closing the cursor on the statement SQLFreeStmt
Fetching part or all of a column of data SQLGetData
Returning the number of result set columns SQLNumResultCols
Preparing a statement for execution SQLPrepare