Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected database commit when displaying data using cl_salv_table

Tags:

abap

alv

In an ABAP program I have noticed unexpected persistence of data when displaying a local table using the class cl_salv_table.

To reproduce I have created a minimal code sample. The program does an insert, displays data in an ALV, then does a ROLLBACK WORK. I expect the inserted value to be present in the database BEFORE the rollback, and absent AFTER the rollback.

However, if between the insert and the rollback, an ALV grid is displayed, the data is persisted beyond the rollback, and immediately visible to other transactions.

Is this expected behaviour, and if so, how can I avoid this? We do use this class quite often and it looks like we may inadvertently commit values to database when we don't actually want to.


This is the code:

*&---------------------------------------------------------------------*
*& Report  zok_alv_commit
*&
*&---------------------------------------------------------------------*
*&
*&
*&---------------------------------------------------------------------*
REPORT zok_alv_commit.

SELECTION-SCREEN BEGIN OF BLOCK b1.

PARAMETERS: p_showtb TYPE boolean AS CHECKBOX DEFAULT abap_false.

SELECTION-SCREEN END OF BLOCK b1.

START-OF-SELECTION.

  DATA: lt_table TYPE TABLE OF zok_alv,
        ls_table TYPE zok_alv.

  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  " Create new GUID and insert into table
  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  TRY.
      ls_table-guid = cl_system_uuid=>create_uuid_c22_static( ).
    CATCH cx_uuid_error.
      " Error creating UUID
      MESSAGE e836(/basf/dps3_apodata).
  ENDTRY.
  WRITE: |Create guid { ls_table-guid } |, /.

  INSERT zok_alv FROM ls_table.
  APPEND ls_table TO lt_table.

  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  " The important bit: show something in an ALV
  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

  IF p_showtb = abap_true.
    cl_salv_table=>factory(
      IMPORTING r_salv_table = DATA(lo_alv)
      CHANGING t_table = lt_table
    ).

    lo_alv->display( ).
  ENDIF.

  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
  " Check existence in table before and after rollback
  " Expectation: If the ALV is shown above, the data is already committed,
  " so the ROLLBACK WORK will not have an effect.
  """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""

  SELECT SINGLE guid FROM zok_alv INTO @DATA(lv_ignored) WHERE guid = @ls_table-guid.
  IF sy-subrc = 0.
    WRITE: 'GUID exists on DB before rollback.', /.
  ELSE.
    WRITE: 'GUID does NOT exist on DB before rollback.', /.
  ENDIF.

  ROLLBACK WORK.

  SELECT SINGLE guid FROM zok_alv INTO @lv_ignored WHERE guid = @ls_table-guid.
  IF sy-subrc = 0.
    WRITE: 'GUID exists on DB after rollback.', /.
  ELSE.
    WRITE: 'GUID does NOT exist on DB after rollback.', /.
  ENDIF.

It requires a table ZOK_ALV with only MANDT and a 22-character field GUID as primary key, nothing else.


When executing the code with p_showtb unchecked:

Selection screen 1 Result screen 1 Table view 1

As you can see, the value is not present after the rollback, and not present in the table - as expected.

When executing the code with p_showtb checked:

Selection screen 2 ALV screen

At this point, already, the id is visible in SE16 in another session:

Table view 2

(I leave the ALV screen with Back (F3) at this point) The code confirms, the value is still present, even after the rollback:

Result screen 2

Even after leaving the program, the values persist in the DB.

like image 272
founderio Avatar asked Dec 23 '22 00:12

founderio


1 Answers

To answer the 2 questions:

1) Yes, this is the "expected behavior" as stated in the database commit documentation :

a database commit is performed implicitly in the following situation: Completion of a dialog step ...

(it means that any display does a database commit)

This is because when the screen is displayed, SAP doesn't do anything except waiting for the user action, so the workprocess which was used to execute the ABAP code prior to the display can be reused for executing the ABAP code of requests from other users.

So that the workprocess can be reused, the memory of the workprocess (variables) is to be switched, it's called the roll-out/roll-in, which also requires that some system database tables are updated for internal SAP stuff and a database commit is needed for that. This is better explained in the documentation of SAP LUWs. I read that somewhere but I don't remember exactly where.


2) No, you can't "avoid this behavior", but considering your current logic of insert + display + rollback the insert, you can do one of these solutions but I recommend only the first one in your case, not the second one:

  • Change your logic to conform the SAP rule (i.e. any display does a database commit so bear with it). If your logic is really the one you said, then why do you want to insert something in the database and rollback it? Without further details, my answer is to just remove the insert and the rollback and keep the display. It would be pure speculation to answer something else because you didn't give enough details how your actual class really works (there must be a reason why it does insert + display + rollback, but what is missing in your explanation?) You'd better post another question and give all the details.
  • Second solution ("non-recommended, counter-performing and dangerous"), if you really really want to stick to your current logic: move your display to a RFC-enabled function module, and do CALL FUNCTION '...' DESTINATION 'NONE' KEEPING LOGICAL UNIT OF WORK (cf documentation). It's not recommended because it's for internal use only. It's counter-performing because it occupies 2 workprocesses at the same time. It's dangerous because "the worst case scenario may be a system shutdown".
like image 111
Sandra Rossi Avatar answered May 12 '23 15:05

Sandra Rossi