in source/pdo_sqlsrv/pdo_stmt.cpp [643:746]
int pdo_sqlsrv_stmt_fetch( _Inout_ pdo_stmt_t *stmt, _In_ enum pdo_fetch_orientation ori,
_In_ zend_long offset)
{
PDO_RESET_STMT_ERROR;
PDO_VALIDATE_STMT;
PDO_LOG_STMT_ENTRY;
try {
SQLSRV_ASSERT( stmt != NULL, "pdo_sqlsrv_stmt_fetch: pdo_stmt object was null" );
pdo_sqlsrv_stmt* driver_stmt = reinterpret_cast<pdo_sqlsrv_stmt*>( stmt->driver_data );
SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_fetch: driver_data object was null" );
// set the types for bound columns to zval so that PDO does no conversion when the value
// is returned by pdo_sqlsrv_get_col_data. Remember the types that were bound by the user
// and use it to manually convert data types
if( stmt->bound_columns ) {
pdo_bound_param_data* bind_data = NULL;
if( !driver_stmt->bound_column_param_types ) {
#if PHP_VERSION_ID < 80100
driver_stmt->bound_column_param_types =
reinterpret_cast<pdo_param_type*>( sqlsrv_malloc( stmt->column_count, sizeof( pdo_param_type ), 0 ));
std::fill( driver_stmt->bound_column_param_types, driver_stmt->bound_column_param_types + stmt->column_count,
PDO_PARAM_ZVAL );
#else
// TODO: possibly no longer need bound_column_param_types?? default to PDO_PARAM_STR???
driver_stmt->bound_column_param_types =
reinterpret_cast<pdo_param_type*>(sqlsrv_malloc(stmt->column_count, sizeof(pdo_param_type), 0));
std::fill(driver_stmt->bound_column_param_types, driver_stmt->bound_column_param_types + stmt->column_count,
PDO_PARAM_STR);
#endif
}
for( long i = 0; i < stmt->column_count; ++i ) {
#if PHP_VERSION_ID < 80100
if (NULL== (bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_index_find_ptr(stmt->bound_columns, i))) &&
(NULL == (bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_find_ptr(stmt->bound_columns, stmt->columns[i].name))))) {
driver_stmt->bound_column_param_types[i] = PDO_PARAM_ZVAL;
continue;
}
if( bind_data->param_type != PDO_PARAM_ZVAL ) {
driver_stmt->bound_column_param_types[i] = bind_data->param_type;
bind_data->param_type = PDO_PARAM_ZVAL;
}
#else
if (NULL == (bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_index_find_ptr(stmt->bound_columns, i))) &&
(NULL == (bind_data = reinterpret_cast<pdo_bound_param_data*>(zend_hash_find_ptr(stmt->bound_columns, stmt->columns[i].name))))) {
continue;
}
// TODO: possibly no longer need bound_column_param_types??
driver_stmt->bound_column_param_types[i] = bind_data->param_type;
#endif
}
}
SQLSMALLINT odbc_fetch_ori = pdo_fetch_ori_to_odbc_fetch_ori( ori );
bool data = core_sqlsrv_fetch( driver_stmt, odbc_fetch_ori, offset );
// support for the PDO rowCount method. Since rowCount doesn't call a
// method, PDO relies on us to fill the pdo_stmt_t::row_count member
// The if condition was changed from
// `driver_stmt->past_fetch_end || driver_stmt->cursor_type != SQL_CURSOR_FORWARD_ONLY`
// because it caused SQLRowCount to be called at each fetch if using a non-forward cursor
// which is unnecessary and a performance hit
if( driver_stmt->past_fetch_end || driver_stmt->cursor_type == SQL_CURSOR_DYNAMIC) {
stmt->row_count = core::SQLRowCount( driver_stmt );
driver_stmt->row_count = stmt->row_count;
// a row_count of -1 means no rows, but we change it to 0
if( stmt->row_count == -1 ) {
stmt->row_count = 0;
}
}
// if no data was returned, then return false so data isn't retrieved
if( !data ) {
return 0;
}
return 1;
}
catch( core::CoreException& ) {
return 0;
}
catch( ... ) {
DIE ("pdo_sqlsrv_stmt_fetch: Unexpected exception occurred.");
}
// Should not have reached here but adding this due to compilation warnings
return 0;
}