in driver/results.cc [2255:2554]
SQLRETURN SQL_API my_SQLExtendedFetch( SQLHSTMT hstmt,
SQLUSMALLINT fFetchType,
SQLLEN irow,
SQLULEN *pcrow,
SQLUSMALLINT *rgfRowStatus,
my_bool upd_status )
{
SQLULEN rows_to_fetch;
long cur_row, max_row;
SQLULEN i;
SQLRETURN row_res, res, row_book= SQL_SUCCESS;
STMT *stmt= (STMT *) hstmt;
MYSQL_ROW values= 0;
MYSQL_ROW_OFFSET save_position= 0;
SQLULEN dummy_pcrow;
BOOL disconnected= FALSE;
long brow= 0;
auto span_stop_if_no_data = [](STMT *stmt) {
if (!stmt->dbc->connection_proxy->more_results())
{
stmt->telemetry.span_end(stmt);
}
return;
};
try
{
if ( !stmt->result )
{
res = stmt->set_error("24000", "Fetch without a SELECT", 0);
throw stmt->error;
}
if (stmt->out_params_state != OPS_UNKNOWN)
{
switch(stmt->out_params_state)
{
case OPS_BEING_FETCHED:
/* Smth weird */
span_stop_if_no_data(stmt);
return SQL_NO_DATA_FOUND;
case OPS_STREAMS_PENDING:
/* Magical out params fetch */
stmt->dbc->connection_proxy->stmt_fetch(stmt->ssps);
default:
/* TODO: Need to remember real fetch' result */
/* just in case... */
stmt->out_params_state= OPS_BEING_FETCHED;
}
}
cur_row = stmt->current_row;
if ( stmt->stmt_options.cursor_type == SQL_CURSOR_FORWARD_ONLY )
{
if ( fFetchType != SQL_FETCH_NEXT && !stmt->dbc->ds->opt_SAFE )
{
res = stmt->set_error(MYERR_S1106,
"Wrong fetchtype with FORWARD ONLY cursor", 0);
throw stmt->error;
}
}
if ( stmt->is_dynamic_cursor() && set_dynamic_result(stmt) )
{
res = stmt->set_error(MYERR_S1000,
"Driver Failed to set the internal dynamic result", 0);
throw stmt->error;
}
if ( !pcrow )
pcrow= &dummy_pcrow;
/* for scrollable cursor("scroller") max_row is max row for currently
fetched part of resultset */
max_row= (long) num_rows(stmt);
stmt->reset_getdata_position();
stmt->current_values= 0; /* For SQLGetData */
cur_row = stmt->compute_cur_row(fFetchType, irow);
if (scroller_exists(stmt)
|| (if_forward_cache(stmt) && !stmt->result_array)
|| (fFetchType == SQL_FETCH_BOOKMARK && stmt->stmt_options.bookmark_insert))
{
rows_to_fetch= stmt->ard->array_size;
}
else
{
rows_to_fetch= myodbc_min(max_row-cur_row,
(long)stmt->ard->array_size);
}
/* out params has been silently fetched */
if (rows_to_fetch == 0)
{
if (stmt->out_params_state != OPS_UNKNOWN)
{
rows_to_fetch= 1;
}
else
{
*pcrow= 0;
stmt->rows_found_in_set= 0;
if ( upd_status && stmt->ird->rows_processed_ptr )
{
*stmt->ird->rows_processed_ptr= 0;
}
span_stop_if_no_data(stmt);
return SQL_NO_DATA_FOUND;
}
}
res= SQL_SUCCESS;
for (i= 0 ; i < rows_to_fetch ; ++i)
{
values = nullptr;
if ( stmt->result_array )
{
values= stmt->result_array + cur_row*stmt->result->field_count;
if ( i == 0 )
{
stmt->current_values= values;
}
}
else
{
/* This code will ensure that values is always set */
if ( i == 0 )
{
save_position= row_tell(stmt);
}
/* - Actual fetching happens here - */
if ( stmt->out_params_state == OPS_UNKNOWN
&& !(values = stmt->fetch_row()) )
{
if (scroller_exists(stmt))
{
scroller_move(stmt);
row_res= scroller_prefetch(stmt);
if (row_res != SQL_SUCCESS)
{
break;
}
if ( !(values = stmt->fetch_row()) )
{
break;
}
/* Not sure that is right, but see it better than nothing */
save_position= row_tell(stmt);
}
else
{
break;
}
}
if (stmt->out_params_state != OPS_UNKNOWN)
{
values= stmt->array;
}
if (stmt->fix_fields)
{
values= (*stmt->fix_fields)(stmt,values);
}
stmt->current_values= values;
}
if (!stmt->fix_fields)
{
/* lengths contains lengths for all rows. Alternate use could be
filling ird buffers in the (fix_fields) function. In this case
lengths could contain just one array with rules for lengths
calculating(it can work out in many cases like in catalog functions
there some fields from results of auxiliary query are simply mixed
somehow and constant fields added ).
Another approach could be using of "array" and "order" arrays
and special fix_fields callback, that will fix array and set
lengths in ird*/
if (stmt->lengths)
{
fill_ird_data_lengths(stmt->ird, stmt->lengths.get() + cur_row*stmt->result->field_count,
stmt->result->field_count);
}
else
{
fill_ird_data_lengths(stmt->ird, fetch_lengths(stmt),
stmt->result->field_count);
}
}
if (fFetchType == SQL_FETCH_BOOKMARK &&
stmt->stmt_options.bookmarks == SQL_UB_VARIABLE)
{
row_book= fill_fetch_bookmark_buffers(stmt, (ulong)(irow + i + 1), (uint)i);
}
row_res= fill_fetch_buffers(stmt, values, (uint)i);
/* For SQL_SUCCESS we need all rows to be SQL_SUCCESS */
if (res != row_res || res != row_book)
{
/* Any successful row makes overall result SQL_SUCCESS_WITH_INFO */
if (SQL_SUCCEEDED(row_res))
{
res= SQL_SUCCESS_WITH_INFO;
}
/* Else error */
else if (i == 0)
{
/* SQL_ERROR only if all rows fail */
res= SQL_ERROR;
}
else
{
res= SQL_SUCCESS_WITH_INFO;
}
}
/* "Fetching" includes buffers filling. I think errors in that
have to affect row status */
if (rgfRowStatus)
{
rgfRowStatus[i]= sqlreturn2row_status(row_res);
}
/*
No need to update rowStatusPtr_ex, it's the same as rgfRowStatus.
*/
if (upd_status && stmt->ird->array_status_ptr)
{
stmt->ird->array_status_ptr[i]= sqlreturn2row_status(row_res);
}
++cur_row;
} /* fetching cycle end*/
stmt->rows_found_in_set = (uint)i;
*pcrow= i;
disconnected= is_connection_lost(stmt->dbc->connection_proxy->error_code())
&& handle_connection_error(stmt);
if ( upd_status && stmt->ird->rows_processed_ptr )
{
*stmt->ird->rows_processed_ptr= i;
}
/* It is possible that both rgfRowStatus and array_status_ptr are set
(and upp_status is TRUE) */
for ( ; i < stmt->ard->array_size ; ++i )
{
if ( rgfRowStatus )
{
rgfRowStatus[i]= disconnected ? SQL_ROW_ERROR : SQL_ROW_NOROW;
}
/*
No need to update rowStatusPtr_ex, it's the same as rgfRowStatus.
*/
if ( upd_status && stmt->ird->array_status_ptr )
{
stmt->ird->array_status_ptr[i]= disconnected? SQL_ROW_ERROR
: SQL_ROW_NOROW;
}
}
if (SQL_SUCCEEDED(res) && !stmt->result_array && !if_forward_cache(stmt))
{
/* reset result position */
stmt->end_of_set= row_seek(stmt, save_position);
}
if (SQL_SUCCEEDED(res)
&& stmt->rows_found_in_set < stmt->ard->array_size)
{
if (disconnected)
{
res = SQL_ERROR;
throw stmt->error;
}
else if (stmt->rows_found_in_set == 0)
{
span_stop_if_no_data(stmt);
return SQL_NO_DATA_FOUND;
}
}
}
catch(MYERROR &e)
{
res = e.retcode;
stmt->telemetry.set_error(stmt, e.message);
}
return res;
}