Skip to Content
Technical Articles
Author's profile photo Stefan Schnell

How to use SAP NetWeaver RFC Library with Python – Read Table

I presented until now in the series “How to use SAPNetWeaver RFC Library with Pyhton” :

Here now an example how to read a table with the function module (FM) RFC_READ_TABLE. You need the file sapnwrfc.py from here – look at the end of the posting.

After the connection we get the function description of the FM, in our case RFC_READ_TABLE. We set the arguments QUERY_TABLE, in our case USR01, and the DELIMITER. We invoke the FM and print the result line by line. The result is in the DATA table, in the field WA.

# -*- coding: iso-8859-15 -*-
#-Begin-----------------------------------------------------------------

#-Include---------------------------------------------------------------
FileName = "sapnwrfc.py"
exec(compile(open(FileName).read(), FileName, "exec"))

#-Main------------------------------------------------------------------

#-Connection parameters-------------------------------------------------
RfcConnParams[0].name = "ASHOST"; RfcConnParams[0].value = "ABAP"
RfcConnParams[1].name = "SYSNR" ; RfcConnParams[1].value = "00"
RfcConnParams[2].name = "CLIENT"; RfcConnParams[2].value = "001"
RfcConnParams[3].name = "USER"  ; RfcConnParams[3].value = "BCUSER"
RfcConnParams[4].name = "PASSWD"; RfcConnParams[4].value = "minisap"

TableName = "USR01"

hRFC = SAP.RfcOpenConnection(RfcConnParams, 5, RfcErrInf)
if hRFC != None:

  charBuffer = create_unicode_buffer(512 + 1)

  hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "RFC_READ_TABLE", RfcErrInf)
  if hFuncDesc != 0:
    hFunc = SAP.RfcCreateFunction(hFuncDesc, RfcErrInf)
    if hFunc != 0:

      rc = SAP.RfcSetChars(hFunc, "QUERY_TABLE", TableName, \
        len(TableName), RfcErrInf)
      rc = SAP.RfcSetChars(hFunc, "DELIMITER", "~", 1, RfcErrInf)

      if SAP.RfcInvoke(hRFC, hFunc, RfcErrInf) == RFC_OK:

        hTable = c_void_p(0)
        if SAP.RfcGetTable(hFunc, "DATA", hTable, RfcErrInf) == RFC_OK:

          RowCount = c_ulong(0)
          rc = SAP.RfcGetRowCount(hTable, RowCount, RfcErrInf)
          rc = SAP.RfcMoveToFirstRow(hTable, RfcErrInf)
          for i in range(0, RowCount.value):
            hRow = SAP.RfcGetCurrentRow(hTable, RfcErrInf)
            rc = SAP.RfcGetChars(hRow, "WA", charBuffer, 512, RfcErrInf)
            print(charBuffer.value)
            if i < RowCount.value:
              rc = SAP.RfcMoveToNextRow(hTable, RfcErrInf)

      rc = SAP.RfcDestroyFunction(hFunc, RfcErrInf)

  rc = SAP.RfcCloseConnection(hRFC, RfcErrInf)

else:
  print(RfcErrInf.key)
  print(RfcErrInf.message)

del SAP

#-End-------------------------------------------------------------------

2017/04/24: I check the method above with Python release 3.6.1 x64 and with the SAP NetWeaver RFC library 721 PL42 x64 and it works perfect.

Assigned Tags

      16 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      It's nice meet another pythoner in this community(recently I'm studaying PyRFC from Srdjan Boskovi).

      As new comer,would you please explain more detail in your RFC_READ_TABLE,especially how to define fields that I want to load.I have try to FIELDS=['fields1','fields2','fields2'] and FIELDS=[['fields1'],['fields2'],['fields2']],neither successe.

      Best regards.

      Davis Han

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Davis,

      thanks for your reply. I am a newbie in Python, this is my really first Project - except this.

      The FM RFC_READ_TABLE has the following Interface:

      FUNCTION RFC_READ_TABLE.
      *"----------------------------------------------------------------------
      *"*"Local Interface:
      *"  IMPORTING
      *"     VALUE(QUERY_TABLE) LIKE  DD02L-TABNAME
      *"     VALUE(DELIMITER) LIKE  SONV-FLAG DEFAULT SPACE
      *"     VALUE(NO_DATA) LIKE  SONV-FLAG DEFAULT SPACE
      *"     VALUE(ROWSKIPS) LIKE  SOID-ACCNT DEFAULT 0
      *"     VALUE(ROWCOUNT) LIKE  SOID-ACCNT DEFAULT 0
      *"  TABLES
      *"      OPTIONS STRUCTURE  RFC_DB_OPT
      *"      FIELDS STRUCTURE  RFC_DB_FLD
      *"      DATA STRUCTURE  TAB512
      *"  EXCEPTIONS
      *"      TABLE_NOT_AVAILABLE
      *"      TABLE_WITHOUT_DATA
      *"      OPTION_NOT_VALID
      *"      FIELD_NOT_VALID
      *"      NOT_AUTHORIZED
      *"      DATA_BUFFER_EXCEEDED
      *"----------------------------------------------------------------------
      

      With RfcGetFunctionDesc you get the handle to the function description. Now you create with the RfcCreateFunction a data container. So you have access to the fields and tables of the interface. E.g. you can set the import parameter direct via RfcSetChars or you can get via RfcGetTable a data container to a table of the interface. With RfcAppendRow you can add an empty line and with RfcSetChars you can set the fields. On this way you can set each part of the interface of a FM. If you have a definite FM, we can explicate this example.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      Thanks for so prompt response.

      I think I'v found what I want in PyRFC:

      connecton.call('RFC_READ_TABLE',QUERY_TABLE='LFA1',FIELDS=[{'FIELDNAME':'MANDT'},{'FIELDNAME':'LAND1'}]) .

      Thanks again for you work.

      Regards

      Davis Han

      Author's profile photo Former Member
      Former Member

      Hi Stefan,

      Hope you are doing well 🙂

      Thank you for this post and I perceived that you have used the table - “USR01” which holds number of fields in single digit. If I am using the tables like “BUT000” which holds 50+ fields, the script is not extracting the data. I believe that we need to adjust the memory buffer value in “RfcGetChars” function, but this is not helping me. Could you please recommend a way to grip more records.

      Regards

      Ramesh

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Ramesh,

      thanks for your reply.

      The table BUT000 has 86 fields with a length of 1131. The function module RFC_READ_TABLE allows a maximum of 512 characters. If you call the function module with the table BUT000 you must get an DATA_BUFFER_EXCEEDED exception. You can find here a solution with an extended function module how to get 8192 characters - search for Z_RFC_READ_TABLE. The solution is over six years old, but it still works.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Good Day Stefan,

      Thank you for the clarification and its awesome.


      Now I got a condition, where I need to extract few fields like BPEXT, PARTNER, PERSNUMBER from BUT000, but the field BPEXT(Datatype – CHAR20) is passing null value and other fields are populating the values well.

      Even I tried to do the data type conversion in SAP and tried to import using RfcGetChars command, but no luck. Could you please suggest a solution for this.

      Below is the statement which I am using:

      hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "MY Function Module", RfcErrInf)

      if hFuncDesc != 0:

      hFunc = SAP.RfcCreateFunction(hFuncDesc, RfcErrInf)

      if hFunc != 0:

      rc = SAP.RfcSetChars(hFunc, "IV_ACCOUNT", acc_num, len(acc_num), RfcErrInf)

      if SAP.RfcInvoke(hRFC, hFunc, RfcErrInf) == RFC_OK:

      rc = SAP.RfcGetChars(hFunc, "EV_ACCOUNT", Export, 256, RfcErrInf) # This line is passing the values well

      rc = SAP.RfcGetChars(hFunc, "EV_IBT", Export1, 256, RfcErrInf) # This line is passing the null values

      rc = SAP.RfcGetChars(hFunc, "EV_SALES_PROD", Export, 256, RfcErrInf) # This line is passing the values well


      Regards

      Ramesh

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Ramesh,

      I tried it with the following RFC-enabled function module:

      FUNCTION Z_BUT000
        IMPORTING
          VALUE(I_PARTNER) TYPE BU_PARTNER
        EXPORTING
          VALUE(E_BPEXT) TYPE BU_BPEXT.
      
      SELECT SINGLE BPEXT FROM BUT000 INTO e_bpext WHERE partner = i_partner.
      
      ENDFUNCTION.

      and the following VBScript:

      '-Begin-----------------------------------------------------------------
      
        '-Directives----------------------------------------------------------
          Option Explicit
      
        '-Constants-----------------------------------------------------------
          Const RFC_OK = 0
      
        '-Variables-----------------------------------------------------------
          Dim SAP, hRFC, rc, hFuncDesc, hFunc, charBuffer
      
        '-Sub Main------------------------------------------------------------
          Sub Main()
      
            Set SAP = CreateObject("COMNWRFC")
            If Not IsObject(SAP) Then
             Exit Sub
            End If
      
            hRFC = SAP.RfcOpenConnection("ASHOST=NSP, SYSNR=00, " & _
              "CLIENT=001, USER=BCUSER")
            If hRFC = 0 Then
              Set SAP = Nothing
              Exit Sub
            End If
      
            hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "Z_BUT000")
            If hFuncDesc = 0 Then
              SAP.RfcCloseConnection(hRFC)
              Set SAP = Nothing
              Exit Sub
            End If
      
            hFunc = SAP.RfcCreateFunction(hFuncDesc)
            If hFunc = 0 Then
              SAP.RfcCloseConnection(hRFC)
              Set SAP = Nothing
              Exit Sub
            End If
      
            rc = SAP.RfcSetChars(hFunc, "I_PARTNER", "4711004711")
      
            If SAP.RfcInvoke(hRFC, hFunc) = RFC_OK Then
      
              rc = SAP.RfcGetChars(hFunc, "E_BPEXT", charBuffer, 20)
              MsgBox charBuffer
      
            End If
      
            rc = SAP.RfcDestroyFunction(hFunc)
            rc = SAP.RfcCloseConnection(hRFC)
            Set SAP = Nothing
      
          End Sub
      
        '-Main----------------------------------------------------------------
          Main
      
      '-End-------------------------------------------------------------------
      

      All works well and expected. I don't what is wrong in your case.

      What delivers RfcGetChars as return code? Delivers the error info structure information?

      Let us know your results.

      Cheers

      Stefan

      Author's profile photo Former Member
      Former Member

      Hello Stefan,

      Thank you for all your blogs, you are a real inspiration for automation.

      I could succesfully connect however I am failing to use the FM BAL_DB_SEARCH

      I want to use the I_S_LOG_FILTER, which is a structure that contains table. When I try to get the range ALDATE, I have the error message

      exception: access violation writing 0x0000000000000000

      Here is my code below

      	hRFC = SAP.RfcOpenConnection(RfcConnParams, 5, RfcErrInf)
      	if hRFC != None:
      		
      		charBuffer = create_unicode_buffer(256 + 1)
      		hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "BAL_DB_SEARCH", RfcErrInf)
      		hFunc = SAP.RfcCreateFunction(hFuncDesc, RfcErrInf)
      		
      		hStruct = c_void_p(0)
      		hTable = c_void_p(0)
      		
      		if SAP.RfcGetStructure(hFunc, "I_S_LOG_FILTER", hStruct, RfcErrInf) == RFC_OK:
      			print("I_S_LOG_FILTER")
      			
      			SAP.RfcSetChars(hFunc, "I_CLIENT", "100", 3, RfcErrInf)
      						
      			try: 
      				SAP.RfcGetTable(hStruct, "ALDATE", hTable, RfcErrInf)
      			except Exception as e: 
      					print(e)
      					

      Do you see anything wrong with my statements ?

      Author's profile photo Former Member
      Former Member

      I found the solution, I was missing some prototypes to make the appropriate calls.

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Quentin,

      thank you very much for your reply.

      Is it possible for you to post here the missing prototypes. On this way it is possible for other members of the community to add it to their prototype definition. Thanks a lot for this.

      Cheers
      Stefan

      Author's profile photo Raghavendran Ramasubramanian
      Raghavendran Ramasubramanian

      Hi Stephan,

       

      I'm trying to extract values from KNVV table using some filter conditions in SAP GUI, and now learning to use the SAP NW RFC python script to perform similar operation on the table KNVV, The table used in example is USR01 and if i try to modify it to KNVV and execute it doesn't work for me. Though I'm new to understand and use the SAP NW RFC python script provided , would like to know what can be fixed in the below code or the approach should be different while accessing different tables using this script.

       

      Any Help would be appreciated 🙂

       

      # -*- coding: iso-8859-15 -*-
      #-Begin-----------------------------------------------------------------
      
      #-Include---------------------------------------------------------------
      from ctypes import *
      
      from pysaf.util.sapnwrfc import SAP, RfcConnParams, RfcErrInf, RFC_OK
      
      FileName = "C:\\Users\\rrama3\\PycharmProjects\\pysaf_core\\pysaf\\util\\sapnwrfc.py"
      exec(compile(open(FileName).read(), FileName, "exec"))
      
      #-Main------------------------------------------------------------------
      
      #-Connection parameters-------------------------------------------------
      RfcConnParams[0].name = "ASHOST"; RfcConnParams[0].value = "sap-pte-pas.nike.com" # PTE
      RfcConnParams[1].name = "SYSNR" ; RfcConnParams[1].value = "00"
      RfcConnParams[2].name = "CLIENT"; RfcConnParams[2].value = "300"
      RfcConnParams[3].name = "USER"  ; RfcConnParams[3].value = "rrama3"
      RfcConnParams[4].name = "PASSWD"; RfcConnParams[4].value = "********"
      
      TableName = "KNVV"
      
      hRFC = SAP.RfcOpenConnection(RfcConnParams, 5, RfcErrInf)
      if hRFC != None:
      
        charBuffer = create_unicode_buffer(512 + 1)
      
        hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "RFC_READ_TABLE", RfcErrInf)
        if hFuncDesc != 0:
          hFunc = SAP.RfcCreateFunction(hFuncDesc, RfcErrInf)
      
          if hFunc != 0:
      
            rc = SAP.RfcSetChars(hFunc, "QUERY_TABLE", TableName, len(TableName), RfcErrInf)
            rc = SAP.RfcSetChars(hFunc, "DELIMITER", "~", 1, RfcErrInf)
            if SAP.RfcInvoke(hRFC, hFunc, RfcErrInf) == RFC_OK:
      
              hTable = c_void_p(0)
              if SAP.RfcGetTable(hFunc, "DATA", hTable, RfcErrInf) == RFC_OK:
      
                f = open("Output.txt", "w+")
                RowCount = c_ulong(0)
                rc = SAP.RfcGetRowCount(hTable, RowCount, RfcErrInf)
                rc = SAP.RfcMoveToFirstRow(hTable, RfcErrInf)
                for i in range(0, RowCount.value):
                  hRow = SAP.RfcGetCurrentRow(hTable, RfcErrInf)
                  rc = SAP.RfcGetChars(hRow, "WA", charBuffer, 512, RfcErrInf)
                  f.write(charBuffer.value + '\n')
                  if i < RowCount.value:
                    rc = SAP.RfcMoveToNextRow(hTable, RfcErrInf)
      
      
            rc = SAP.RfcDestroyFunction(hFunc, RfcErrInf)
      
        rc = SAP.RfcCloseConnection(hRFC, RfcErrInf)
      
      else:
        print(RfcErrInf.key)
        print(RfcErrInf.message)
      
      del SAP
      
      #-End-------------------------------------------------------------------
      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Raghavendran,

      this is not a problem of your Python code, RFM RFC_READ_TABLE can't read KNVV completly.

      This is exact the error which delivers the Python program after the invoke.

      Use the fields table to reduce the size of the data less than 512 characters.

      Append this code and your Python code works:

            hFields = c_void_p(0)
            rc = SAP.RfcGetTable(hFunc, "FIELDS", hFields, RfcErrInf)
            hRow = SAP.RfcAppendNewRow(hFields, RfcErrInf)
            rc = SAP.RfcSetChars(hRow, "FIELDNAME", "KUNNR", 5, RfcErrInf)
            hRow = SAP.RfcAppendNewRow(hFields, RfcErrInf)
            rc = SAP.RfcSetChars(hRow, "FIELDNAME", "VKORG", 5, RfcErrInf)

      Best regards
      Stefan

       

      Author's profile photo Raghavendran Ramasubramanian
      Raghavendran Ramasubramanian

      Hi Stephan,

      Thanks for your quick response, I tried providing the fields the reduce the buffer size while reading the KNVV table, getting a new issue “RFC_MEMORY_INSUFFICIENT”.

       

      Below are the things i'm trying to figure out as well -

      1. Read the Table (of any type from SAP using RFC) - KNVV etc.
      2. Provide Filter values to the fields for the table to reduce the outcome from the RFC_READ_TABLE (to make sure not to get MEMORY error or BUFFER error)

      Let me know if something else can be done to resolve this , also i'm trying to understand on how to provide filter values as we do in the front end SAP GUI for different fields.

      Current Issue Snapshot -

      Updated Code Snippet -

      # -*- coding: iso-8859-15 -*-
      #-Begin-----------------------------------------------------------------
      
      #-Include---------------------------------------------------------------
      from ctypes import *
      
      from pysaf.util.sapnwrfc import SAP, RfcConnParams, RfcErrInf, RFC_OK
      
      FileName = "C:\\Users\\rrama3\\PycharmProjects\\pysaf_core\\pysaf\\util\\sapnwrfc.py"
      exec(compile(open(FileName).read(), FileName, "exec"))
      
      #-Main------------------------------------------------------------------
      
      #-Connection parameters-------------------------------------------------
      RfcConnParams[0].name = "ASHOST"; RfcConnParams[0].value = "sap-pte-pas.nike.com" # PTE
      RfcConnParams[1].name = "SYSNR" ; RfcConnParams[1].value = "00"
      RfcConnParams[2].name = "CLIENT"; RfcConnParams[2].value = "300"
      RfcConnParams[3].name = "USER"  ; RfcConnParams[3].value = "rrama3"
      RfcConnParams[4].name = "PASSWD"; RfcConnParams[4].value = "**********"
      
      TableName = "KNVV"
      
      hRFC = SAP.RfcOpenConnection(RfcConnParams, 5, RfcErrInf)
      if hRFC != None:
        charBuffer = create_unicode_buffer(512 + 1)
        hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, "RFC_READ_TABLE", RfcErrInf)
        if hFuncDesc != 0:
      
          hFunc = SAP.RfcCreateFunction(hFuncDesc, RfcErrInf)
      
          if hFunc != 0:
      
            rc = SAP.RfcSetChars(hFunc, "QUERY_TABLE", TableName, len(TableName), RfcErrInf)
            rc = SAP.RfcSetChars(hFunc, "DELIMITER", "~", 1, RfcErrInf)
      
            hFields = c_void_p(0)
            rc = SAP.RfcGetTable(hFunc, "FIELDS", hFields, RfcErrInf)
            hRow = SAP.RfcAppendNewRow(hFields, RfcErrInf)
            rc = SAP.RfcSetChars(hRow, "FIELDNAME", "KUNNR", 5, RfcErrInf)
            hRow = SAP.RfcAppendNewRow(hFields, RfcErrInf)
            rc = SAP.RfcSetChars(hRow, "FIELDNAME", "VKORG", 5, RfcErrInf)
            hRow = SAP.RfcAppendNewRow(hFields, RfcErrInf)
            rc = SAP.RfcSetChars(hRow, "FIELDNAME", "VTWEG", 5, RfcErrInf)
            hRow = SAP.RfcAppendNewRow(hFields, RfcErrInf)
            rc = SAP.RfcSetChars(hRow, "FIELDNAME", "SPART", 5, RfcErrInf)
            if SAP.RfcInvoke(hRFC, hFunc, RfcErrInf) == RFC_OK:
      
              hTable = c_void_p(0)
      
              if SAP.RfcGetTable(hFunc, "DATA", hTable, RfcErrInf) == RFC_OK:
      
                f = open("Output.txt", "w+")
                RowCount = c_ulong(0)
                rc = SAP.RfcGetRowCount(hTable, RowCount, RfcErrInf)
                rc = SAP.RfcMoveToFirstRow(hTable, RfcErrInf)
                for i in range(0, RowCount.value):
                  hRow = SAP.RfcGetCurrentRow(hTable, RfcErrInf)
                  rc = SAP.RfcGetChars(hRow, "WA", charBuffer, 512, RfcErrInf)
                  f.write(charBuffer.value + '\n')
                  if i < RowCount.value:
                    rc = SAP.RfcMoveToNextRow(hTable, RfcErrInf)
      
      
            rc = SAP.RfcDestroyFunction(hFunc, RfcErrInf)
      
        rc = SAP.RfcCloseConnection(hRFC, RfcErrInf)
      
      else:
        print(RfcErrInf.key)
        print(RfcErrInf.message)
      
      del SAP
      
      #-End-------------------------------------------------------------------

       

      Author's profile photo Stefan Schnell
      Stefan Schnell
      Blog Post Author

      Hello Raghavendran,

      it seems that your KNVV table contains to many entries for the RFM. Please try the ROWCOUNT parameter of the RFM to reduce the data e.g. like this:

      rc = SAP.RfcSetChars(hFunc, "ROWCOUNT", "100", 3, RfcErrInf)

      On this way the RFM delivers the first 100 entries of the table.

      Let us know your results.

      Cheers
      Stefan

      Author's profile photo Raghavendran Ramasubramanian
      Raghavendran Ramasubramanian

      Hi Stephan,

       

      The ROWCOUNT worked for me as it got me only 100 records. I was also able to get the filtered out value for One Field (e.g. KUNNR) with multiple values (0000469612, 0000469613,0000469614) ?

       

      As providing filter values to a specific field/fields would get only filtered out data from SAP and would be helpful in my case.

      This is the current code snippet update -

      hOptions = c_void_p(0)
      if SAP.RfcGetTable(hFunc, "OPTIONS", hOptions, RfcErrInf ) == RFC_OK:
      hRow = SAP.RfcAppendNewRow(hOptions, RfcErrInf)
      rc = SAP.RfcSetChars(hRow, "TEXT","KUNNR = '0000469612'",len("KUNNR = '0000469612'"),RfcErrInf)
      rc = SAP.RfcSetChars(hFunc, "ROWCOUNT", "100", 3, RfcErrInf)

       

       

      Author's profile photo Martin Varbanov
      Martin Varbanov

      Hello Stefan,​

      I hope you can help me with date filters. I am using below script to extract few columns from CATSDB table.

      The scripts works well before adding the WORKDATE = 20150803 in the condition. There are records in CATSDB for 'PERNR = 00001111 AND STATUS = 30'  for that WORKDATE but the script returns no records after adding WORKDATE = 20150803.

      How to modify the code to correctly filter a signal date or a range of dates like 'WORKDATE >= 20150801' AND WORKDATE <= 20150831'?

      # you need to put a where condition in there... could be anything
      where = ['PERNR = 00001111 AND STATUS = 30 AND WORKDATE = 20150803']
      from pyrfc import Connection
      import re
      
      
      class main():
          def __init__(self):
              ASHOST='****'
              CLIENT='****'
              SYSNR='****'
              USER='****'
              PASSWD='****'
              self.conn = Connection(ashost=ASHOST, sysnr=SYSNR, client=CLIENT, user=USER, passwd=PASSWD)
          
          def qry(self, Fields, SQLTable, Where = '', MaxRows=50, FromRow=0):
              """A function to query SAP with RFC_READ_TABLE"""
      
      
              # By default, if you send a blank value for fields, you get all of them
              # Therefore, we add a select all option, to better mimic SQL.
              if Fields[0] == '*':
                  Fields = ''
              else:
                  Fields = [{'FIELDNAME':x} for x in Fields] # Notice the format
      
      
              # the WHERE part of the query is called "options"
              options = [{'TEXT': x} for x in Where] # again, notice the format
      
      
              # we set a maximum number of rows to return, because it's easy to do and
              # greatly speeds up testing queries.
              rowcount = MaxRows
      
      
              # Here is the call to SAP's RFC_READ_TABLE
              tables = self.conn.call("RFC_READ_TABLE", QUERY_TABLE=SQLTable, DELIMITER='|', FIELDS = Fields,
                                      OPTIONS=options, ROWCOUNT = MaxRows, ROWSKIPS=FromRow)
      
      
              # We split out fields and fields_name to hold the data and the column names
              fields = []
              fields_name = []
      
      
              data_fields = tables["DATA"] # pull the data part of the result set
              data_names = tables["FIELDS"] # pull the field name part of the result set
      
      
              headers = [x['FIELDNAME'] for x in data_names] # headers extraction
              long_fields = len(data_fields) # data extraction
              long_names = len(data_names) # full headers extraction if you want it
      
      
              # now parse the data fields into a list
              for line in range(0, long_fields):
                  fields.append(data_fields[line]["WA"].strip())
      
      
              # for each line, split the list by the '|' separator
              fields = [x.strip().split('|') for x in fields ]
      
      
              # return the 2D list and the headers
              return fields, headers
      
      # Choose your fields and table
      fields = ['PERNR', 'WORKDATE', 'STATUS', 'CATSHOURS'] 
      table = 'CATSDB' 
      
      # you need to put a where condition in there... could be anything
      where = ['PERNR = 00001111 AND STATUS = 30 AND WORKDATE = 20150803']
      
      # max number of rows to return
      maxrows = 2000
      
      # starting row to return
      fromrow = 0
      
      # query SAP
      results, headers = s.qry(fields, table, where, maxrows, fromrow)
      
      print(headers)
      print(results)