Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Update before rollback

Former Member
0 Likes
3,862

Hi all,

how can I save some data in a Z table before rolling back a transaction?

the order is something like this:

transaction start

do something

update, modify etc

...

error

update ZTABLE

rollback.

end of transaction.

obviously in the order mentioned also the update of ZTABLE will be rolled back, my need is to save it and roll back everything else.

thanks

Stefano Cattaneo

1 ACCEPTED SOLUTION
Read only

Former Member
0 Likes
3,087

Why not write it to a log file before the rollback?

Cheers,

Julius

22 REPLIES 22
Read only

rvinod1982
Contributor
0 Likes
3,087

Hi Stefano,

Check the value of sy-subrc when you are updating your primary table. If sys-subrc ne 0, then you update the ZTABLE.

Regards,

Vinod

Read only

0 Likes
3,087

Hi Vinod,

the problem is that I'm working on a FM called from a standard program.

The standard program make some update (without commit) and after this calls my FM.

In my function module I make some checks and if necessary, i raise an error.

The error cause the standard program to rollback everything.

What I want to do is to change a Ztable before raising the error. The problem is that I cannot make a commit work at this point to prevent that all the changes previously made will also be commited. I can't neither make a rollback because I'm not supposed to control the rollback event in my function module. What I'm looking for is a way to manage my update in a different LUW or to postpone my update after the rollback.

Thanks

Stefano

Read only

0 Likes
3,087

Maybe you could register a routine in your FM with PERFORM ... ON ROLLBACK, in which this update is done. However you cannot do a COMMIT WORK inside such a registered routine, so not sure if this works.

Is there another enhancement point (or similar) after the rollback in the standard program? If yes, you could store some data in ABAP memory in your first FM which you could read in a second FM and update your table accordingly.

Thomas

Edit: sorry, all obsolete after reading your last reply...

Read only

Former Member
0 Likes
3,087

Hi ,

If error then you update variable as lv_error = 'Y' rollback.

After rollback you can check the lv_error = 'Y' then update your Ztable. I hope you must be storing required information to update

ztable in an internal table.

Read only

0 Likes
3,087

Hi Narajan,

I can't insert any code after rollback since there are no exit after that.

I tried to use perform on rollback but I can't insert a commit inside of it.

any other suggestion?

Read only

Clemenss
Active Contributor
0 Likes
3,087

Hi Stefano,

create a small function to do the Z-table update, make it RFC - callable and call it with addition 'DESTINATION 'NONE'.

This starts a new task and the update in the new task can only be rolled back in the new task making it independent of the calling task - that may be rolled back.

Regards,

Clemens

Read only

Former Member
0 Likes
3,087

Hi Clemens,

i have the same problem, so i hope it is OK when i join this thread.

Tthe ABAP-documention says, that the synchronous RFC triggers a database commit in the calling program:

[http://help.sap.com/abapdocu_70/en/ABAPCALL_FUNCTION_DESTINATION.htm]

How is it possbile to do it in a separate LUW without calling a COMMIT WORK?

The addition KEEPING LOGICAL UNIT OF WORK is unfortunetaly not allowed to use...

[http://help.sap.com/abapdocu_70/en/ABAPCALL_FUNCTION_DESTINATION_INT.htm]

Many greetings,

Stefan

Read only

0 Likes
3,087
Read only

Former Member
0 Likes
3,087

Hi a®s,

thanks, however this will call the FM as an asynchronous RFC and trigger a database commit in the calling program, too.

See the SAP ABAP-Keyword Documention under Notes:

I think it's not so easy.

Many greetings,

Stefan

Read only

Former Member
0 Likes
3,087

Hi all,

I work-around my problem using a rollback followed by the update and the commit, after this the main program continue its operations...

Anyway I'm still looking for a better solution. The way suggested by Stefan Gerschler is the same I'm trying to follow. So the question is if it's possible to start a new LUW without closing the current one?

Thanks for replying.

Stefano

Read only

Clemenss
Active Contributor
0 Likes
3,087

Hi all,

oh yes - any RFC call (including starting new task and destination NONE) will trigger an implicit database commit.

The only way will be to put all database operations into a PERFORM ON COMMIT or write a function and call it IN UPDATE TASK. Those will be triggered only by explicit COMMIT WORK (or call of function BAPI_TRANSACTION_COMMIT).

"An SAP LUW that is not closed by COMMIT WORK, but instead by ending the current program or closing the internal session, has no effect on the registered procedures. Registered update function modules remain on the database but can no longer be executed." ([ABAP Keyword Documentation u2192 ABAP - Reference u2192 Processing External Data u2192 Data Consistency u2192 SAP LUW u2192 COMMIT WORK|http://help.sap.com/abapdocu_70/en/ABAPCOMMIT.htm])

Regards,

Clemens

Read only

Former Member
0 Likes
3,087

Has anybody experience with the Background Remote Function Calls bgRFC ?

In the [ABAP documentation|http://help.sap.com/abapdocu_70/en/ABAPCALL_FUNCTION_BACKGROUND_UNIT.htm] for bgRFC they say:

--- begin of copy & paste -


- If, within the same SAP LUW, bgRFC units and also updates are executed, the bgRFC units are dependent on the update. Only after the update has been processed can the linked bgRFC also be processed. When an incorrect update record is deleted, the corresponding bgRFC units are also deleted. The linkage of bgRFC with the update can be removed with the interface method IF_BGRFC_UNIT~SEPARATE_FROM_UPDATE_TASK of the bgRFC object.

- Dialog module registered bgRFCs that were not started there using COMMIT WORK are not executed by the COMMIT WORK of the caller either.

- The statements COMMIT WORK and ROLLBACK WORK may not be executed in a unit. In addition, no implicit database commit may be triggered there.

---- end of copy & paste -


This sounds for me, that some LUW-Units can linked together and proceeded separately ?!

Many greetings,

Stefan

Read only

Former Member
0 Likes
3,087

hi

after update command..u do commit work...

and then use other statements..

and after that rollback work...

thanks and regards

Dhruv

Read only

Former Member
0 Likes
3,088

Why not write it to a log file before the rollback?

Cheers,

Julius

Read only

0 Likes
3,087

>

> Why not write it to a log file before the rollback?

>

> Cheers,

> Julius

Hi Julius,

your solution is a nice work-around that I considered but, as stated in the previous message, I choose a different one. Now I still looking for "the" solution.

Thanks.

Stefano

Read only

0 Likes
3,087

update the ztable after rollback.

Read only

0 Likes
3,087

> update the ztable after rollback.

Hi Rainer,

as stated in previous messages working after standard rollback is not an option since there are no exit point.

thanks,

Stefano

Read only

0 Likes
3,087

As a variant of the internal DESTINATION 'NONE' suggestion, you could try an R/3 connection. Create a remote enabled FM and update your ztable in the FM. If you save the logon data (which you don't have to within the same system) then take the sy-uname with as a parameter together with the other data.

A bit ugly, but might work for your requirement purposes.

Cheers,

Julius

Read only

0 Likes
3,087

Hello,

This thread is a bit oldish but I would like to stir a little bit here...

At the first sight, it appears that the point is to break the consistency of a transaction - save some data to DB while not saving others. With regards to the fact that most developers try to stick to the ACID principle rather than break it, the task looks interesting and hard to be justified.

But on a second thought, the problem seems to me a bid to narrowly defined to me. Why have the data been put in any kind of persistency layer at all in the first place? Why the need to call the rollback?

E.g., there is a TEST switch in most BAPIs allowing to mock the processing of the data without running into risk that anything is going to be saved to DB upon commit.

All the checks and error handling should be done in the application layer rather than the DB one, shouldn't they?

Maybe the design of the solution needs some reengineering?

Kind regards

Wiktor Nyckowski

Read only

0 Likes
3,087

Hi Wiktor,

I agree with you that maybe the process should be re-engineered.

Anyway in many real situation the re-engineering of the process is not an option, also because in this case it is a financial process, so anyone is "scared" to change it.

The above mentioned consideration are also the cause of my needs.

In the end, I solved the problem with a work around, but I kept this post opened just to find a better solution.

Thanks,

Stefano

Read only

Former Member
0 Likes
3,087

No way out

Read only

0 Likes
3,087

I notice this is a really old thread but since you left it opened till two days ago, I'll contribute with something I think helps to solve this kind of problem, if not for you maybe for others.

You could make use of the event TRANSACTION_FINISHED of the class CL_SYSTEM_TRANSACTION_STATE. This event gets raised by the system whenever a COMMIT WORK or ROLLBACK WORK gets done, so you can set your own event handler to be called back on that moment. In case you need it to run only for COMMIT or only for ROLLBACK, you can place a check at the method using parameter KIND.

So basically you would have a class with two methods, for example:

- SAVE_ERROR which you would call in your exit at the moment an error occurs. In there you would do "SET HANDLER save_error_to_db", and save temporarily the relevant error data in attributes of the class (memory).

- SAVE_ERROR_TO_DB which would be declared with the addition "for event TRANSACTION_FINISHED of CL_SYSTEM_TRANSACTION_STATE". In there you would have the update of your Z table using global data left in some attribute of the class, you would deactivate the method itself with SET HANDLER...ACTIVATION space (to avoid entering an endless loop, although the standard coding takes care of this as well), and a COMMIT WORK (safe to do because the standard COMMIT or ROLLBACK has already been done).

I did a quick proof of concept and it seems to work as you needed (YTEST1 and 2 are two tables with just UZEIT as key field):


REPORT y_abindi_tests.

*----------------------------------------------------------------------*
*       CLASS lcl_test DEFINITION
*----------------------------------------------------------------------*
CLASS lcl_test DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS:
      activate,
      run              FOR EVENT transaction_finished
                       OF cl_system_transaction_state.
  PRIVATE SECTION.
    CLASS-DATA:
      g_activate_time  TYPE syuzeit.
ENDCLASS.                    "lcl_test DEFINITION


*----------------------------------------------------------------------*
*       CLASS lcl_test IMPLEMENTATION
*----------------------------------------------------------------------*
CLASS lcl_test IMPLEMENTATION.
  METHOD activate.
    SET HANDLER run.
    g_activate_time = sy-uzeit.
  ENDMETHOD.                    "activate

  METHOD run.
    DATA: ls_ytest2  TYPE ytest2.

    SET HANDLER run ACTIVATION space.
    ls_ytest2-uzeit = g_activate_time.
    INSERT ytest2 FROM ls_ytest2.
    COMMIT WORK.
  ENDMETHOD.                    "run
ENDCLASS.                    "lcl_test IMPLEMENTATION

DATA:
  gs_ytest1 TYPE ytest1.

PARAMETERS:

  p_comm  TYPE c RADIOBUTTON GROUP rbg1 DEFAULT 'X',
  p_roll  TYPE c RADIOBUTTON GROUP rbg1,
  p_dele  TYPE c RADIOBUTTON GROUP rbg1.

START-OF-SELECTION.

  IF p_dele = 'X'.
    DELETE: FROM ytest1,
            FROM ytest2.
  ELSE.
    gs_ytest1-uzeit = sy-uzeit.
    INSERT ytest1 FROM gs_ytest1.
    lcl_test=>activate( ).
    CASE 'X'.
      WHEN p_comm.
        COMMIT WORK.    "Both tables are updated
      WHEN p_roll.
        ROLLBACK WORK.  "Only YTEST2 is updated
    ENDCASE.
    ROLLBACK WORK.      "Just to test...this doesn't undo the INSERT ytest2 inside the RUN method...
  ENDIF.

Of course, this would have to be tested in a real environment, integrated in an exit inside a standard transaction, where probably update function modules are used and maybe more than one COMMIT / ROLLBACK are done...

But should work in most cases.

Regards