2022 Feb 02 3:47 PM
Hi there!
I experienced a strange problem with references:
see the following program
TYPES t_t000 TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.
DATA b TYPE REF TO t_t000.
DATA BEGIN OF a OCCURS 0.
INCLUDE STRUCTURE t000.
DATA END OF a.
b = REF #( a[] ).
The "source" data is defined with DATA ... OCCURS. Yes, I know, it's outdated and should not be used anymore. tell this to the persons maintaining SAPMV45A... 😂
the report can not be activated due to the error
Type "REF TO " is incompatible with type "REF TO T_T000".
Is there any chance to define an internal table with exactly the same technical conditions so that it can be referenced?I tried various definitions:I also know that there is a workaround: Use TYPE REF TO DATA and use Field-Symbols to access.
2022 Feb 03 9:24 PM
Hi enno.wulff,
with your sample in mind I've created a new sample. Maybe this is what you need.
TYPES:
BEGIN OF _data_reference,
name TYPE string,
data TYPE REF TO data,
type TYPE tablename,
END OF _data_reference,
_data_references TYPE SORTED TABLE OF _data_reference WITH UNIQUE KEY name.
DATA:
BEGIN OF xvbap OCCURS 125.
INCLUDE STRUCTURE vbapvb.
DATA:
END OF xvbap.
DATA:
BEGIN OF yvbap OCCURS 2.
INCLUDE STRUCTURE vbapvb.
DATA:
END OF yvbap.
CLASS lcl_reference DEFINITION.
PUBLIC SECTION.
CLASS-DATA:
grt_xvbap TYPE REF TO va_vbapvb_t,
grt_yvbap TYPE REF TO va_vbapvb_t.
CLASS-METHODS:
set_references
IMPORTING
it_data_references TYPE _data_references.
ENDCLASS.
CLASS lcl_reference IMPLEMENTATION.
METHOD set_references.
FIELD-SYMBOLS:
<lt_data> TYPE STANDARD TABLE.
LOOP AT it_data_references REFERENCE INTO DATA(lr_data_reference).
TRY.
ASSIGN lr_data_reference->data->* TO <lt_data> CASTING TYPE (lr_data_reference->type).
CASE lr_data_reference->name.
WHEN 'XVBAP'.
grt_xvbap = REF #( <lt_data> ).
WHEN 'YVBAP'.
grt_yvbap = REF #( <lt_data> ).
ENDCASE.
CATCH cx_sy_assign_cast_illegal_cast cx_sy_assign_cast_unknown_type.
ENDTRY.
ENDLOOP.
IF grt_xvbap IS NOT INITIAL AND grt_yvbap IS NOT INITIAL.
cl_demo_output=>write_html( html = '<h1>Before modifikation:</h1>' ).
cl_demo_output=>write_html( html = |<table border = "2" style="border-collapse: collapse; border-spacing: 2px;">| &&
|<thead>| &&
|<tr><th colspan = "2">referenced variables</th><th colspan = "2">reference variables</th></tr>| &&
|<tr><th>xvbap[ 1 ]-vbeln</th><th>yvbap[ 1 ]-vbeln</th>| &&
|<th>mt_xvbap->*[ 1 ]-vbeln</th><th>mt_yvbap->*[ 1 ]-vbeln</th></tr>| &&
|</thead>| &&
|<tbody><tr><td>{ xvbap[ 1 ]-vbeln }</td><td>{ yvbap[ 1 ]-vbeln }</td>| &&
|<td>{ grt_xvbap->*[ 1 ]-vbeln }</td><td>{ grt_yvbap->*[ 1 ]-vbeln }</td></tr></tbody></table>| ).
grt_xvbap->*[ 1 ]-vbeln = '0000000011'.
grt_yvbap->*[ 1 ]-vbeln = '0000000012'.
cl_demo_output=>write_html( html = '<h1>After modifikation:</h1>' ).
cl_demo_output=>write_html( html = |<table border = "2" style="border-collapse: collapse; border-spacing: 2px;">| &&
|<thead>| &&
|<tr><th colspan = "2">referenced variables</th><th colspan = "2">reference variables</th></tr>| &&
|<tr><th>xvbap[ 1 ]-vbeln</th><th>yvbap[ 1 ]-vbeln</th>| &&
|<th>mt_xvbap->*[ 1 ]-vbeln</th><th>mt_yvbap->*[ 1 ]-vbeln</th></tr>| &&
|</thead>| &&
|<tbody><tr><td>{ xvbap[ 1 ]-vbeln }</td><td>{ yvbap[ 1 ]-vbeln }</td>| &&
|<td>{ grt_xvbap->*[ 1 ]-vbeln }</td><td>{ grt_yvbap->*[ 1 ]-vbeln }</td></tr></tbody></table>| ).
cl_demo_output=>display( ).
ENDIF.
ENDMETHOD.
ENDCLASS.
TYPES:
gtyt_xvbapvb LIKE STANDARD TABLE OF xvbap WITH NON-UNIQUE DEFAULT KEY,
gtyt_yvbapvb LIKE STANDARD TABLE OF yvbap WITH NON-UNIQUE DEFAULT KEY.
START-OF-SELECTION.
xvbap[] = VALUE #( ( vbeln = '0000000001' ) ).
yvbap[] = VALUE #( ( vbeln = '0000000002' ) ).
lcl_reference=>set_references( VALUE #( ( name = 'XVBAP' data = REF gtyt_xvbapvb( xvbap[] ) type = 'VA_VBAPVB_T' )
( name = 'YVBAP' data = REF gtyt_yvbapvb( yvbap[] ) type = 'VA_VBAPVB_T' ) ) ).
Greetings
Stephan
2022 Feb 02 4:25 PM
Hi Enno,
not long ago I had the same issue. Didn't find a better solution than generic TYPE REF TO DATA.
Though, if only local access is sufficient this should work.
DATA b LIKE REF TO a[].
OR
DATA(b) = REF #( a ).
Christian
2022 Feb 02 4:36 PM
Thanks for the feedback, christian.guenter !
local access is not possible.
2022 Feb 02 5:40 PM
Hi Enno,
maybe this will solve your issue. The magic is NEW instead of REF.
TYPES t_t000 TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.
DATA b TYPE REF TO t_t000.
DATA:
BEGIN OF a OCCURS 0.
INCLUDE STRUCTURE t000.
DATA:
END OF a.
SELECT * FROM t000 INTO TABLE a.
b = NEW #( a[] ).
Greetings
Stephan
2022 Feb 02 5:55 PM
Direct access to the reference b is possible.
DATA(client) = VALUE #( b->*[ 1 ]-mandt OPTIONAL ).
LOOP AT b->* REFERENCE INTO DATA(b_line).
DATA(mandt) = b_line->mandt.
ENDLOOP.
Greetings
Stephan
2022 Feb 02 5:59 PM
2022 Feb 02 6:16 PM
Maybe it's better to combine NEW with CORRESPONDING (see sample output of sample report).
TYPES t_t000 TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.
DATA b TYPE REF TO t_t000.
DATA d TYPE REF TO t_t000.
DATA:
BEGIN OF a OCCURS 0.
INCLUDE STRUCTURE t000.
DATA:
END OF a.
SELECT * FROM t000 INTO TABLE a.
SELECT mandt, mtext, ort01, mwaer, adrnr,
cccategory AS ddcategory, cccopylock AS ddcopylock
FROM t000 INTO TABLE @DATA(c).
cl_demo_output=>write_data( value = c
name = 'Selected data (only 7 fields including renaming two of them)' ).
d = NEW #( c[] ).
cl_demo_output=>write_data( value = d->*
name = 'Referencing without corresponding' ).
d = NEW #( CORRESPONDING #( c[] ) ).
cl_demo_output=>write_data( value = d->*
name = 'Referencing with corresponding' ).
d = NEW #( CORRESPONDING #( c[] MAPPING cccategory = ddcategory cccopylock = ddcopylock ) ).
cl_demo_output=>write_data( value = d->*
name = 'Referencing with corresponding and mapping' ).
cl_demo_output=>display( ).
b = NEW #( a[] ).
DATA(client) = VALUE #( b->*[ 1 ]-mandt OPTIONAL ).
LOOP AT b->* REFERENCE INTO DATA(b_line).
DATA(mandt) = b_line->mandt.
ENDLOOP.
Greetings
Stephan
2022 Feb 02 6:30 PM
NEW will create a new data object, and copies the contents of the original data object. If A is changed, B will not reflect it.
I don't think it's what the OP wants. But let's see.
2022 Feb 02 6:46 PM
Doesn't NEW create a new data object and copies the internal table? I think Enno wants a reference so he can carry it around change the content of a[] with that. In your example if you change b->* this change isn't reflected in a[].
2022 Feb 02 6:59 PM
Yes, just realized it after seeing the comment of sandra.rossi.
But there is another workaround.
TYPES t_t000 TYPE STANDARD TABLE OF t000 WITH NON-UNIQUE DEFAULT KEY.
DATA b TYPE REF TO t_t000.
DATA:
BEGIN OF a OCCURS 0.
INCLUDE STRUCTURE t000.
DATA:
END OF a.
SELECT mandt, mtext, ort01, mwaer, adrnr, cccategory FROM t000 INTO CORRESPONDING FIELDS OF TABLE @a.
cl_demo_output=>write_data( value = a[] name = 'Selected Data' ).
* Create a helper reference
DATA(c) = REF #( a[] ).
b = c.
LOOP AT b->* REFERENCE INTO DATA(b_line).
b_line->mandt = b_line->mandt + 800.
ENDLOOP.
cl_demo_output=>display_data( value = a[] name = 'Manipulated Data' ).
Greetings
Stephan
2022 Feb 02 7:18 PM
Well that's interesting. That gives me a warning with 752 and syntax error with >=754.
2022 Feb 02 7:27 PM
Strange. With 750PL22 it's working.
So, in which system we have a bug?
2022 Feb 03 8:24 AM
2022 Feb 03 3:11 PM
Hey stephkoester christian.guenter sandra.rossi
thanks for all your comments!
But, as already mentioned, this is not a solution to my problem.
NEW creates a copy of the table and returns the reference.
We now have the following solution:
pass the reference by REF TO DATA and store the reference in a variable TYPE REF TO DATA.
Before accessing the data, it must be assigned to a typed field-symbol:
FIELD-SYMBOLS <tab> TYPE TABLE OF special_type.
again: thanks to all!
2022 Feb 03 3:20 PM
Hi Enno,
what about my last comment where I don't use the new statement?
DATA:
BEGIN OF a OCCURS 0.
INCLUDE TYPE t000.
DATA:
END OF a.
TYPES t_t000 LIKE STANDARD TABLE OF a WITH NON-UNIQUE DEFAULT KEY.
DATA b TYPE REF TO t_t000.
SELECT mandt, mtext, ort01, mwaer, adrnr, cccategory FROM t000 INTO CORRESPONDING FIELDS OF TABLE @a.
cl_demo_output=>write_data( value = a[] name = 'Selected Data' ).
b = REF #( a[] ).
LOOP AT b->* REFERENCE INTO DATA(b_line).
b_line->mandt = b_line->mandt + 800.
ENDLOOP.
cl_demo_output=>display_data( value = a[] name = 'Manipulated Data' ).
Greetings
Stephan
2022 Feb 03 3:34 PM
Hey stephkoester
just saw this afterwards and this is a genius solution! I just test it. but seems good.
Only thing that worries me is the comment of christian.guenter concerning the higher releases...
"my" system release is
SAP_BASIS 754
SAP_ABA 75E
unfortunately your solution does not work because of cheating. 😄
The definition of B is done with LIKE instead of TYPE.
TYPES t_t000 LIKE STANDARD TABLE OF a WITH NON-UNIQUE DEFAULT KEY.
This only works if you can access the variable what I can't. my goal is to transfer the reference of XVBAP[] of SAPMV45A to a class attribute via a general interface:
Types: BEGIN OF _data_reference,
name TYPE string,
data TYPE REF TO DATA,
END OF _data_reference,
_data_references TYPE SORTED TABLE OF _data_reference WITH UNIQUE KEY name.
IN SAPMV45A:
class=>set_references( VALUE #(
( name = 'XVBAP' data = REF #( xvbap[] ) ).
the assignment inside the class does not work:
CLASS-DATA mt_xvbap TYPE va_vbapvb_tt.
CLASS-METHODS set_references
IMPORTING
it_data_references TYPE _data_references.
METHOD set_references.
mt_xvbap = it_data_references[ name = 'XVBAP' ]-data.
ENDMETHOD.
2022 Feb 03 3:56 PM
2022 Feb 03 5:03 PM
enno.wulff
The curse of <br> (and SAP Community being a custom development without the best developers...)
so, for any people reading your post, with the right "pretty print":
Types: BEGIN OF _data_reference,
name TYPE string,
data TYPE REF TO DATA,
END OF _data_reference,
_data_references TYPE SORTED TABLE OF _data_reference WITH UNIQUE KEY name.
In SAPMV45A:class=>set_references( VALUE #(
( name = 'XVBAP' data = REF #( xvbap[] ) ).
the assignment inside the class does not work:
CLASS-DATA mt_xvbap TYPE va_vbapvb_tt.
CLASS-METHODS set_references
IMPORTING
it_data_references TYPE _data_references.
METHOD set_references.
mt_xvbap = it_data_references[ name = 'XVBAP' ]-data.
ENDMETHOD.
2022 Feb 02 9:18 PM
This is my last idea (working in 750 and 756)
DATA:
BEGIN OF a OCCURS 0.
INCLUDE TYPE t000.
DATA:
END OF a.
TYPES t_t000 LIKE STANDARD TABLE OF a WITH NON-UNIQUE DEFAULT KEY.
DATA b TYPE REF TO t_t000.
SELECT mandt, mtext, ort01, mwaer, adrnr, cccategory FROM t000 INTO CORRESPONDING FIELDS OF TABLE @a.
cl_demo_output=>write_data( value = a[] name = 'Selected Data' ).
b = REF #( a[] ).
LOOP AT b->* REFERENCE INTO DATA(b_line).
b_line->mandt = b_line->mandt + 800.
ENDLOOP.
cl_demo_output=>display_data( value = a[] name = 'Manipulated Data' ).
Greetimgs
Stephan
2022 Feb 03 4:56 PM
I appreciate your efforts stephkoester !
unfortunately:
TYPES tt_vbapvb LIKE STANDARD TABLE OF vbapvb.
Only use "TYPE" to reference ABAP Dictionary types, not "LIKE" or "STRUCTURE".
2022 Feb 03 6:38 AM
Just out of interest, I tried this:
METHOD do.
DATA(c) = REF #( a[] ).
ENDMETHOD.
Then, I used the Eclipse assistance to explicitly define local variable c.
It came up with
DATA: c LIKE REF TO standard table OF a.
Which isn't even syntactically correct!
2022 Feb 03 3:51 PM
Hi Enno!
You can drill it down to
DATA BEGIN OF s.
INCLUDE STRUCTURE t000.
DATA END OF s.
DATA r TYPE REF TO t100.
r = REF #( s ). "Error
It has nothing to do with the internal tables or with the REF or NEW syntax, but with the structure definitions.
The structure types do not match.
See Assignments Between Data Reference Variables
"Both have an identical structured type. In the case of structured types, identical technical type attributes are not sufficient, but the same structured type must have been used to define the static types. "
INCLUDE STRUCTURE is different compared to typing with the structure itself.
Horst
2022 Feb 03 4:53 PM
Thanks for your explanation horst.keller !
Unfortunately the reference with LIKE does not work with internal tables.Structures do work. the problem is the internal table.
I will use the work around with TYPE REF TO DATA and ASSIGN to specific type.
2022 Feb 03 5:43 PM
And I say, it is the difference in the structure definitions, in your case of the table lines.
The LIKE was a typo ...
Yes, if you have to use these weird declarations, well, you need workarounds.
2022 Feb 03 9:24 PM
Hi enno.wulff,
with your sample in mind I've created a new sample. Maybe this is what you need.
TYPES:
BEGIN OF _data_reference,
name TYPE string,
data TYPE REF TO data,
type TYPE tablename,
END OF _data_reference,
_data_references TYPE SORTED TABLE OF _data_reference WITH UNIQUE KEY name.
DATA:
BEGIN OF xvbap OCCURS 125.
INCLUDE STRUCTURE vbapvb.
DATA:
END OF xvbap.
DATA:
BEGIN OF yvbap OCCURS 2.
INCLUDE STRUCTURE vbapvb.
DATA:
END OF yvbap.
CLASS lcl_reference DEFINITION.
PUBLIC SECTION.
CLASS-DATA:
grt_xvbap TYPE REF TO va_vbapvb_t,
grt_yvbap TYPE REF TO va_vbapvb_t.
CLASS-METHODS:
set_references
IMPORTING
it_data_references TYPE _data_references.
ENDCLASS.
CLASS lcl_reference IMPLEMENTATION.
METHOD set_references.
FIELD-SYMBOLS:
<lt_data> TYPE STANDARD TABLE.
LOOP AT it_data_references REFERENCE INTO DATA(lr_data_reference).
TRY.
ASSIGN lr_data_reference->data->* TO <lt_data> CASTING TYPE (lr_data_reference->type).
CASE lr_data_reference->name.
WHEN 'XVBAP'.
grt_xvbap = REF #( <lt_data> ).
WHEN 'YVBAP'.
grt_yvbap = REF #( <lt_data> ).
ENDCASE.
CATCH cx_sy_assign_cast_illegal_cast cx_sy_assign_cast_unknown_type.
ENDTRY.
ENDLOOP.
IF grt_xvbap IS NOT INITIAL AND grt_yvbap IS NOT INITIAL.
cl_demo_output=>write_html( html = '<h1>Before modifikation:</h1>' ).
cl_demo_output=>write_html( html = |<table border = "2" style="border-collapse: collapse; border-spacing: 2px;">| &&
|<thead>| &&
|<tr><th colspan = "2">referenced variables</th><th colspan = "2">reference variables</th></tr>| &&
|<tr><th>xvbap[ 1 ]-vbeln</th><th>yvbap[ 1 ]-vbeln</th>| &&
|<th>mt_xvbap->*[ 1 ]-vbeln</th><th>mt_yvbap->*[ 1 ]-vbeln</th></tr>| &&
|</thead>| &&
|<tbody><tr><td>{ xvbap[ 1 ]-vbeln }</td><td>{ yvbap[ 1 ]-vbeln }</td>| &&
|<td>{ grt_xvbap->*[ 1 ]-vbeln }</td><td>{ grt_yvbap->*[ 1 ]-vbeln }</td></tr></tbody></table>| ).
grt_xvbap->*[ 1 ]-vbeln = '0000000011'.
grt_yvbap->*[ 1 ]-vbeln = '0000000012'.
cl_demo_output=>write_html( html = '<h1>After modifikation:</h1>' ).
cl_demo_output=>write_html( html = |<table border = "2" style="border-collapse: collapse; border-spacing: 2px;">| &&
|<thead>| &&
|<tr><th colspan = "2">referenced variables</th><th colspan = "2">reference variables</th></tr>| &&
|<tr><th>xvbap[ 1 ]-vbeln</th><th>yvbap[ 1 ]-vbeln</th>| &&
|<th>mt_xvbap->*[ 1 ]-vbeln</th><th>mt_yvbap->*[ 1 ]-vbeln</th></tr>| &&
|</thead>| &&
|<tbody><tr><td>{ xvbap[ 1 ]-vbeln }</td><td>{ yvbap[ 1 ]-vbeln }</td>| &&
|<td>{ grt_xvbap->*[ 1 ]-vbeln }</td><td>{ grt_yvbap->*[ 1 ]-vbeln }</td></tr></tbody></table>| ).
cl_demo_output=>display( ).
ENDIF.
ENDMETHOD.
ENDCLASS.
TYPES:
gtyt_xvbapvb LIKE STANDARD TABLE OF xvbap WITH NON-UNIQUE DEFAULT KEY,
gtyt_yvbapvb LIKE STANDARD TABLE OF yvbap WITH NON-UNIQUE DEFAULT KEY.
START-OF-SELECTION.
xvbap[] = VALUE #( ( vbeln = '0000000001' ) ).
yvbap[] = VALUE #( ( vbeln = '0000000002' ) ).
lcl_reference=>set_references( VALUE #( ( name = 'XVBAP' data = REF gtyt_xvbapvb( xvbap[] ) type = 'VA_VBAPVB_T' )
( name = 'YVBAP' data = REF gtyt_yvbapvb( yvbap[] ) type = 'VA_VBAPVB_T' ) ) ).
Greetings
Stephan
2022 Feb 04 12:34 PM
Thanks a lot stephkoester!!
the main part is the workaround via field-symbol.
ASSIGN lr_data_reference->data->* TO <lt_data> CASTING TYPE (lr_data_reference->type).
another Stefan provided this solution which is mainly the same:
FIELD-SYMBOLS <xvbap_tab> TYPE TABLE OF va_vbapvb_t.
ASSIGN xvbap[] TO <xvbap_tab>.
grt_xvbap = REF #( <vbap_tab> ).
Your solution with passing the desired specific type is very elegant!
I also tried to retrieve the type by
CL_ABAP_TYPEDESCR=>DESCRIBE_BY_DATA( xvbap[] )
but this will of course return the "wrong" type which cannot be used.
thanks for your tenacity and this elegant solution!