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 17 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
This will be the final post in this series on ABAP Dynamic Programming, but it’s a doozy! Let’s set the stage, suppose most, if not all, of the information you need to write a particular subroutine or program is available only at runtime. For instance, you want to develop a utility for migrating legacy data. In situations like this, where the data structures are unknown and must be created at runtime, program generation and execution may be your only option.
Program code generation is considered to be the highest level of dynamic programming because the source code is created at runtime and all ABAP features can be used independently of input parameters. But, please be aware that this is an expensive and difficult option. The code to generate programs dynamically is very complex and hard to maintain. If you adopt this approach, you still have choices to make. ABAP supports two types of runtime program generation — transient and persistent.
Transient Program Code Generation
In ABAP, you can generate programs at runtime and execute them. To generate a program, the source code must be created at runtime. The source code is then passed to special ABAP commands that generate and execute the program. You have two options for generating a program during runtime. The difference between them is the lifetime of the generated program. Transient code generation means that the generated program exists only as long as the internal mode exists. When the internal mode is finished, all transient generated programs are deleted. Persistent code generation means that the generated program is stored permanently in a database (until you delete it). Generating code at runtime is typically used for handling dynamic data. It is possible to generate very efficient programs for special data at runtime. However, be aware of the following disadvantages: (1) Generating a program at runtime is very time consuming and memory-intensive. (2) Generated programs are hard to debug. (3) There are no static checks or scans (such as scanning for the use of critical ABAP commands in a system) for programs that are generated at runtime. (4) Generated programs are not fully supported by the ABAP Workbench (e.g., there is no Where-Used list available). (5) Special services, such as the connection to the Transport Organizer, have to be implemented manually. The above caveats aside, the general rule should be obvious: do not generate programs unless you have no other option. One exception is working with Open SQL, as not all of its constructs support dynamic features. Please check SAP help for a complete list. OK, a transient-generated program is called a subroutine pool. Subroutine pools cannot be called directly, and you can only call forms in a subroutine pool. In addition, there is a maximum limit of subroutine pools per internal mode. Lets see how to generate a subroutine pool and execute a form in it! Take a look at the code below…
PROGRAM subroutine_pool_example. TYPES: source_line(72) TYPE c. DATA: src TYPE TABLE OF source_line, prog_name(30) TYPE c, msg(120) TYPE c, line(10) TYPE c, word(10) TYPE c, off(3) TYPE c. APPEND 'PROGRAM SUBPOOL.' TO src. APPEND 'FORM DYN1.' TO src. APPEND ' WRITE / ''Hello, I am FORM DYN1!''.' TO src. APPEND 'ENDFORM.' TO src. GENERATE SUBROUTINE POOL src NAME prog_name MESSAGE msg LINE line WORD word OFFSET off. IF sy-subrc <> 0. WRITE: / 'Error during generation in line', line, / msg, / 'Word:', word, 'at offset', off. ELSE. PERFORM dyn1 IN PROGRAM (prog_name). ENDIF.
The program generates a subroutine pool with the form DYN1 and executes the form. First, the source code is built and stored in an internal table with a mandatory line type of 72 characters. Every line in the internal table SRC represents one line of ABAP source code. The form DYN1 contains only one command, which writes the text Hello, I am FORM DYN1! to the ABAP List. The command GENERATE SUBROUTINE POOL generates a subroutine pool from the internal table SRC and publishes it for the internal mode. The program name PROG_NAME is an output parameter. The command GENERATE SUBROUTINE POOL generates a unique name for every generated subroutine pool, which is used to call a special form. If a syntax error occurs while the subroutine pool is being generated, the output parameters MSG, LINE, WORD, and OFFS are set appropriately so you can find the error in the code. The SY-SUBRC is set to greater than zero if an error was detected during the generation. Persistent code generation is somewhat more complex than transient code generation. Let’s look at that option now.
Persistent Program Code Generation
Persistent code generation has most of the same advantages and disadvantages as transient code generation. However, you can call persistent programs directly, and there is no limit to the number of generated programs within an internal mode. Be aware that persistent code generation is even more time-consuming and memory-intensive than transient code generation. It involves selected database operations (such as insert report and update report) to achieve the persistence of the generated program. However, it does have one advantage over transient code generation: the program is available to all programs within all SAP application servers of an SAP system, not only for the internal mode from which it was generated. Thus you might want to use this method if the program will be used by more than one application server, or if it will be used more than once. Lets see how a persistent program is generated and executed. PLEASE NOTE that the program still exists after the end of the execution of the generating program. You must explicitly delete persistent generated programs with the ABAP command DELETE REPORT. Take a look at the code below…
PROGRAM generate_program_example. TYPES: source_line(72) TYPE c. DATA: src TYPE TABLE OF source_line, msg(120) TYPE c, line(10) TYPE c, word(10) TYPE c, off(3) TYPE c. CONSTANTS: prg_name(30) VALUE 'ZDYNGENPGM1'. APPEND 'PROGRAM ZDYNGENPGM1.' TO src. APPEND 'WRITE / ''Hello, I am dynamically created!''.' TO src. INSERT REPORT prg_name FROM src. GENERATE REPORT prg_name MESSAGE msg LINE line WORD word OFFSET off. IF sy-subrc <> 0. WRITE: / 'Error during generation in line', line, / msg, / 'Word:', word, 'at offset', off. ELSE. SUBMIT (prg_name) AND RETURN. ENDIF.
Walking thru the code, first the program source is created and stored in the internal table SRC. The special command INSERT REPORT inserts the program into the program database table of the SAP application server. The command GENERATE REPORT generates a program that already exists in the program database table. You choose the program name, which must be a standard program name as in the ABAP Workbench. Any existing programs are overwritten. The command SUBMIT executes the program, the name of which must be passed as a parameter. The AND RETURN statement causes the starting program to resume after the execution of the submitted program.
So in closing, program generation is the most powerful and flexible method of dynamic programming. The downside is that these programs are very expensive to create and difficult to maintain. Program generation should always be your last resort for solving a design problem. We now have discussed all the important concepts needed for dynamic programming in ABAP. We began with techniques for accessing data dynamically, starting with generic types and proceeding to the dynamic data types of internal tables and strings. Next, we explored techniques for executing operations dynamically using various forms of dynamic token specification. Then we have discussed using RTTI for dynamically obtaining parameter characteristics. As a last resort, a really, really, last resort, we discussed dynamic Source Code Generation and execution. Thats right, build a subroutine or entire program at run-time and execute it.