Taming function module RFC_READ_TABLE

by | May 1, 2015 | 0 comments

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
CALL FUNCTION RFC_READ_TABLE' DESTINATION p_dest
EXPORTING
query_table = p_tabnam
TABLES
options     = lt_where
fields      = lt_nametab1
data        = lt_raw_tab
EXCEPTIONS
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'.
ENDIF.

*   Get table description e.g. from target system or current system, here current system is sufficent
lv_tabnam = p_tabnam.
CALL FUNCTION 'DD_GET_NAMETAB'
EXPORTING
tabname   = lv_tabnam
get_all   = 'X'
TABLES
x031l_tab = lt_field
EXCEPTIONS
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>.
CALL FUNCTION 'HR_RU_CONVERT_HEX_TO_STRING'
EXPORTING
xstring = lv_x
IMPORTING
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.
ELSE.
lv_length = <field>-dblength.
ENDIF.

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

*       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.

ENDLOOP.

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

ENDLOOP.

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…