Pass dynamic table as reference out of method
Ever wondered how to get out your inline created dynamic table out of your method / sub procedure?
As known, only references can be passed through a method interface. But I failed always, because the referred table was empty outside of the method (freed stack) because it is created on stack memory which is only valid inside of the method scope.
So I managed to dynamically create a table of the same structure using RTTS and copied the content of the table in there. This table can be assigned to a class attribute reference without loosing the content. Why is ABAP that laborious?
Additionally I’ve only the select statement as declaration of my data to process in the report. If the customer needs an additional field even from an additional table, no problem, just add it to the select statement. That’s it!
REPORT zzjd_tmp2. CLASS lc_flights DEFINITION. PUBLIC SECTION. METHODS main. METHODS get_data RETURNING VALUE(rr_dyntab) TYPE REF TO data. METHODS display_alv IMPORTING REFERENCE(ir_dyntab) type REF TO data. PRIVATE SECTION. DATA _r_datatable TYPE REF TO data. ENDCLASS. CLASS lc_flights IMPLEMENTATION. METHOD get_data. * create a fancy dynamic table SELECT FROM sflights AS f JOIN scarr AS c ON c~carrid = f~carrid FIELDS c~*, f~* INTO TABLE @DATA(lt_flight). *** copy table to heap memory *** * Create table description DATA(lo_tabledesc) = CAST cl_abap_tabledescr( cl_abap_tabledescr=>describe_by_data( p_data = lt_flight ) ). * Create table in heap memory and set return reference CREATE DATA rr_dyntab TYPE HANDLE lo_tabledesc. FIELD-SYMBOLS <lt_datatable> LIKE lt_flight. " Create a field-symbol... ASSIGN rr_dyntab->* TO <lt_datatable>. " because append doesn't work with references APPEND LINES OF lt_flight TO <lt_datatable>. " Copy content to heap table ********************************* ENDMETHOD. METHOD display_alv. FIELD-SYMBOLS <lt_datatable> TYPE ANY TABLE. ASSIGN ir_dyntab->* TO <lt_datatable>. cl_salv_table=>factory( IMPORTING r_salv_table = DATA(lo_salv) CHANGING t_table = <lt_datatable> ). lo_salv->display( ). ENDMETHOD. METHOD main. _r_datatable = get_data( ). display_alv( _r_datatable ). ENDMETHOD. ENDCLASS. START-OF-SELECTION. DATA(lo_flights) = NEW lc_flights( ). lo_flights->main( ).
Is there any more simple solution for that? Please let me know in the comments.
Please follow my profile.
- Community ABAP: https://community.sap.com/topics/abap
- ABAP Q&A: https://answers.sap.com/tags/833755570260738661924709785639136
- ABAP Blogs: https://blogs.sap.com/tags/833755570260738661924709785639136/
Based on the title of your blog post, I thought you would be explaining how to have a method return a dynamically-created internal table, and how to use it, i.e. some code like that:
Yes, you are absolutely right. I changed my demo report. Now it is even better to understand.
Hi Shai, yes, this is a blog post not a question.
How did you come up with it?
I must confess you've been able to confuse me 🙂
It might be because you don't really explain what problem you are trying to solve.
(And you end your post with the question "Is there any more simple solution for that? Please let me know in the comments.")
Judging by the comments, it works much better to post questions as blog posts. There would never be that many replies from such esteemed Community members if this was a question. 🙂
People love correcting more than aswering 😉
( saw this quip somewhere 😀 )
I had similar expectation to Sandra's, based on the title.
It says "only references can be passed through a method interface" - that's not true, RETURNING parameters are always "by value", for example. But then in the provided example the methods don't have any parameters at all. And you're trying to do... what? Get access to the internal table that is local to one method from another method? That should never be needed. Whatever the method intends to pass along to others, should be declared as a parameter. If it's not intended to be accessed from the outside then just don't.
Rather confused by this post, to be honest...
Thanks for your replay, I changed it 🙂 Please tell me if you like it better now.
In addition to the passing comments from Jelena Perfiljeva & Sandra Rossi
The blog title says, Pass by reference. Pass by reference also relates to saving memory used by programs.
But the following code
is actually duplicating the data into another table, there by doubling the memory requirement.
The dynamic table of the select statement will be freed as soon as the method is left. this was my root problem.
That should be addressed in other ways. Data duplication isn't the correct solution for that.
Jan Dahl This blog post really is a bit confusing because you do not describe the problem that this technique solves...
In this special case you do not need to use RTTC functions.
Creating a data reference based on an existing internal table is as easy as this:
Jelena Perfiljeva says:
That's the point where Jelena is absolutely right: If you know the database table there is no need to do this dynamically!
But: I wouldn't say this will never be needed. The following program select data dynamically into a locally defined table and displays the values in another method. It is also demonstrated how to access the data from outside the class.
Yes, you are right. Nice improvement to my solution. It points out the "passing reference" aspect very good. In the mean while made a second version my self. The reason for this was to have a report, where the select statement is the only point of declaration for the data to process. I'm so tiered to change several places if the customer needs a field more or less.
In newer ABAP releases this can even more simplified.
That's exactly what I'm looking for. Do you know the release no. of that?
NW >= 754 I think
Can't believe I'm arguing with The Great Enno but isn't this a violation of some kind of programming principle? "Open-closed" or something? This seems like one of 'em "even though you can, it doesn't mean you should" things, sorry. 🙂
Hey Jelena Perfiljeva you wrote:
That's a different pair of shoes... 😀
Jan Dahl explained:
Depending on what to do with the data it sounds totally legit to me to choose this way of programming. If there were a lot of data manipulations inside this class, then this would require dynamic access. To avoid dynamic access where it isn't necessarily needed, I would rather choose a static data declaration.
To evade the annoying process of adding new fields I'd define a static structure and used SELECT INTO CORRESPONDING FIELDS.
Yes, me too, but then you loose the performance advantage, right? To have the flexibility from above with "INTO CORRESPONDING FIELDS" you have to order all fields from each table in the select. I guess the "INTO CORRESPONDING FIELDS" is done on the Application-Server? Here you discard all the data provided from the database, which is not in your static structure. Would be interesting to do a measurement here.
It's a long time ago since INTO CORRESPONDING FIELDS was a perfomance issue. Don't ask me for a version...
It's amazing how long those urban legends live! 🙂
Probably once upon a time, ten or more years ago, you would have wanted to avoid INTO CORRESPONDING FIELDS due to performance considerations. But to be honest I have been doing this (INTO CORRESPONDNG) since 1997 and have never had a problem even with bucket loads of fields.
So I suspect this was never a problem.
And the Hungarian Notation is a bit odd as well. What does the underscore at the front of a variable mean?