I recently wanted to write a report that would compare data between different systems (e.g. customizing or transactional data). I found the function module “RFC_READ_TABLE”, which delivers data from other systems. The where-clause, which can easily be passed into the options parameter, is essential, especially when comparing transactional data, as one does not want to have all of the data returned in one call for performance reasons.

I soon stumbled upon a limitation. This standard function module does not properly support packed fields and everything was out. I was checking the internet and found this nice SDN thread, which describes a solution. However, it does not include enough detail. After playing around a bit, I think I have tamed the beast.

There were a couple of issues, mainly the one that the length of the fields differs accordingly to their type and the offset to know where to start looking for the next needed to consider the length as well.

  DATA lt_where    TYPE rsds_where_tab.               “ where clause for selection
  DATA lt_nametab1 TYPE STANDARD TABLE OF rfc_db_fld. “ will be left blank
  DATA lt_raw_tab  TYPE TABLE OF veri_raw.            “ buffer table with raw data
  DATA lt_field    TYPE TABLE OF x031l.               “ field description
  DATA lv_x        TYPE xstring.
  DATA lv_str      TYPE string.
  DATA lv_char     TYPE char2048.
  DATA lv_offset   TYPE roffset.
  DATA lv_length   TYPE outlength.

  FIELD-SYMBOLS <ls_raw_line> TYPE veri_raw.
  FIELD-SYMBOL <fld>          TYPE any.
  FIELD-SYMBOL <fld_tar>      TYPE any.

* Get raw data from a different system
      query_table = p_tabnam
      options     = lt_where
      fields      = lt_nametab1
      data        = lt_raw_tab
      others      = 7.

    IF sy-subrc <> 0.
      MESSAGE ID sy-msgid TYPE 'E' NUMBER sy-msgno
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 DISPLAY LIKE 'I'.

*   Get table description e.g. from target system or current system, here current system is sufficent
    lv_tabnam = p_tabnam.
        tabname   = lv_tabnam
        get_all   = 'X'
        x031l_tab = lt_field
        others    = 0.

*   Loop over the raw data needs to be done because packed fields are giving hassles
    LOOP AT lt_raw_tab ASSIGNING <ls_raw_line>.

*     get the string for the raw data
      lv_x = <ls_raw_line>.
          xstring = lv_x
          cstring = lv_str.

*     Move to character string
      lv_char = lv_str.

*     Clear some variables
      CLEAR <line2>.
      CLEAR lv_offset.

*     Loop over each field of the table
      LOOP AT lt_field ASSIGNING <field>.

*       Assign the target field
        ASSIGN COMPONENT <field>-fieldname OF STRUCTURE <line> TO <fld_tar>. “ <line> is a fieldsymbol which is assigned to a structure corresponding to the table

*       Determine the length of the field accordingly to type
        IF <field>-exid eq 'P'.         “packed field
          lv_length = <field>-digits.
        ELSEIF <field>-exid eq 'b'.     “integer field
          lv_length = <field>-exlength.
          lv_length = <field>-dblength.

        IF lv_length EQ 0. “don’t processes if length is zero e.g. include description

*       Get the field value
        ASSIGN lv_char+lv_offset(lv_length) TO <fld>.

*       Assign to target field
        <fld_tar> = <fld>.
*       Adjust length for next field
        ADD lv_length TO lv_offset.


*     Append line to compare table
      APPEND <line> TO <tab>.


Please note: The function module itself does an authority check and from my perspective it is the responsibility of the developer and administrator to ensure that the RFC destinations are set up properly, so that a logon is enforced. Otherwise this function module can be abused to read data from a system where the user is not supposed to poke around…