Skip to Content

ABAP News for Release 7.40 – New Internal Table Functions

The most important news for internal tables are the Table expressions that allow the same single line access as the READ TABLE statement. But soon after those were available, the question arised “What about the system fields?”.

We all use the well known patterns


IF sy-subrc = 0.




DATA(idx) = sy-tabix.

Since an expression should be free of side effects it especially should not influence any system field. So what about these patterns?

The answer comes in form of two new built-in functions.

Line existence

A new predicate function that returns true if a line exists:

IF line_exists( itab[ … ] ).


Where itab[ … ] is a table expression that works here like READ TABLE … TRANSPORTING NO FIELDS.

(Note that we have already some other predicate functions in ABAP: matches and the contains-variants in the context of string processing).

Line index

A new table function that returns the number of the line in the index used (primary or secondary index):

DATA(idx)= line_index( itab[ … ] ).

Where itab[ … ] is a table expression that works here like READ TABLE … TRANSPORTING NO FIELDS. If no line is found, the value 0 is returned. For Hash-Tables or hashed secondary keys, always the value -1 is returned.

(Note that this is the second table function in ABAP. The other one is lines).

You must be Logged on to comment or reply to a post.
    • This old question ...


      A Boolean data type is in discussion, planned since I am in  the ABAP group - and this is quite a time. To be honest, I can't fullly explain why it isn't done yet. One reason can be that any introduction of a new built-in type is dangeroius for compatibility. If we introduce a type named "boole" or "boolean" you will have naming collisions with self defined types in ABAP programs or in the Dictionary of that name. We made that experience recently with int8. int8 could be introduced in the NGAP release (8.x) because this ABAP release is not downward compatible. But up to now int8 did not find its way into 7.40.


      For the time being you still have two work with type c length 1 aka abap_bool with values abap_true and abap_false as workaround. The Boolean functions boolc and boolx also support this access.


      But since you will participate in our TechEd session as a mentor this year, you will very probalbly have the chance to discuss that with us directly

  • Hi Horst,


    For moving data from one Internal Table to another, of same type,

    we are having a handy option,


    itab_1[] = itab_2[].


    But the we do not have any similar syntax, to move data from

    one Internal Table to another, of different type, as we have

    for work areas ,


    move-corresponding ls_tab_1 to ls_tab_2.


    Just wondering,

    why can not we have such function even for Internal Tables,

    or else if we do already have some similar syntax,

    please post.


    Thanking You All.

  • Hello Horst,


    which idiom would recommend for the ubiquitous SY-SUBRC check after a READ TABLE ?


           rv_msg = mt_return[ 1 ]-message.

           CATCH cx_sy_itab_line_not_found.

             CLEAR rv_msg.



    IF line_exists( mt_return[ 1 ] ).

       rv_msg = mt_return[ 1 ]-message.


      CLEAR rv_msg.



    or anything else?





    • Before 7.40, SP08 you only have the above two and I would recommend line_exists.


      With 7.40, SP08 there will be


      VALUE #( mt_return[ 1 ]-message DEFAULT def ) and

      VALUE #( mt_return[ 1 ]-message OPTIONAL )


      For non-existing lines you can define your own default value and check the result for that one.


      rv_msg = VALUE #( mt_return[ 1 ]-message DEFAULT def ).

      IF rv_msg = def.




      Or in your case above, you simply denote the initial value a follows:


      rv_msg = VALUE #( mt_return[ 1 ]-message OPTIONAL ).





  • Hello Horst,


    what is the differene between a table function and a functional operand? e.g. error message Arithmetic calculation not permitted here is triggered for


         MESSAGE s542(>4) WITH lines( mt_data[] ).

    I can use


    DATA(lv_count) = lines( mt_data[] ).

         MESSAGE s542(>4) WITH lv_count

    but it is legal to write

    MESSAGE s035(mv) WITH lo_stream->get_filename( ).

    so why can't I use a table function in an expression at a functional operand position? It seems to me it works in some contexts, but I could not find a reference yet.



    • Hi Jacques,


      Unfortunately, this is a little bit tricky because ABAP is growing very evolutionary and especially for operand positions it is not always clear what you can place there.


      But fortunately, you have (my) documentation which (at least) tries to describe it right for all these possibilities.


      In your case, you can look up  MESSAGE ...WITH :

      If the data type is character-like, then dobj1 through dobj4 are character-like expression positions; if it is not character-like, they are functional operand positions.


      Well, in your first example "lines( mt_data[] )." as a built-in function is neither character-like nor an operand for a functional operand position.


      For built-in functions you need a general expression position.


      But you can also make it easily character-like:


      ... WITH |{ lines( mt_data[] ) }|.

  • Hi Horst,


    this might be a dumb question, but why is it not supported to return the value of "line_exists"?


    I get an error if I try the following:

    rv_assigned = line_exists( lt_roles[ table_line = iv_role ] ).


    The following works (obviously), but an IF is actually what I wanted to avoid due to the table function.

    IF line_exists( lt_roles[ table_line = iv_role ] ).

      rv_assigned = abap_true.



    (I am currently on a System with 7.40 SP7)




  • Would it make sense to permit functions such as:


    IF ( line_exists( lt_serial_tc[ sernr <> 0 ] ) ).



    or is there a more obvious way than this?

  • Hi,


    Thanks for the informative blog. I  have a question..


    Is it possible to have dynamic string clause within line_index statement?

    For example something like


    FIELD-SYMBOLS:   <fs_t_data>   TYPE table.

    // Some logic to determine lv_string_key which is the row key

    line_index<fs_t_data>[ lv_string_key ] ).



    How do we get the index/tabix for the ‘for loop’ in a statement below?

    Currently sy-index/sy-tabix does not return the correct row of wa.

    rt_selected_lines VALUE (BASE rt_selected_lines FOR wa IN <fs_t_data> WHERE (lv_string_keytabixsyindex )  ).


    Thanks & Best Regards,




    • line_index<fs_t_data>[ lv_string_key ] ).

      How do we get the index/tabix for the ‘for loop’ in a statement below?



      • Hi Horst,

        Thanks a lot for the quick feedback.


        The second problem is now solved with INDEX INTO . Thanks a lot for the reference..  🙂


        However, I still get the error in first one. To elaborate, my code looks something like this

        FIELD-SYMBOLS:   <fs_t_data>   TYPE table.  // This is a dynamic table whose structure is known only at runtime

        // A dynamic runtime logic results in lv string_key values as below that uniquely identifies one row of <fs_t_data>

        lv_string_key = 'field1 = value1 field2 = value2'.


        line_index<fs_t_data>[ lv_string_key ] ).  // I get an error here..

        line_index( <fs_t_data>[ KEY lv_string_key ] ).  // I tried with prefix KEY as well.. I still get an error


        We are on NW750 SP 005. 

        Could you please help?


        Thanks & Regards,



        • Seems that you haven’t read the documentation I sent you.

          Is there a dynamic clause for table expressions? No. Is there a dynamic clause for READ TABLE? No. And now the sixty–four–dollar question: Where do we have a dynamic clause for reading internal tables?

          • Sixty-four-dollar answer.. 🙂

            I know READ TABLE does not support dynamic clause.

            However,  I was trying to understand whether the newer syntax supports a dynamic clause so that we can avoid a LOOP statement that supports dynamic where clause.

            Thanks a lot for your response Horst..

            Best Regards,


  • Hi All,

    Do we have CONTINUE like statement which can be used in FOR loop to do nothing in a COND -> ELSE block?

    SPAN {
    font-family: "Courier New";
    font-size: 10pt;
    color: #000000;
    background: #FFFFFF;
    .L0S32 {
    color: #3399FF;
    .L0S52 {
    color: #0000FF;
    .L0S55 {
    color: #800080;
    .L0S70 {
    color: #808080;
    lt_sect VALUE lty_sectBASE lt_sect  FOR ws IN results INDEX INTO l_cntr
    LET  l_nrec VALUE #results[ l_cntr + ]-line OPTIONAL )
    l_trow VALUE #p_gt_raw_data[ l_nrec ]-row OPTIONAL )
    l_crow p_gt_raw_data[ ws-line ]-row
    l_prow ws-line 39
    l_sect p_gt_raw_data[ l_prow ]-value+0(10)  IN
    VALUE #sec   l_sect
    frm   l_crow + 1
    to    l_trow )
    ELSE Continue???  )



  • I notice we can write

    IF line_exists( itab[ ... ] ).

    but not

    CASE abap_true.
      WHEN line_exists( itab[ ... ] ).

    Even though the predicate returns a Boolean. Is there a reason the latter isn't supported?

    The syntax for a method specification is "objref->method" or
    "class=>method". "objref->method" or "class=>method". "class=>method".


  • Hello Horst,

    Is there any performance difference between

    READ TABLE itab into wa

    WITH KEY F1 = X

    F2 = Y

    F3 = Z



    IF SY-SUBRC = 0.

    //bussness logic



    IF line_exists(itab[ F1 = X   F2 = Y  F3 = Z]).

    //business logic



    if "itab" contains millions of records