Skip to content

Commit

Permalink
Check 103 - SELECT on table with replacement obj (#1135)
Browse files Browse the repository at this point in the history
Co-authored-by: Lars Hvam <[email protected]>
  • Loading branch information
fidley and larshp authored Mar 15, 2024
1 parent a6b37b7 commit 17f6250
Show file tree
Hide file tree
Showing 4 changed files with 295 additions and 0 deletions.
31 changes: 31 additions & 0 deletions docs/_checks/103.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: SELECT on table with replacement object
cNumber: CHECK_103
rfc: true
index: 103
---

In S/4HANA many old DB tables have now replacement objects/proxy objects which in many case decrease the performance of old SELECT statements when the DB table is used in the OpenSQL.

In many cases usage of dictionary views based on that tables is much faster. But we have to make sure that the selected field is still stored in the DB level. (Check OSS Note: https://me.sap.com/notes/0002000002)

### Example
MARC table has now replacement object and select on it can be really slow. If we replace it with V_MARC_MD it will be much faster to select basic plant level information.


```abap
DATA: materials TYPE HASHED TABLE OF MARC WITH UNIQUE KEY MATNR.
SELECT * FROM MARC
WHERE WERKS = '0001'
INTO CORRESPONDING FIELDS OF TABLE materials.
```

can be replaced by

```abap
DATA: materials TYPE HASHED TABLE OF MARC WITH UNIQUE KEY MATNR.
SELECT * FROM V_MARC_MD
WHERE WERKS = '0001'
INTO CORRESPONDING FIELDS OF TABLE materials.
```
131 changes: 131 additions & 0 deletions src/checks/zcl_aoc_check_103.clas.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
CLASS zcl_aoc_check_103 DEFINITION
PUBLIC
INHERITING FROM zcl_aoc_super
CREATE PUBLIC.

PUBLIC SECTION.
CONSTANTS:
BEGIN OF gc_code,
table_has_replacement_object TYPE sci_errc VALUE '001',
END OF gc_code.

METHODS constructor.
METHODS check REDEFINITION.

PRIVATE SECTION.
CLASS-DATA gt_proxy_objects TYPE HASHED TABLE OF dd02v WITH UNIQUE KEY tabname.

METHODS get_tokens_for_statement
IMPORTING is_statement TYPE sstmnt
it_tokens TYPE stokesx_tab
RETURNING VALUE(rt_tokens) TYPE stokesx_tab.

METHODS get_table_info
IMPORTING iv_tabname TYPE tabname
RETURNING VALUE(rs_table_info) TYPE dd02v.
ENDCLASS.


CLASS zcl_aoc_check_103 IMPLEMENTATION.
METHOD constructor.
super->constructor( ).

version = '001'.
position = '103'.

has_documentation = abap_true.
has_attributes = abap_true.
attributes_ok = abap_true.

enable_rfc( ).

insert_scimessage( iv_code = gc_code-table_has_replacement_object
iv_text = 'Table/View &1 has replacement object &2'(m01) ).
ENDMETHOD.

METHOD check.
DATA lv_include TYPE sobj_name.
DATA lv_tabname TYPE tabname.
DATA lt_statement_tokens TYPE stokesx_tab.
DATA ls_next LIKE LINE OF lt_statement_tokens.
DATA ls_table_info TYPE dd02v.
FIELD-SYMBOLS <ls_statement> LIKE LINE OF io_scan->statements.
FIELD-SYMBOLS <ls_token> LIKE LINE OF io_scan->tokens.

LOOP AT io_scan->statements ASSIGNING <ls_statement>.

READ TABLE io_scan->tokens ASSIGNING <ls_token> INDEX <ls_statement>-from.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.

IF <ls_token>-str <> 'SELECT'.
CONTINUE.
ENDIF.

lt_statement_tokens = get_tokens_for_statement( is_statement = <ls_statement>
it_tokens = io_scan->tokens ).

READ TABLE lt_statement_tokens WITH KEY str = 'FROM' TRANSPORTING NO FIELDS.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
READ TABLE lt_statement_tokens INDEX sy-tabix + 1 INTO ls_next.
IF sy-subrc <> 0.
CONTINUE.
ENDIF.
lv_tabname = ls_next-str.

ls_table_info = get_table_info( lv_tabname ).

IF ls_table_info-viewref IS NOT INITIAL AND ls_table_info-viewref <> space.
lv_include = io_scan->get_include( <ls_statement>-level ).
inform( p_sub_obj_name = lv_include
p_line = <ls_token>-row
p_column = <ls_token>-col
p_kind = mv_errty
p_test = myname
p_param_1 = lv_tabname
p_param_2 = ls_table_info-viewref
p_code = gc_code-table_has_replacement_object ).

ENDIF.

ENDLOOP.
ENDMETHOD.

METHOD get_tokens_for_statement.
FIELD-SYMBOLS <ls_token> LIKE LINE OF it_tokens.

LOOP AT it_tokens FROM is_statement-from TO is_statement-to ASSIGNING <ls_token>.
APPEND <ls_token> TO rt_tokens.
ENDLOOP.
ENDMETHOD.

METHOD get_table_info.
DATA lv_destination TYPE rfcdest.
READ TABLE gt_proxy_objects WITH KEY tabname = iv_tabname INTO rs_table_info.
IF sy-subrc = 0.
RETURN.
ENDIF.


lv_destination = get_destination( ).
CALL FUNCTION 'DD_TABL_GET'
DESTINATION lv_destination
EXPORTING
tabl_name = iv_tabname
IMPORTING
dd02v_wa_a = rs_table_info
EXCEPTIONS
access_failure = 1
communication_failure = 2
system_failure = 3
OTHERS = 4.

IF sy-subrc <> 0 OR rs_table_info IS INITIAL.
RETURN.
ENDIF.
INSERT rs_table_info INTO TABLE gt_proxy_objects.
ENDMETHOD.
ENDCLASS.
108 changes: 108 additions & 0 deletions src/checks/zcl_aoc_check_103.clas.testclasses.abap
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
*"* use this source file for your ABAP unit test classes
CLASS ltcl_test DEFINITION
FINAL
FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT.

PRIVATE SECTION.
DATA mt_code TYPE string_table.
DATA ms_result TYPE scirest_ad.
DATA mo_check TYPE REF TO zcl_aoc_check_103.

METHODS setup.

METHODS assert_error_code
IMPORTING
iv_expected_error_code TYPE sci_errc.

METHODS assert_no_error_code.
METHODS execute_check.

METHODS database_select_01 FOR TESTING.
METHODS database_select_02 FOR TESTING.
METHODS database_select_03 FOR TESTING.

ENDCLASS.


CLASS ltcl_test IMPLEMENTATION.
DEFINE _code.
APPEND &1 TO mt_code.
END-OF-DEFINITION.

METHOD setup.
mo_check = NEW #( ).
zcl_aoc_unit_test=>set_check( mo_check ).
ENDMETHOD.

METHOD execute_check.
ms_result = zcl_aoc_unit_test=>check( mt_code ).
ENDMETHOD.

METHOD assert_error_code.
cl_abap_unit_assert=>assert_equals( exp = iv_expected_error_code
act = ms_result-code ).
ENDMETHOD.

METHOD assert_no_error_code.
cl_abap_unit_assert=>assert_initial( ms_result ).
ENDMETHOD.



METHOD database_select_03.
" Given
_code `SELECT *`.
_code ` FROM demo_sumdist`.
_code ` UP TO 1 ROWS`.
_code ` INTO @DATA(lv_host)`.
_code ` ORDER BY PRIMARY KEY.`.
_code `ENDSELECT.`.

" When
execute_check( ).

" Then
assert_error_code( zcl_aoc_check_103=>gc_code-table_has_replacement_object ).
ENDMETHOD.



METHOD database_select_01.
" Given
_code `SELECT host`.
_code ` FROM ztable`.
_code ` UP TO 1 ROWS`.
_code ` INTO @DATA(lv_host)`.
_code ` WHERE sysname = @sy-sysid`.
_code ` ORDER BY PRIMARY KEY.`.
_code `ENDSELECT.`.

" When
execute_check( ).

" Then
assert_no_error_code( ).
ENDMETHOD.

METHOD database_select_02.
" Given
_code `DATA lv_host TYPE string.`.
_code `SELECT host`.
_code ` FROM ztable`.
_code ` UP TO 1 ROWS`.
_code ` INTO lv_host`.
_code ` WHERE sysname = sy-sysid`.
_code ` ORDER BY PRIMARY KEY.`.
_code `ENDSELECT.`.

" When
execute_check( ).

" Then
assert_no_error_code( ).
ENDMETHOD.


ENDCLASS.
25 changes: 25 additions & 0 deletions src/checks/zcl_aoc_check_103.clas.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<abapGit version="v1.0.0" serializer="LCL_OBJECT_CLAS" serializer_version="v1.0.0">
<asx:abap xmlns:asx="http://www.sap.com/abapxml" version="1.0">
<asx:values>
<VSEOCLASS>
<CLSNAME>ZCL_AOC_CHECK_103</CLSNAME>
<LANGU>E</LANGU>
<DESCRIPT>103 - Select on Table with Replacement Object</DESCRIPT>
<STATE>1</STATE>
<CLSCCINCL>X</CLSCCINCL>
<FIXPT>X</FIXPT>
<UNICODE>X</UNICODE>
<WITH_UNIT_TESTS>X</WITH_UNIT_TESTS>
</VSEOCLASS>
<TPOOL>
<item>
<ID>I</ID>
<KEY>M01</KEY>
<ENTRY>Table/View &amp;1 has replacement object &amp;2</ENTRY>
<LENGTH>132</LENGTH>
</item>
</TPOOL>
</asx:values>
</asx:abap>
</abapGit>

0 comments on commit 17f6250

Please sign in to comment.