Version Introduced: ODBC 1.0
Standards Compliance: ISO 92
SQLFetch fetches the next rowset of data from the result set and returns data for all bound columns.
SQLRETURN SQLFetch( SQLHSTMT StatementHandle);
SQL_SUCCESS, SQL_SUCCESS_WITH_INFO, SQL_NO_DATA, SQL_STILL_EXECUTING, SQL_ERROR, or SQL_INVALID_HANDLE.
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.
|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 nonblank 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.|
|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.|
SQLFetch returns the next rowset in the result set. It can be called only while a result set existsthat 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 fetch only a single row.
For more information, see "Block Cursors, Scrollable Cursors, and Backward Compatibility" in Appendix G: Driver Guidelines for Backward Compatibility.
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 rules listed in the following table describe cursor positioning after a call to SQLFetch, based on the conditions listed in the second table below.
|Condition||First row of new rowset|
|CurrRowsetStart <= LastResultRow RowsetSize||CurrRowsetStart + RowsetSize|
|CurrRowsetStart > LastResultRow RowsetSize||After end|
|After end||After end|
 If the rowset size is changed between fetches, this is the rowset size that was used with the previous fetch.
 If the rowset size is changed between fetches, this is the rowset size that was used with the new fetch.
|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.
|# 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
|96 to 100||SQL_NO_DATA||None.||0|
|99 to 100||SQL_NO_DATA||None.||0|
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:
If the data for the column is not NULL, SQLFetch proceeds to step 2.
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.
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.
For information about how to determine the address of the length/indicator buffer, see "Buffer Addresses" in SQLBindCol.
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.
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,, and ||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 is changed to the row's new status.|
|SQL_ROW_DELETED||The row has been deleted since it was last fetched from this result set.|
|SQL_ROW_ADDED||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.|
 For 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.
 Some 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.
 SQLFetch 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.
 Returned by SQLBulkOperations only. Not set by SQLFetch or SQLFetchScroll.
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.
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.
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 does the following:
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.
The following sections describe how SQLFetch interacts with descriptors.
The driver does not set any descriptor fields based on the arguments of SQLFetch.
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.
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.
|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|