SAP / PyRFC

Asynchronous, non-blocking SAP NW RFC SDK bindings for Python
http://sap.github.io/PyRFC
Apache License 2.0
500 stars 132 forks source link

cannot extract data package by package from sap bw using RFC call #338

Closed shakh85 closed 8 months ago

shakh85 commented 11 months ago

conn.get_function_description('ZRSDRI_HA01M0002_READ_RFC').parameters give me the following picture.

[{'decimals': 0,
  'default_value': 'RS_C_TRUE',
  'direction': 'RFC_CHANGING',
  **'name': 'C_FIRST_CALL',**
  'nuc_length': 1,
  'optional': False,
  'parameter_text': 'Boolean',
  'parameter_type': 'RFCTYPE_CHAR',
  'type_description': None,
  'uc_length': 2},
 {'decimals': 0,
  'default_value': '',
  'direction': 'RFC_EXPORT',
  'name': 'E_END_OF_DATA',
  'nuc_length': 1,
  'optional': False,
  'parameter_text': 'Last Data Package Yes/No',
  'parameter_type': 'RFCTYPE_CHAR',
  'type_description': None,
  'uc_length': 2},
 {'decimals': 0,
  'default_value': '',
  'direction': 'RFC_EXPORT',
  'name': 'E_T_DATA',
  'nuc_length': 142,
  'optional': False,
  'parameter_text': 'Internal Table with Query Result',
  'parameter_type': 'RFCTYPE_TABLE',
  'type_description': <TypeDescription 'ZBW_HA01M0002_RFC_TABLE' with 10 fields (n/uclength=142/276)>,
  'uc_length': 276},
 {'decimals': 0,
  'default_value': '',
  'direction': 'RFC_IMPORT',
  'name': 'I_T_RANGE',
  'nuc_length': 56,
  'optional': True,
  'parameter_text': 'BW Data Manager: Range List',
  'parameter_type': 'RFCTYPE_TABLE',
  'type_description': <TypeDescription 'RSDRI_T_RANGE' with 5 fields (n/uclength=56/88)>,
  'uc_length': 88}]

aiming at retrieving data call by call by 10K rows at a time i got stuck with the issue that first call is being processed only returning my 10k rows and then it stops as if it never saw that i tried to make adjustments to changing parameter. The code is as follows:

from pyrfc import Connection

def ZRSDRI_HA01M0002_READ_RFC_TEST():
    l_first_call = "X"
    l_end_of_data = "X"
    l_t_data = []

    conn_params = {
        'ashost': 'XX.XX.XX.XX',
        'sysnr': 'XX',
        'client': 'XX',
        'user': 'user',
        'passwd': 'password'
    }

    with Connection(**conn_params) as conn:
        while l_end_of_data == "X":
            result = conn.call('ZRSDRI_HA01M0002_READ_RFC',
                                C_FIRST_CALL=l_first_call)
            l_first_call = ""  # Reset after the first call

            # If E_T_END_OF_DATA exists in the result, update our variable
            if 'E_T_END_OF_DATA' in result:
                l_end_of_data = result['E_T_END_OF_DATA']

            # If E_T_DATA exists, append the new data to our list
            if 'E_T_DATA' in result:
                l_t_data.extend(result['E_T_DATA'])

    return l_t_data

# Run the function
if __name__ == "__main__":
    output = ZRSDRI_HA01M0002_READ_RFC_TEST()
    print(output)

Please can you shine any light on how to get data call by call in proper manner?

bsrdjan commented 11 months ago

To my understanding if 10k rows returned in first call, then it is probably not the "end of data" and result['E_T_END_OF_DATA'] is empty.

The block:

            if 'E_T_END_OF_DATA' in result:
                l_end_of_data = result['E_T_END_OF_DATA']

will then set the l_end_data to empty and exit the while loop.

The while loop should probably look like

l_end_of_data == "" # no end of data
while l_end_of_data != "X": # wait for end of data
   ...
   # you can also check if values returned for end of data are what is expected by your Python script
   # print (result['E_T_END_OF_DATA'])
shakh85 commented 11 months ago

To my understanding if 10k rows returned in first call, then it is probably not the "end of data" and result['E_T_END_OF_DATA'] is empty.

The block:

            if 'E_T_END_OF_DATA' in result:
                l_end_of_data = result['E_T_END_OF_DATA']

will then set the l_end_data to empty and exit the while loop.

The while loop should probably look like

l_end_of_data == "" # no end of data
while l_end_of_data != "X": # wait for end of data
   ...
   # you can also check if values returned for end of data are what is expected by your Python script
   # print (result['E_T_END_OF_DATA'])

thank you to looking into it:

something maybe is different with first call that is being pointed out as X and not transformed into call method while trying to perform the second call?:

image

i am trying to change this changing param but it is not changed after the first call been made

bsrdjan commented 11 months ago

If you have access to ABAP system, the external breakpoint in ZRSDRI_HA*READ_RFC function module can be set as described here: troubleshooting.md#remote-abap-debugging. Then it can be tested in ABAP debugger what exactly does not work as expected.

It is custom function module but in general the parameter like 'E_T_END_OF_DATA' is always returned in result, not sure why. result.get() used for this and other parameters. Perhaps also to check if ABAP domain of C_FIRST_CALL and E_T_END_OF_DATA is " " and "X" or maybe "Y" and "N" ?

Without checking the system and both the Python and ABAP logic, I can't help more. I would suggest to set the breakpoint in ABAP and investigate or request support via SAP customer message and refer to this issue.