Application Development 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: 

Problem with an obsolete ABAP expression

0 Kudos


This is really a tricky problem, maybe only old ABAP developers know a solution... for this...

FORM routine STRUKTUR_ANLEGEN that contains a Userexit Call

EXIT_SAPFV45S_001

See note 548205

In this case coding is very old, so we have a function module call that is part of this 'old' construction' with global table VBAP VBAK  etc...

and EXIT has not enough parameters to implement program logic because logic of return table XSTB depends on VKORG and VTWEG value of VBAK..

So I can only use two approaches:

1. Use  'dirty' assigns in userexit function

2. Use an implicit enhancement point at beginning of form routine STRUKTUR_ANLEGEN and copy complete code to change program behavior before adding a check 1 = 0.

Both approaches are not 'nice' but the secon approach seems to be the nicer one because I have access to all variables...

But now there's a serious problem because my code starts directly after FORM statement and before variables...

To substitute local variables with other named ones and in coding is no problem..

But there are varables defined with

LOCAL: structure,

              *vbap,

              tvak.

But an obsolete LOCAL definition can only be made directly after a FORM statement, but as a part of an enhancement point implementation it technically seems to be a part of a mthod... so system throws an error that LOCAL is only allowed directly after FORM ..

Is there a way to implement LOCAL logic using other ABAP expressions ?

BR

Thomas

19 REPLIES 19

Former Member
0 Kudos

Hi

No I don't think, but you can try this:

A) Create a new include Z.........

B) in this include define your form ZZ_STRUKTUR_ANLEGEN_NEW (you can call how you prefer of course)

B) Create an implicit enhancement point in include FV45SFST (the system allows to insert an enhancement at the end of include definition): here insert your include

INCLUDE Z.............

D) Create an implicit enhancement point in form STRUKTUR_ANLEGEN, here insert the calling for your new routine and skip the standard code:

PERFORM ZZ_STRUKTUR_ANLEGEN_NEW.

CHECK 1 = 2.

Now you should have a new form where you can insert all code you need: LOCAL statament too

Max

SuhaSaha
Advisor
Advisor
0 Kudos

My 2 cents ...

What i understand from the SAP documentation that the LOCAL keyword creates a buffer for the global variable so that their values are not changed unnecessarily in the procedure.

So i was thinking if we can try to assign these global variable to formal params of a Z-class method via "pass by value". Here is a small code snippet (plagiarised from SAP example )

  1. DATA text TYPE string VALUE 'Global text'.
  2. CLASS lcl_test DEFINITION CREATE PRIVATE.
  3.   PUBLIC SECTION.
  4.     CLASS-METHODS:
  5.     main IMPORTING VALUE(im_text) TYPE string.
  6. ENDCLASS.
  7. CLASS lcl_test IMPLEMENTATION.
  8.   METHOD main.
  9.     im_text = 'Local text'.
  10.     cl_demo_output=>write_text( im_text ).
  11.   ENDMETHOD.
  12. ENDCLASS.
  13. START-OF-SELECTION.
  14. cl_demo_output=>write_text( text ).
  15. lcl_test=>main( text ).
  16. cl_demo_output=>display_text( text ).

What are your thoughts about it?

BR,

Suhas

Former Member
0 Kudos

Hi

Why to use a global variable defined in a local class?

It would be enough  a new local variable defined in the routime, but then it needs to replace "old" variable with a new one in all points where it's used.

If I've understood Thomas want to copy all code of the routine in order to insert his modification, because it can't place an enhancement in the middle of a form.

The LOCAL statament but also all local declarations will be a problem, because it has to define all again (the enhancement is before the declaration), but if you can use a new form (as copy of old one), the development will be easier

Max

0 Kudos

Why to use a global variable defined in a local class?

I was trying to show that LOCAL statement behaves in the same way as "pass-by-value". That's why i wrote this code to see if the results in the SAP sample coding match that of my code.


If I've understood Thomas want to copy all code of the routine in order to insert his modification, because it can't place an enhancement in the middle of a form.

I think i got the requirement wrong then I thought Thomas wanted to use these LOCAL variables to do some processing.

BR,

Suhas

PS - Did i mention that i hate global variables? I kinda broke-up with them since i started coding in OO.

Former Member
0 Kudos

I thought that too

but then I thought if he needs to define some variable by LOCAL statement, he'll  have to define all local variables too: it's really dirty job.

Max

0 Kudos

It could be that easy if SAP would only allow a IF ... ELSE  in first enhancement point and an ENDIF at the end...

Then this problem would just mean copying complete code one conditional function call and one  IF ELSE END ...statement

Because this is no modification, SAP doesn't seem to have too many trust in 'extern' developers, being able to replace their code too easily

because if something goes wrong they (devs) could post it here an search for a solution provider or even write an OSS message....

Idea with form routine at the end seems possible at first sight ... and needs a lot of form parameters ( all local variables)....

but it is still like the magic bullet of JFK.. or like old times with GOTO statements forward backward and an EXIT at the end....

In german: Spaghetticode

will try it as soon as I will get budget for this

Thanks

Private_Member_7726
Active Contributor
0 Kudos

Hi,

It's never a good idea to copy SAP code, I believe... and, if I understand you correctly, that's an awful lot of copied code, with enhancement points and so on...

I would go for explicit enhancement at the beginning of form, but what i would try to do is pass all the data I need (or references to it) to a singleton class and retrieve it from singleton class inside user exit... A better (in terms of seeing where the values come from) variant of export to memory/import from memory, in other words.

cheers

Jānis

0 Kudos

Yes

Good idea, I didn't think that, but a problem could be if it needs to have the data (not managed in exit interface) elaborated by part of code before the exit (I mean the part of code betwenn the beginning of the form and the exit)

Max

0 Kudos

Yes, but getting and passing references by GET REFERENCE OF, and then dereferencing using ASSIGN when you need the data, should allow to solve that - even for stuff defined locally in STRUKTUR_ANLEGEN, I believe? About the stuff localized using LOCAL in STRUKTUR_ANLEGEN - that one I'm not sure about Needs trying out...

Alternatively, if you don't need any local data of STRUKTUR_ANLEGEN, enhance the Module Pool (implicit at the end of some important include) with Get_VBAK_And_Other_Useful_Stuff subroutine and call it from the exit

cheers

Jānis

0 Kudos

Ok so I have to  make clear what functional thing should be implemented:

This FORM routine performs a BOM explosion for a root material using different possible parameters... and creates customer order positions out of these bill of material positions.

But now we have here a very customer specific bill of material (very special and not usable with SAP standard functionality) that contains assembled materials. For these assembled and not produced materials no order position should be created.. so  just have to delete some BOM explosion results

Program uses a parameter with value A = simple BOM explosion B = multilevel/multihierarchical BOM explosion and E (use customer exit)

Specification is quite simple: BOM explosion should exactly be executed like using parameter B.. but should then be extended by my logic to reduce table xstb by deleting positions that contain an assembled material.... so that customer order does not create a position for these..

Because there are some additional code lines before BOM explosion module when using B, I can not use Exit directly without copying this code into function module also... here I have to do dirty assignments to get all this working.. so I thought it could be easier to use  a full code copy enhancement replace method... and here I meet my LOCAL friends.... that make it impossible to simply copy SAP code and add a function module to reduce xstb...

By the way trying to solve this using suggested FORM method above -> I will run into trouble with all the other enhancement point definitions.... grrrr

I only want to reduce entries of table xstb  ..... using B logic and a logic using vbak-vkorg and vbak-vtweg and some other values from bill of material position data....

At the end I may really have to choose dirty assignment solution...with parameter value 'E' for USER_EXIT, but I really don't know how to copy logic lines of B before BOM explosion into EXIT....

Small concept big problem

0 Kudos

Good good....I've tried it and it works...

but the last little problem: it's it needs to use local data, the enhancement point it's at the beginning of form, so it can't use local variables they aren't defined yet

Max

0 Kudos

By the way trying to solve this using suggested FORM method above -> I will run into trouble with all the other enhancement point definitions.... grrrr

They are a part of a code, you need to copy in your new form if the enhancement is active in your system

0 Kudos

Getting a reference via dynamic assign like the red marked stuff in the following example is perhaps stretching it too far already, but will also work, I believe... It needs sy-subrc checks, just in case the SAP enhancements/definitions disappear...

REPORT zjbtst1 .

CLASS lcl_memory DEFINITION CREATE PRIVATE.

  PUBLIC SECTION.

    CLASS-METHODS get_instance

       RETURNING value(ro_instance) TYPE REF TO lcl_memory .


    METHODS: set IMPORTING i_ref TYPE REF TO data,

             get RETURNING value(r_data) TYPE string .

  PRIVATE SECTION.

    CLASS-DATA so_instance TYPE REF TO lcl_memory.

    DATA: m_ref TYPE REF TO data.

ENDCLASS.


CLASS lcl_memory IMPLEMENTATION.

  METHOD get_instance.

    IF so_instance IS NOT BOUND.

      CREATE OBJECT so_instance.

    ENDIF.

    ro_instance = so_instance.

  ENDMETHOD.

  METHOD set .

    m_ref = i_ref .

  ENDMETHOD .

  METHOD get .

    FIELD-SYMBOLS <l_data> TYPE any .

    ASSIGN m_ref->* TO <l_data> .

    r_data = <l_data> .

  ENDMETHOD .

ENDCLASS.


START-OF-SELECTION .

  PERFORM test1 .

FORM test1 .

"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""$"$\SE:(1) Form TEST1, Anfang                 *$*$-Start: (1)---------------------------------------------------------------------------------$*$*

ENHANCEMENT 1  ZJBTEST_BEGIN.    "active version

FIELD-SYMBOLS <fs> type any .

data: l_ref type ref to data .

assign ('L_VAR') to <fs> .

get REFERENCE OF <fs> into l_ref .

lcl_memory=>get_instance( )->set( l_ref ) .

ENDENHANCEMENT.

*$*$-End:   (1)---------------------------------------------------------------------------------$*$*

  DATA: l_string TYPE string VALUE 'Test Test 1' .

  DATA: l_ref_int TYPE REF TO data.

ENHANCEMENT-POINT ZJBTST SPOTS ZJBTST1 .

*$*$-Start: ZJBTST------------------------------------------------------------------------------$*$*

ENHANCEMENT 1  ZJBTST1.    "active version

data l_var type string value 'Test test 2' .


l_var = |Changed | && l_var .

ENDENHANCEMENT.

*$*$-End:   ZJBTST------------------------------------------------------------------------------$*$*

  PERFORM test2 .

  GET REFERENCE OF l_string INTO l_ref_int .

  lcl_memory=>get_instance( )->set( l_ref_int ) .

  PERFORM test2 .

ENDFORM .

FORM test2 .

  DATA: l_string TYPE string .

  l_string = lcl_memory=>get_instance( )->get( ).

  WRITE: / l_string .

ENDFORM .

0 Kudos

Hi

Yes you're right.....I've never noticed and thought that as It can't use a variable before its definition (we'll have a sintax error), but after starting program all variables are loaded in memory, so they are readily available: it doesn't matter where they are defined.

Good good very good job

Thank you very much

Max

0 Kudos

You're welcome. Unrelated to this stuff, but right about now I really wish SAP had sneaked in a simple way, via kernel call or something, for a method to get its own parameter bindings (abap_parmbind_tab from type pool ABAP)... I guess I'm getting used that so much is possible in ABAP

cheers

Jānis

matt
Active Contributor
0 Kudos

With all that is going on there, the safest and most practical option is simply to go for a repair. Get the object key and make the changes in as minimal a fashion as you can.

It's still done with the modification assistant, and so is picked up during upgrades and support package implementations.

It's what I would do.

0 Kudos

Hello, you're perfectly right.. from a developers perspective...

but you will surely also know ,, what the persistent issue is about this..

1. Getting modification acknowledged by customer.   SAP support  may deny support  ... in case of OSS etc etc ...

2. We (as solution provider) will have to take it as a part of our maintenance agreement

In 16 years of development I've seen all kinds of customer attitude toward mods...

From "No way .."  to "Is there still some original code ?..  Who cares about!"

I will only ask customer to choose a mod, if I'm convinced I can't deliver it as an enhancement or an exit...

Will have to check back options with customer , so until now I thank you all...

I will surely report complete result ... hopefully already during next week..

BR

Thomas

matt
Active Contributor
0 Kudos

SAP Support may deny support for anything with an implicit enhancement, dynamic assigns up the call stack, or any kind of user exit. The support comes back when you reverse or switch off the exit.

You'll also have to take any enhancement or user exit as a solution provider.

Ultimately, the customer have to decide whether they really want this functionality. I think in all my 17 years I've never seen an implementation that didn't have some kind of direct modification. At least they're better than copies of standard programs!

Another approach that occurs to me, when you need data not available through the interface, is to make an enhancement/use an exit in the place where the data is present, and store it, perhaps as static attributes of a class.

0 Kudos

Ok, I've made some checks and there are a lot more global variables that are mixed up terribly and are not considered to be a part of the standard user exit in this form routine...

Tried all kind of tricks with enhancements and result is:

Use a simple call function in a 7 line mod and implement a restrictive conditional call and an own  active/inactive switch logic....

Use standard result table XSTB of BOM Explosion as IMPORT and EXPORT and implement table content reduction logic.... in function module..

Worst case is somebody will have to do one more SPAU decision ...

Sometimes this old SAP codes are ......really woooahhh...

I hope SAP still has some young employees that know what purpose all this global variable mixups in SD code have..

This is sureley a question of long story telling nights.... during mentoring...

So I've proposed a modification in this case....

let's wait and see...

Now I will have to describe logic and prepare a specification, because this decision is taken during my holiday.....

BR

Thomas