March 25, 2015

Dynamic code generation in ABAP

Recently I discovered an excellent feature in ABAP which has helped me a lot in a requirement I had. This feature is the capacity to generate dynamic code and execute it in your program. As far as I know is possible to generate forms, classes and even programs.

My requirement needed to basically copy an SQL to create a special output. Following the DRY principle I didn't want to duplicate code. I wanted to use a parameter to change a portion of the SQL and get a dataset.

After some research I found this excellent feature which allows me to use a common procedure to manage any table and handle that data. 

Let's code an example:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
report  zdynamic.

tables mara.

data: gt_output type standard table of mara,
      wa_output like line of gt_output,
      gt_output2 type standard table of marc,
      wa_output2 like line of gt_output2.

select-options so_matnr for mara-matnr.

start-of-selection.

  write / 'MARA'. " Generate output for table 'MARA'
  perform create_dataset tables gt_output so_matnr using 'mara'.
  loop at gt_output into wa_output.
    write: / wa_output-matnr, wa_output-meins.
  endloop.

  write: /, /, 'MARC'. " Generate output for table 'MARC'
  perform create_dataset tables gt_output2 so_matnr using 'marc'.
  loop at gt_output2 into wa_output2.
    write: / wa_output2-matnr, wa_output2-maabc.
  endloop.

*&---------------------------------------------------------------------*
*&      Form  create_dataset
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
*      -->P_OUTPUT   Result table
*      -->P_SELECT   Search parameter
*      -->P_TABLE    Table name
*----------------------------------------------------------------------*
form create_dataset tables p_output p_select using p_table type string.
  data: it_source type standard table of string with header line, " Structure that will hold the program to be generated
        lv_program type string, " The name of the program
        lv_error type string.  " The error in generation

  it_source = 'report create_dataset.'.
  append it_source.
  it_source = 'form execute tables p_output s_matnr.' .
  append it_source.
  it_source = 'select * from '.
  append it_source.
  it_source = p_table.
  append it_source.
  it_source = ' up to 10 rows into corresponding fields of '.
  append it_source.
  it_source = ' table p_output'.
  append it_source.
  it_source = 'where matnr in s_matnr.'.
  append it_source .
  it_source = 'endform.'.
  append it_source.

  generate subroutine pool it_source
           name lv_program
           message lv_error. " Generate the program. Here is where magic happens.

  if sy-subrc eq 0.
    write: / 'Program name:', lv_program.
    perform execute in program (lv_program) tables p_output p_select if found.
  else.
    write: / 'Error ocurred', lv_error.
    write sy-subrc.
  endif.
  write /.
endform.                    "create_dataset

The objective here is to read data from different tables. We will send a table name as a parameter to a form and generate ABAP code to execute it.

The form 'create_dataset' is the place where the generation happens. As we debug the code you can see that the internal table 'it_source' has the generated source code that is constructed using the parameter 'p_table'.



After that, the source code is compiled and a program is generated using the following statement:

1
2
3
generate subroutine pool it_source
         name lv_program
         message lv_error.

If everything works the following data is produced:

LV_PROGRAM = "%_T00O4R" (This name changes when generated)
LV_ERROR = Blank if compilation is succesful.


As I wanted to print different outputs with different data I just send the table name as the parameter and let SAP construct the subroutine for me.

What happens if the code is wrong and there are compilation errors? The answer is that nothing happens, there will be no dump, at least not at this stage. When an error happens in the code you will get the description of that exception in the 'message' parameter and SY-SUBRC will have the value '4' or '8'.

According to SAP documentation, SY-SUBRC will have one of the following values:

0 Generation was successful.
4 Source code contains a syntax error.
8 A generation error occurred.

The last part is check the value of SY-SUBRC and call the generated program, sending  the parameters as defined in the code.

1
perform execute in program (lv_program) tables p_output p_select using p_table if found.

Remember that the parameters must match with the form otherwise you'll get a dump.

The output of the program is the following:


In summary this great feature helped me a lot and the most important part of this is that it let me save code. Code that you don't write is code that you don't need to debug.

For better reference on this issue check this link.

See you in the next. Hope it helps.
Please Share it! :)

2 comments :

  1. Hi,

    Thanks for sharing a practical example but this requirement doesn't need to be solved by using dynamic program generation. It can be solved by Run Time Type Creation. Dynamic program generation has its downside such as security risk & performance issues. It should be used as the last option when other RTTI & RTTC methods can't solve your problem. Please check the following link.
    https://help.sap.com/abapdocu_731/en/abengeneric_progr_guidl.htm

    ReplyDelete
  2. Thanks for your comment, your're absolutely right, I'll comment in what circumstances we could use this solution. As you wrote it's just an example.

    ReplyDelete