Skip to Content
Author's profile photo Juwin Pallipat Thomas

Dynamic IF Condition

We all have heard about dynamic conditions in WHERE clauses (Dynamic where clause – ABAP Development – SCN Wiki), dynamic READ statements (Dynamic WHERE in READ TABLE | SCN), dynamic internal tables/ structures/ ALV (Tutorial abap – Code for Dynamic Alv grid – Code Gallery – SCN Wiki), in short dynamic programming (Dynamic Programming –  Application Development on AS ABAP – SAP Library)…

But, when I searched about dynamic conditions in IF statement, I couldn’t find many hits. Some of the hits said, it was not possible, some said to use ranges, and some others said it required dynamic subroutine generation etc.

I have used EVAL_FORMULA function module before (Program to evaluate formula in a string – ABAP Development – SCN Wiki). But, I haven’t had much success with TEXT operations, using this function module.

So, I am here to discuss a method to achieve dynamic IF conditions in ABAP.

Interfaces used:

IF_FOBU_CONNECTOR

IF_FOEV_CONNECTOR

Classes used:

CL_FOBU_FORMULA – Formula Builder

CL_FOEV_FORMULA – Formula Evaluator

This same method can be used to evaluate dynamic formulae, just by changing the return type of the method. Since, I have used return type as BOOLEAN, I expect a TRUE or FALSE value to be returned by the method.

Global Class ZCL_EVALUATE_DYNAMIC_CONDITION:

    1  class zcl_evaluate_dynamic_condition definition

    2    public

    3    final

    4    create public .

    5 

    6    public section.

    7 

    8      interfaces if_fobu_connector .

    9      interfaces if_foev_connector .

   10 

   11      types:begin            of   ty_field_values .

   12      types name             type string.

   13      types data             type ref to data.

   14      types type             type string.

   15      types end              of   ty_field_values .

   16      types:tyt_field_values type standard table

   17            of ty_field_values with non-unique key table_line .

   18 

   19      class-methods factory

   20        returning

   21          value(rv_evaluator) type ref to zcl_evaluate_dynamic_condition .

   22      methods calculate

   23        importing

   24          value(it_dictionary) type tyt_field_values

   25          value(iv_formula)    type string

   26        returning

   27          value(rv_value)      type boolean .

   28    protected section.

   29    private section.

   30 

   31      data    dictionary       type tyt_field_values .

   32  endclass.

   33 

   34  class zcl_evaluate_dynamic_condition implementation.

   35 

   36    method calculate.

   37      data: lr_env     type ref to if_foev_connector,

   38            lr_fenv    type ref to if_fobu_connector,

   39            lr_formula type ref to cl_fobu_formula,

   40            lr_runtime type ref to cl_foev_formula.

   41 

   42      dictionary      =  it_dictionary.

   43      lr_env          ?= me.

   44      lr_fenv         ?= me.

   45      cl_fobu_formula=>create(

   46        exporting

   47          im_tech_names   = abap_true

   48          im_environment  = lr_fenv

   49          im_desired_type = ‘BOOLEAN’ “<<<<<

                 “Change this return type to use for other purposes

   50          io_fobu_storage = cl_fobu_storage=>get_instance( )

   51        importing

   52          ex_formula      = lr_formula ).

   53      lr_formula->parse( iv_formula ).

   54      lr_runtime       = cl_foev_formula=>load_from_fobu(

   55                           im_formula     = lr_formula

   56                           im_environment = lr_env ).

   57      data(lv_resuld)  = lr_runtime->evaluate( ).

   58      assign lv_resuld->* to field-symbol(<res>).

   59      rv_value         = <res>.

   60    endmethod.

   61 

   62    method factory.

   63      create object rv_evaluator.

   64    endmethod.

   65 

   66    method if_fobu_connector~check.

   67    endmethod.

   68 

   69    method if_fobu_connector~get.

   70    endmethod.

   71 

   72    method if_fobu_connector~get_all_operands.

   73    endmethod.

   74 

   75    method if_fobu_connector~parse_op_get.

   76      read table dictionary into data(meaning)

   77           with key name = ch_tech_name.

   78      if sy-subrc eq 0.

   79        ex_type  = meaning-type.

   80        ex_token = cl_fobu_formula=>c_token_appl_1.

   81      endif.

   82    endmethod.

   83 

   84    method if_fobu_connector~pushbuttons_get.

   85    endmethod.

   86 

   87    method if_fobu_connector~pushbutton_op_get.

   88    endmethod.

   89 

   90    method if_foev_connector~evaluate.

   91      read table dictionary into data(meaning)

   92           with key name = im_fieldname.

   93      if sy-subrc eq 0.

   94        assign meaning-data->* to field-symbol(<fld>).

   95        create data re_result like <fld>.

   96        assign re_result->* to field-symbol(<res>).

   97        <res> = <fld>.

   98      else.

   99        raise exception type cx_foev_formula_invalid

  100          exporting

  101            textid = |{ im_fieldname } field was not found in dictionary|.

  102      endif.

  103    endmethod.

  104  endclass.

Explanation:

  • IF_FOBU_CONNECTOR~PARSE_OP_GET helps in specifying the field types and token type, based on DICTIONARY entries.
  • IF_FOEV_CONNECTOR~EVALUATE helps in converting the fieldnames into values, based on the DICTIONARY entries.
  • LT_FIELDVALUES holds the values of all possible fields that may be used in the formula. Here, since I already know what are the fields used in my formula, I am passing only these values. This is stored in the DICTIONARY, so that the above methods may use it.
  • In the code below, I am passing a constant formula to the method, but purpose of this method is to analyze any dynamic text formula.

Example usage:

    1  class zcl_evaluate_dynamic_condition

    2        definition load.

    3  try.

    4    data:lt_fieldvalues

    5      type zcl_evaluate_dynamic_condition=>tyt_field_values.

    6    lt_fieldvalues = value #( ( name = ‘PLAAB’

    7                              type = ‘MDPS-PLAAB’

    8                              data = ref #( gs_mdps-plaab ) )

    9                            ( name = ‘DELKZ’

   10                              type = ‘MDPS-DELKZ’

   11                              data = ref #( gs_mdps-delkz ) )

   12                            ( name = ‘LIFNR’

   13                              type = ‘MDPS-LIFNR’

   14                              data = ref #( gs_mdps-lifnr ) )

   15                            ( name = ‘PLUMI’

   16                              type = ‘MDPS-PLUMI’

   17                              data = ref #( gs_mdps-plumi ) ) ).

   18 

   19    if zcl_evaluate_dynamic_condition=>factory( )->calculate(

   20      iv_formula     = |PLAAB = ’02’ AND DELKZ = ‘BB’

                            AND LIFNR <> ” AND PLUMI = ‘-‘|

   21      it_fieldvalues = lt_fieldvalues ) = abap_true.

   22      continue.

   23    endif.

   24  catch cx_root.

   25  endtry.

Assigned Tags

      4 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      Hello Juwin,

      thanks for taking the time to explain how to use the build in ABAP formula builder/interpreter.  I have started checking how it is used in the system to add functional extension to the language.

      Note this can also be done with A Lisp interpreter in ABAP. Due to LISP nature, a simpler interpreter can run complex programs. I will suggest that this version has more features than the demo report SFBE_EXAMPLE6.

      best regards,

      JNN

      Author's profile photo Juwin Pallipat Thomas
      Juwin Pallipat Thomas
      Blog Post Author

      Isn't that a little more complex? Or, I am understanding it incorrectly?

      Thanks,

      Juwin

      Author's profile photo Jacques Nomssi Nzali
      Jacques Nomssi Nzali

      OK, you first have to learn ABAP LISP syntax, but in the end it is actually simpler.

      I would convert your example to this:

      ; Define fields

      (define PLAAB (ab-data "GS_MDPS-PLAAB" ))

      (define DELKZ (ab-data "GS_MDPS-DELKZ" ))

      (define LIFNR (ab-data "GS_MDPS-LIFNR" ))

      (define PLUMI (ab-data "GS_MDPS-PLUMI" ))

      ; test

      (and (= PLAAB '02') (= DELKZ 'BB') (> LIFNR '') (= PLUMI '-'))

      Assuming GS_MDPS is defined and you put this in the string variable code, you could now execute:

        DATA(response) = NEW lcl_lisp_interpreter( )->eval_source( code ).

      So it is different yes but certainly not more complex.

      regards,

      JNN

      Author's profile photo Sercan Küçükdemirci
      Sercan Küçükdemirci

      Hello, i am in need of similar thing, trying to evaluate your code but it is always giving me error

      No constant can be used here SFB528

       

      I am just testing it with code below

       

      DATA:lt_fieldvalues TYPE zcl_test=>tyt_field_values.
      DATA: BEGIN OF gs_data,
              matnr TYPE mara-matnr,
              maktx TYPE makt-maktx,
              mtart TYPE mara-mtart,
              meins TYPE mara-meins,
            END OF gs_data.
      
      DATA: lv_bool TYPE boolean.
      lt_fieldvalues = VALUE #( ( name = 'MATNR'
                                type = 'MARA-MATNR'
                                data = REF #( gs_data-matnr ) )
                              ( name = 'MTART'
                                type = 'MARA-MTART'
                                data = REF #( gs_data-mtart ) )
                              ( name = 'MEINS'
                                type = 'MARA-MEINS'
                                data = REF #( gs_data-meins ) ) ).
      
      SELECT SINGLE *
        FROM mara AS a
        LEFT JOIN makt AS b ON b~matnr EQ a~matnr
                           AND b~spras EQ @sy-langu
        INTO CORRESPONDING FIELDS OF @gs_data.
      
      zcl_test=>factory( )->calculate(
        EXPORTING
          it_dictionary = lt_fieldvalues
          iv_formula    = |MATNR = 'TEST' AND MTART = 'TEST' AND MEINS = 'KG'|
        RECEIVING
          rv_value      = lv_bool
      ).