Anthony Cecchini is the President of Information Technology Partners (ITP), an SAP consulting company headquartered in Pennsylvania. ITP offers comprehensive planning, resource allocation, implementation, upgrade, and training assistance to companies. Anthony has over 20 years of experience in SAP R/3 business process analysis and SAP systems integration. His areas of expertise include SAP NetWeaver integration; ALE development; RFC, BAPI, IDoc, Dialog, and Web Dynpro development; and customized Workflow development. You can reach him at [email protected].
ABAP Dynamic Programming Techniques
OK, lets pick up from last month where I promised we would look at how to create a Dynamic Where clause for our OPEN SQL. Before we start diving into this, I want to give you a little context about “Tokens”. No No, not the kind you use for the subway! What are Tokens in ABAP? Lets go right to the help for an ABAP Tutorial!
ABAP Statements
ABAP statements consist of the following tokens and end with a period (.).
– ABAP words
– Operands
– Operators
Certain ABAP words, operands and operators form
which can be specified at certain operand positions.
The tokens of a statement must be separated by at least one blank or a line break. Otherwise, blanks and line breaks between tokens are not significant. An ABAP statement is not restricted to a line in the source text.
No distinction is made between upper and lowercase letters. Apart from ABAP words, operands and operators, you can also use the following special characters:
– If a number of expressions of the same type with operators are linked to an expression, the priority of the individual operations can be defined usig round brackets (()).
– For the purpose of calling functions and methods, round brackets (()) can sometimes be used.
– Lists of operands are expressed by round brackets (()) and commas (,) in certain positions.
– When forming a chained statement, a colon (:) and commas (,) can be used.
A number of free-standing special characters, such as round brackets for setting the priority, need to be separated from other tokens by an empty character. Other special characters – as well as the period at the end – do not have to be separated by an empty character.
Example
ABAP statement with the keyword DELETE, the addition WHERE, the operators =, <, >, AND, OR, the operands itab, col1, op1, col2, op2, col3, op3and round brackets.
DELETE itab WHERE ( col1 = op1 AND ( col2 > op2 OR col3 < op3 ) ).
Now that we understand what a Token is, we can see the WHERE Clause has tokens in it, but so do other ABAP statements. So instead of focusing on just a Dynamic Where Clause, let broaden the discussion to DYNAMIC TOKENS in ABAP.
Dynamic Token Specification
Most ABAP statements allow you to specify some part of the statement dynamically. Essentially, this means you can supply various components of ABAP statements at runtime with a common syntax (see help above). The best way to understand this concept is via an example: Suppose you have an internal table, which must have a specified sort order. The name of the component to be used for sorting the internal table could be specified at runtime and stored in either a character field or string. Dynamic token specification is the technique you would use to meet this requirement. Take a look at the code below.
* dynamic sort name = 'SSN'. SORT itab BY (name). * static sort SORT itab BY SSN.
First, the name of the component to use for sorting the internal table ITAB is stored in the string variable NAME at runtime. According to syntax rules for a dynamic statement, you must write the component name in capital letters. Instead of statically specifying the component name in the SORT statement, the string variable containing the component name is specified in parentheses, with no spaces between the variable name and the parentheses. So now you can compare the dynamic statement with its static counterpart, at the end of the example above.
The best way to conceptualize dynamic token specification is to think of it as a replacement. The statement is completed at runtime by replacing the variable in parentheses with its value. In the example above, (name) is replaced by ssn.
Clearly, using dynamic token specification is both valuable and powerful. However, be aware of the consequences of being unable to determine the ABAP statement at compile time:
- No static type check or syntax check is performed for the dynamic parts of a statement.
- Runtime errors can occur if the dynamic statement is not valid when completed.
ABAP offers five forms of dynamic token specification, each of which is intended for a specific part of a program statement:
- Dynamic field specification contains the name of a field. The field for an ASSIGN statement, which should be assigned to a field symbol, can be specified dynamically. (We have seen examples of this in earlier blogs of this series)
- Dynamic type specification contains the name of a type. The type for CREATE DATA can be specified dynamically. (We have seen examples of this in earlier blogs of this series)
- Dynamic component specification contains the name of a component of a structure, such as the sort order for an internal table. (this was our example at the start of this blog)
- Dynamic clause specification contains a whole part of a statement. For example, all clauses of the Open SQL statement SELECT can be specified dynamically. In this case, the variable must be an internal table of character fields. (you will se examples of this shortly)
- Dynamic subroutine specification contains the name of a subroutine. Methods, functions, forms, programs, and transactions can be called dynamically.
Using Dynamic Tokens, Field Symbols, Clauses and References
Now let’s see how you would use dynamic tokens in the real world. In little program below, dynamic token specification, field symbols, and data references are used to implement a display program for any database table. It also illustrates using a WHERE clause as an input parameter. Take a look below….
*&---------------------------------------------------------------------* *& Report dynamic_select_example *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* PROGRAM dynamic_select_example. PARAMETER: p_from(30) TYPE c DEFAULT 'T001L', p_where(255) TYPE c DEFAULT 'WERKS = ''PL01'' AND LGORT = ''SL01'' '. *----------------------------------------------------------------------* * CLASS lcl_util DEFINITION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_util DEFINITION. PUBLIC SECTION. CLASS-METHODS: write_struct IMPORTING p_struct TYPE any. ENDCLASS. "lcl_util DEFINITION *----------------------------------------------------------------------* * CLASS lcl_util IMPLEMENTATION *----------------------------------------------------------------------* * *----------------------------------------------------------------------* CLASS lcl_util IMPLEMENTATION. METHOD write_struct. FIELD-SYMBOLS: <field> TYPE any. WRITE / '('. DO. ASSIGN COMPONENT sy-index OF STRUCTURE p_struct TO <field>. IF sy-subrc <> 0. EXIT. ENDIF. WRITE /4 <field>. ENDDO. WRITE / ')'. ENDMETHOD. "write_struct ENDCLASS. "lcl_util IMPLEMENTATION DATA: data_ref TYPE REF TO data, where_tab LIKE TABLE OF p_where. FIELD-SYMBOLS: <line> TYPE any. START-OF-SELECTION. CREATE DATA data_ref TYPE (p_from). ASSIGN data_ref->* TO <line>. APPEND p_where TO where_tab. SELECT * FROM (p_from) INTO <line> WHERE (where_tab). CALL METHOD lcl_util=>write_struct EXPORTING p_struct = <line>. ENDSELECT.
This program takes a database table name and a WHERE clause as input parameters. The parameters are initialized with values for the database table T001L. (Note that T001L is just an example; you could use any table.) Lets dissect the code and see what we are doing…
First, an appropriate work area is created with dynamic type specification using the name of the database table. For every database, a corresponding ABAP structure type with the same name exists. The field symbol <LINE> is used to access the work area. Because the WHERE clause demands a table for dynamic clause specification, the parameter P_WHERE is converted into a table WHERE_TAB. The SELECT loop, which contains the dynamic specification of the database table name and the WHERE clause, retrieves the entries from the database. Every retrieved entry is written to the ABAP List by the method WRITE_STRUCT of the class LCL_UTIL. (Refer back to the ABAP Dynamic Programming blog on field symbols if you need a reminder of how some of this code works.)
Her is another example of generating a Dynamic Where clause on the SPFLI fight table. The static and dynamic parts of the WHERE clause are combined at runtime and sent to the database as a single clause. Any mixture of static and dynamic parts is allowed, as long as every single dynamic fragment represents a logical condition. Please note I am using the SELECT-END_SELECT construct for speed of construction.
*&---------------------------------------------------------------------* *& Report dynamic_where_example *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------* REPORT dynamic_where_example. PARAMETERS: depart TYPE spfli-cityfrom, arrive TYPE spfli-cityto, op_and RADIOBUTTON GROUP 1 DEFAULT 'X', op_or RADIOBUTTON GROUP 1. DATA: where_tab TYPE TABLE OF edpline, source_line TYPE edpline, operator(3) TYPE c VALUE 'AND', carrid TYPE spfli-carrid, connid TYPE spfli-connid. IF op_or = 'X'. operator = 'OR'. ENDIF. CONCATENATE 'cityfrom = ''' depart '''' INTO source_line. APPEND source_line TO where_tab. APPEND operator TO where_tab. CONCATENATE 'cityto = ''' arrive '''' INTO source_line. APPEND source_line TO where_tab. SELECT carrid connid cityfrom cityto FROM spfli INTO (carrid, connid, depart, arrive) WHERE (where_tab). WRITE: / carrid, connid, depart, arrive. ENDSELECT.
You now know how to access or operate on data dynamically. In the next blog I’ll explain what is required when you need to get information at runtime about data that is passed with generic types. using RTTI. Runtime Type Identification (RTTI) is a powerful technique for obtaining all information about a data type at runtime.