int pdo_sqlsrv_stmt_fetch()

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;
}