Skip to Content
Technical Articles
Author's profile photo Sandra Rossi

List of DDIC structures with erroneous Enhancement Category

In this blog post, I propose a little program to detect all DDIC structures and tables with invalid Enhancement Categories. It’s largely inspired by the SAP program Z_CHECK_ENH_CAT provided in the note 2205573 – Checking enhancement category for data dictionary objects with SAP tool, but this SAP program is to analyze just one given DDIC structure or table at a time.

The reason why I created this program was that after adding few more possible values to a custom DDIC domain and activating it, the activation log reported few standard DDIC structures with syntax errors, especially the DDIC structure PSHLP_CUSTFLDS_NTWK_ST. A check on it:
DDIC%20Structure%20check%20error

DDIC Structure check error

A fix is proposed by the note 1834868 – PSHLP: Syntax error in Customer field structures of HLP which consists in adjusting the Enhancement Category via SE11 > menu option Extras > Enhancement Category.

This syntax error didn’t seem to be a problem in production, but maybe this structure was actually never used. I created a little test program to use that DDIC structure, the program could activate, only a warning was reported by the Extended Check (SLIN).

I don’t know why it wasn’t detected earlier, so maybe we had other DDIC tables and structures in the same situation. It’s why I decided to extend the SAP program to detect all of them.

I named this custom program Z_CHECK_ENH_CAT_ALL.

The selection screen takes as input a list of packages, so you can type Z* to analyze all DDIC tables and structures which contain custom objects:

Selection%20screen%20of%20Z_CHECK_ENH_CAT_ALL

Selection screen of Z_CHECK_ENH_CAT_ALL

The result shows all analyzed DDIC tables and structures.

Just search “FAIL” to directly go to the errors.

Result%20of%20Z_CHECK_ENH_CAT_ALL

Result of Z_CHECK_ENH_CAT_ALL

In the example above, you can see that the Enhancement Category of ZBAPI_TE_DPR_PHASE is inconsistent. It’s because it includes BAPI_TE_DPR_PHASE whose Category is Can be Enhanced (without restriction), so ZBAPI_TE_DPR_PHASE Category should also be Can be Enhanced (at the time of the run it was Extensible alpha and numeric).

 

I hope this will help.

 

Source code (compiled and used on 7.40 SP08):

*This program extends z_check_enh_cat of note 2205573, copyright SAP.
*https://launchpad.support.sap.com/#/notes/2205573
*2205573 - Checking enhancement category for data dictionary objects with SAP tool

REPORT z_check_enh_cat_all LINE-SIZE 500.

TABLES tdevc.
SELECT-OPTIONS: s_devcl FOR tdevc-devclass DEFAULT 'Z*' OPTION CP.

TYPES: ty_tables TYPE STANDARD TABLE OF tabname WITH DEFAULT KEY.

TYPES:
  BEGIN OF ty_include,
    precfield TYPE char30,
    fieldname TYPE char30,
    rollname  TYPE char30,
  END OF ty_include,

  BEGIN OF ty_message,
    precfield TYPE char200,
  END OF ty_message.

DATA: g_wa_message TYPE ty_message,
      gt_message   TYPE TABLE OF ty_message,
      gv_deep      TYPE n.

START-OF-SELECTION.
  PERFORM main.

FORM main.

* 1. FIND ALL TABLES AND STRUCTURES TO BE CHECKED

  " starting from data elements
  SELECT dd03l~tabname
    FROM       tadir
    INNER JOIN tdevc   ON tdevc~devclass = tadir~devclass
    INNER JOIN dd03l   ON dd03l~rollname  = tadir~obj_name
                      AND dd03l~as4local  = 'A'
                      AND dd03l~as4vers   = 0
    WHERE tadir~devclass IN @s_devcl
      AND tadir~pgmid  = 'R3TR'
      AND tadir~object = 'DTEL'
  UNION
  SELECT dd03l_2~tabname
    FROM       tadir
    INNER JOIN tdevc   ON tdevc~devclass = tadir~devclass
    INNER JOIN dd03l   ON dd03l~rollname  = tadir~obj_name
                      AND dd03l~as4local  = 'A'
                      AND dd03l~as4vers   = 0
    INNER JOIN dd03l   AS dd03l_2
                       ON dd03l_2~precfield = dd03l~tabname
                      AND dd03l_2~fieldname LIKE '.INCLU%'
                      AND dd03l_2~as4local  = 'A'
                      AND dd03l_2~as4vers   = 0
    WHERE tadir~devclass IN @s_devcl
      AND tadir~pgmid  = 'R3TR'
      AND tadir~object = 'DTEL'
  UNION
  SELECT dd03l_3~tabname
    FROM       tadir
    INNER JOIN tdevc   ON tdevc~devclass = tadir~devclass
    INNER JOIN dd03l   ON dd03l~rollname  = tadir~obj_name
                      AND dd03l~as4local  = 'A'
                      AND dd03l~as4vers   = 0
    INNER JOIN dd03l   AS dd03l_2
                       ON dd03l_2~precfield = dd03l~tabname
                      AND dd03l_2~fieldname LIKE '.INCLU%'
                      AND dd03l_2~as4local  = 'A'
                      AND dd03l_2~as4vers   = 0
    INNER JOIN dd03l   AS dd03l_3
                       ON dd03l_3~precfield = dd03l_2~tabname
                      AND dd03l_3~fieldname LIKE '.INCLU%'
                      AND dd03l_3~as4local  = 'A'
                      AND dd03l_3~as4vers   = 0
    WHERE tadir~devclass IN @s_devcl
      AND tadir~pgmid  = 'R3TR'
      AND tadir~object = 'DTEL'
  " starting from domains
  UNION
  SELECT dd03l~tabname
    FROM       tadir
    INNER JOIN tdevc   ON tdevc~devclass = tadir~devclass
    INNER JOIN dd03l   ON dd03l~domname   = tadir~obj_name
                      AND dd03l~as4local  = 'A'
                      AND dd03l~as4vers   = 0
    WHERE tadir~devclass IN @s_devcl
      AND tadir~pgmid  = 'R3TR'
      AND tadir~object = 'DOMA'
  UNION
  SELECT dd03l_2~tabname
    FROM       tadir
    INNER JOIN tdevc   ON tdevc~devclass = tadir~devclass
    INNER JOIN dd03l   ON dd03l~domname   = tadir~obj_name
                      AND dd03l~as4local  = 'A'
                      AND dd03l~as4vers   = 0
    INNER JOIN dd03l   AS dd03l_2
                       ON dd03l_2~precfield = dd03l~tabname
                      AND dd03l_2~fieldname LIKE '.INCLU%'
                      AND dd03l_2~as4local  = 'A'
                      AND dd03l_2~as4vers   = 0
    WHERE tadir~devclass IN @s_devcl
      AND tadir~pgmid  = 'R3TR'
      AND tadir~object = 'DOMA'
  UNION
  SELECT dd03l_3~tabname
    FROM       tadir
    INNER JOIN tdevc   ON tdevc~devclass = tadir~devclass
    INNER JOIN dd03l   ON dd03l~domname   = tadir~obj_name
                      AND dd03l~as4local  = 'A'
                      AND dd03l~as4vers   = 0
    INNER JOIN dd03l   AS dd03l_2
                       ON dd03l_2~precfield = dd03l~tabname
                      AND dd03l_2~fieldname LIKE '.INCLU%'
                      AND dd03l_2~as4local  = 'A'
                      AND dd03l_2~as4vers   = 0
    INNER JOIN dd03l   AS dd03l_3
                       ON dd03l_3~precfield = dd03l_2~tabname
                      AND dd03l_3~fieldname LIKE '.INCLU%'
                      AND dd03l_3~as4local  = 'A'
                      AND dd03l_3~as4vers   = 0
    WHERE tadir~devclass IN @s_devcl
      AND tadir~pgmid  = 'R3TR'
      AND tadir~object = 'DOMA'
  " starting from tables
  UNION
  SELECT dd03l~tabname
    FROM       tadir
    INNER JOIN tdevc   ON tdevc~devclass = tadir~devclass
    INNER JOIN dd03l   ON dd03l~precfield = tadir~obj_name
                      AND dd03l~fieldname LIKE '.INCLU%'
                      AND dd03l~as4local  = 'A'
                      AND dd03l~as4vers   = 0
    WHERE tadir~devclass IN @s_devcl
      AND tadir~pgmid  = 'R3TR'
      AND tadir~object = 'TABL'
  UNION
  SELECT dd03l_2~tabname
    FROM       tadir
    INNER JOIN tdevc   ON tdevc~devclass = tadir~devclass
    INNER JOIN dd03l   ON dd03l~precfield = tadir~obj_name
                      AND dd03l~fieldname LIKE '.INCLU%'
                      AND dd03l~as4local  = 'A'
                      AND dd03l~as4vers   = 0
    INNER JOIN dd03l   AS dd03l_2
                       ON dd03l_2~precfield = dd03l~tabname
                      AND dd03l_2~fieldname LIKE '.INCLU%'
                      AND dd03l_2~as4local  = 'A'
                      AND dd03l_2~as4vers   = 0
    WHERE tadir~devclass IN @s_devcl
      AND tadir~pgmid  = 'R3TR'
      AND tadir~object = 'TABL'

    INTO TABLE @DATA(tables).

* 2. ANALYZE ALL STRUCTURES AND TABLES

  LOOP AT tables ASSIGNING FIELD-SYMBOL(<table>).
    WRITE / <table>-tabname COLOR 5.
    PERFORM check_one_table USING <table>-tabname.
  ENDLOOP.

ENDFORM.

FORM check_one_table USING p_table TYPE tabname.

  SELECT COUNT(*) FROM dd02l WHERE tabname = p_table AND as4local = 'A'.

  IF sy-subrc = 4.
    WRITE 'Table not found!'.
  ELSE.

    gt_message = VALUE #( ).

    PERFORM check_enhancements USING p_table
                                     ''.
    IF NOT gt_message[] IS INITIAL.
      LOOP AT gt_message INTO g_wa_message.
        WRITE: 'FAIL', g_wa_message.
        NEW-LINE NO-SCROLLING.
      ENDLOOP.
      WRITE 'The check was completed successfully!'.
    ELSE.
      WRITE 'No errors found!'.
    ENDIF.
  ENDIF.

ENDFORM.

FORM check_enhancements USING p_main_obj    TYPE char30
                              p_prev_obj    TYPE char30.

  DATA: lv_sub_ex   TYPE n, "EXCLASS/ ENHANCEMENT CATEGORY
        lv_main_ex  TYPE n,
        wa_includes TYPE ty_include,
        ls_includes TYPE TABLE OF ty_include,
        lv_curr_obj TYPE char30.

  lv_curr_obj = p_main_obj.

  SELECT SINGLE exclass FROM dd02l
    INTO lv_main_ex "Get the main structure
    WHERE tabname = lv_curr_obj AND as4local = 'A'.

  SELECT precfield fieldname rollname FROM dd03l "Get the fields
    INTO CORRESPONDING FIELDS OF wa_includes
    WHERE tabname = lv_curr_obj AND precfield <> '' AND as4local = 'A'. "( rollname = '' or datatype = 'STRU' ) AND AS4LOCAL = 'A'.

    APPEND wa_includes TO ls_includes.
  ENDSELECT.

  LOOP AT ls_includes INTO wa_includes.
    IF wa_includes-precfield <> ''.
      SELECT SINGLE exclass FROM dd02l INTO lv_sub_ex
        WHERE tabname = wa_includes-precfield AND as4local = 'A'.

      IF sy-subrc = 0 AND lv_main_ex < lv_sub_ex AND lv_main_ex <> 0 . "Check if will write
        PERFORM format_message USING p_main_obj
                                     wa_includes-precfield
                                     lv_sub_ex.
      ENDIF.
      PERFORM check_enhancements USING wa_includes-precfield "p_main_obj
                                       lv_curr_obj.          "previous
    ELSEIF wa_includes-rollname <> '' .
      SELECT SINGLE exclass FROM dd02l INTO lv_sub_ex
       WHERE tabname = wa_includes-rollname AND as4local = 'A' .

      IF sy-subrc = 0 AND lv_main_ex < lv_sub_ex AND lv_main_ex <> 0. "Check if will write
        PERFORM format_message USING p_main_obj
                                     wa_includes-rollname
                                     lv_sub_ex.
      ENDIF.
      PERFORM check_enhancements USING wa_includes-fieldname "p_main_obj
                                       lv_curr_obj.          "previous
    ENDIF.
  ENDLOOP.

ENDFORM.

FORM format_message USING p_main_obj  TYPE tabname
                          p_sub_obj   TYPE tabname
                          p_obj_ex    TYPE n.

  DATA lw_message TYPE ty_message.

  CONCATENATE lw_message p_sub_obj INTO lw_message.
  CONCATENATE lw_message 'has a bigger enhancement category than' p_main_obj INTO lw_message SEPARATED BY space.
  CONCATENATE lw_message '.' INTO lw_message.
  CONCATENATE lw_message p_sub_obj 'is set to ' INTO lw_message SEPARATED BY space.

  IF p_obj_ex   = 1.
    CONCATENATE lw_message '(Cannot be enhanced)' INTO lw_message SEPARATED BY space.
  ELSEIF p_obj_ex   = 2.
    CONCATENATE lw_message '(Can be enhanced (character-type)' INTO lw_message SEPARATED BY space.
  ELSEIF p_obj_ex   = 3.
    CONCATENATE lw_message '(Can be enhanced (character-type or numeric))' INTO lw_message SEPARATED BY space.
  ELSEIF p_obj_ex   = 4.
    CONCATENATE lw_message '(Can Be Enhanced (DEEP))' INTO lw_message SEPARATED BY space.
  ENDIF.

  APPEND lw_message TO gt_message.
  CLEAR lw_message.

ENDFORM.

 

Assigned Tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Paul Hardy
      Paul Hardy

      This is a program from an SAP note you have adapted as I understand it?

      That is, SAP are - in 2022 - 22 years after ABAP Objects - providing programs with FORM routines as modularization units, and this is not even a procedural program as the bulk if the logic is in a big blob after START-Of-SELECTION.

      We all have to write quick and dirty quick fix programs but I just cannot bear to have all the code after START-OF-SELECTION. At the very minimum I have the quick and dirty code in a FORM routine.

      I am also bursting to know what the ASSERT 1 = 1 thing is all about.

      And while I am here ... in some systems at work when I create a new structure or table the enhancement category defaults to "cannot be modified" which is good as a default. In some systems it does not, same as historically and when you activate the structure/table you get the "enhancement category not defined" warning. What is controlling that? Our German system has a higher support stack level than our AUS system and yet the AUS system gets the "good" behaviour and the DE system gets the "bad" behaviour.

       

      Author's profile photo Sandra Rossi
      Sandra Rossi
      Blog Post Author

      Yes, the subroutines of the check part comes from the SAP program Z_CHECK_ENH_CAT provided in the note 2205573 – Checking enhancement category for data dictionary objects with SAP tool. I just added a part to repeat the check for each structure and table that contains DDIC objects (tables, structures, data elements, domains) of given packages.

      It's a quick and dirty program, "one-time" usage. Just copy/paste in your system if you need to scan your system, and delete it after usage. Better sharing it than keeping it just for me, it could help. I moved the code into a form and I removed ASSERT 1 = 1 (I use it to just add a breakpoint at parts where the debugger can't go, like end of event, end of implicit enhancement, and so on).

      No idea about the default enhancement category.