* _______ _______ _______ _______ _______ _______ ______ _______ _______ ______ _______ * | _ | _ | _ | | | _ | || _ | _ | _ | | _ | * | |_| | |_| | |_| | _ | | |_| | _ | |_| | |_| | | || | |_| | * | | | | |_| | | | | | | | | |_||_| | * | | _ || | ___| _| | |_| | | _ || __ | | * | _ | |_| | _ | | | |_| _ | | _ | |_| | | | | _ | * |__| |__|_______|__| |__|___| |_______|__| |__|______||__| |__|_______|___| |_|__| |__| * www.abapcadabra.com *------------------------------------------------------------------------------------------- * program : ZABAPCADABRA_TABLE_DOCUMENTER * title : Table documentation generator - Table(field, field,... * functional area : X-component * environment : 4.7 * program Function : This report shows the classic notation for a table definition * where table name, key fields and normal fields (and foreign * keys) are all shown in a very compact manner. As this formatting * requires undelines, the output is in HTML. * Documentation : Search for "Table(field, field,.. " on AbapcadabrA.com * Previous version : This is the initial version * Developer name : Wim Maasdam * Development date : 03-04-2017 * Version : 0.1 *--------------------------------------------------------------------- * Change list: * Date Description * 03-04-2017 Initial release *--------------------------------------------------------------------- REPORT zabapcadabra_table_documenter. TABLES: dd02l, dd03l. "Selection screen purpose only CLASS lcl_report_scanner DEFINITION DEFERRED. CLASS lcl_controller DEFINITION. PUBLIC SECTION. CONSTANTS: co_undetermined TYPE c LENGTH 20 VALUE '~???~', co_field_error TYPE c LENGTH 20 VALUE '~XXX~'. TYPES: begin of ty_tvdir, tabname type tvdir-tabname, end of ty_tvdir. CLASS-DATA: gr_tabname TYPE RANGE OF dd02l-tabname, gw_tabname LIKE LINE OF gr_tabname, gr_fieldname TYPE RANGE OF dd03l-fieldname, go_container TYPE REF TO cl_gui_custom_container, go_viewer TYPE REF TO cl_gui_html_viewer, gv_url TYPE c LENGTH 200, gt_dd02l TYPE STANDARD TABLE OF dd02l, gw_dd02l TYPE dd02l, gt_dd02t TYPE STANDARD TABLE OF dd02t, gw_dd02t TYPE dd02t, gt_dd03l TYPE STANDARD TABLE OF dd03l, gw_dd03l TYPE dd03l, gt_TVDIR TYPE SORTED TABLE OF ty_tvdir WITH UNIQUE KEY tabname, gt_html TYPE STANDARD TABLE OF char120, gv_okcode TYPE sy-ucomm. CLASS-METHODS: main_selection, compose_html_report, get_sap_description IMPORTING fieldreference TYPE any language TYPE sy-langu DEFAULT sy-langu RETURNING VALUE(description) TYPE text80. ENDCLASS. class lcl_report_scanner definition FINAL. PUBLIC SECTION. types: begin of ty_scan_results, table type c length 40, level type c length 12, counter type i, end of ty_scan_results. class-data: gv_main_program type sy-repid, gt_sourcecode type standard table of char255, gt_scan_results type sorted table of ty_scan_results with unique key table level, gw_scan_results type ty_scan_results. class-methods: initialize importing main_program type any, scan_for_DB_actions. PRIVATE SECTION. class-methods: set_result importing level type any tablename type any. endclass. CLASS lcl_controller IMPLEMENTATION. METHOD main_selection. DATA: lt_dd03l TYPE STANDARD TABLE OF dd03l, lw_dd03l TYPE dd03l, lw_dd02l type dd02l. * Listing of Ztables, in boyce-codd vorm SELECT * FROM dd02l INTO TABLE gt_dd02l WHERE tabname IN gr_tabname AND tabclass in ('TRANSP', 'CLUSTER') and AS4LOCAL = 'A'. IF sy-subrc = 0. IF NOT gr_fieldname[] IS INITIAL. SELECT * FROM dd03l INTO TABLE lt_dd03l FOR ALL ENTRIES IN gt_dd02l WHERE tabname = gt_dd02l-tabname AND fieldname IN gr_fieldname and AS4LOCAL = 'A'. * Filter the tables that don't have the fields that * are defined on the selection screen. loop at gt_dd02l into lw_dd02l. read table lt_dd03l with key tabname = lw_dd02l-tabname TRANSPORTING NO FIELDS. if sy-subrc <> 0. delete gt_dd02l. endif. endloop. ENDIF. if not gt_dd02l[] is initial. SELECT * FROM dd02t INTO TABLE gt_dd02t FOR ALL ENTRIES IN gt_dd02l WHERE tabname = gt_dd02l-tabname and AS4LOCAL = 'A'. SELECT * FROM dd03l INTO TABLE gt_dd03l FOR ALL ENTRIES IN gt_dd02l WHERE tabname = gt_dd02l-tabname and AS4LOCAL = 'A'. SORT gt_dd03l BY tabname position. SELECT tabname FROM tvdir INTO CORRESPONDING FIELDS OF TABLE gt_TVDIR FOR ALL ENTRIES IN gt_dd02l WHERE tabname = gt_dd02l-tabname. endif. ENDIF. ENDMETHOD. METHOD compose_html_report. DATA: lv_html_line TYPE string, lv_type TYPE c LENGTH 30, lt_html TYPE STANDARD TABLE OF char120, lv_fieldname TYPE c LENGTH 40, lv_first TYPE boolean, lv_tabix type sy-tabix, lv_fields type sy-tabix, lv_hlpvar type c length 12, lw_trdirt type trdirt. CLEAR: gt_html[], lt_html[]. DEFINE sethtml. append &1 to gt_HTML. END-OF-DEFINITION. sethtml: '', 'Table notation', '', '', '', '', '
Total number of tables:', '', '
..
'. LOOP AT gt_dd02l INTO gw_dd02l. CLEAR lv_html_line. * Table description READ TABLE gt_dd02t INTO gw_dd02t WITH KEY tabname = gw_dd02l-tabname ddlanguage = sy-langu. if sy-subrc <> 0. READ TABLE gt_dd02t INTO gw_dd02t WITH KEY tabname = gw_dd02l-tabname. endif. IF sy-subrc = 0. CONCATENATE '

' gw_dd02t-ddtext '' INTO lv_html_line. ELSE. CONCATENATE '

' 'No description ' INTO lv_html_line. ENDIF. if gw_dd02t-ddlanguage <> sy-langu. concatenate lv_html_line ' (' gw_dd02t-ddlanguage ')' into lv_html_line. endif. APPEND lv_html_line TO gt_html. read table gt_TVDIR with key tabname = gw_dd02l-tabname TRANSPORTING NO FIELDS. if sy-subrc = 0. sethtml '(Has table maintenance)'. endif. * For the tables that were reported as "used in main report", details on the usage: if not lcl_report_scanner=>gt_scan_results[] is initial. lv_html_line = '
'. loop at lcl_report_scanner=>gt_scan_results into lcl_report_scanner=>gw_scan_results where table = gw_dd02l-tabname. lv_hlpvar = lcl_report_scanner=>gw_scan_results-counter. concatenate lv_hlpvar 'x' into lv_hlpvar. condense lv_hlpvar NO-GAPS. concatenate lv_html_line lv_hlpvar lcl_report_scanner=>gw_scan_results-level into lv_html_line SEPARATED BY space. endloop. concatenate lv_html_line '' into lv_html_line. sethtml lv_html_line. endif. * Table itself CONCATENATE '
' gw_dd02l-tabname ' (' INTO lv_html_line. sethtml lv_html_line. * The fields: lv_first = abap_true. clear lv_fields. LOOP AT gt_dd03l INTO gw_dd03l WHERE tabname = gw_dd02l-tabname AND fieldname(5) <> '.INCL'. * Field description and type definition: CONCATENATE gw_dd02l-tabname gw_dd03l-fieldname INTO lv_fieldname SEPARATED BY '-'. lv_html_line = get_sap_description( fieldreference = lv_fieldname language = gw_dd02t-ddlanguage ). WRITE: gw_dd03l-leng TO lv_type NO-ZERO LEFT-JUSTIFIED. SHIFT lv_type RIGHT BY 1 PLACES. lv_type(1) = gw_dd03l-inttype. CONCATENATE ' (' lv_type ')' INTO lv_type. CONDENSE lv_type NO-GAPS. CONCATENATE '"' gw_dd03l-fieldname '":"' lv_html_line lv_type '",' INTO lv_html_line. APPEND lv_html_line TO lt_html. * Field IF gw_dd03l-keyflag = abap_true. CONCATENATE ', ' gw_dd03l-fieldname '' INTO lv_html_line. ELSE. * Foreign key field ? READ TABLE gt_dd03l WITH KEY fieldname = gw_dd03l-fieldname keyflag = abap_true TRANSPORTING NO FIELDS. IF sy-subrc = 0. CONCATENATE ', ' gw_dd03l-fieldname '' INTO lv_html_line. ELSE. CONCATENATE ', ' gw_dd03l-fieldname '' INTO lv_html_line. ENDIF. ENDIF. IF lv_first = abap_true. CLEAR lv_first. SHIFT lv_html_line LEFT BY 2 PLACES. ENDIF. APPEND lv_html_line TO gt_html. add 1 to lv_fields. ENDLOOP. if lv_fields > 10. lv_html_line = lv_fields. condense lv_html_line. concatenate ') ' lv_html_line ' fields' into lv_html_line. else. lv_html_line = ')'. endif. sethtml lv_html_line. ENDLOOP. sethtml ''. SORT lt_html. DELETE ADJACENT DUPLICATES FROM lt_html. * Now place the lt_HTML results in the gt_HTML table, where '/* DEFINITIONS */' is waiting to be replaced: READ TABLE gt_html WITH KEY table_line = '/* DEFINITIONS */' TRANSPORTING NO FIELDS. IF sy-subrc = 0. INSERT LINES OF lt_html INTO gt_html INDEX sy-tabix. ENDIF. READ TABLE gt_html WITH KEY table_line = '' TRANSPORTING NO FIELDS. IF sy-subrc = 0. lv_tabix = sy-tabix. describe table gt_dd02l lines lv_html_line. condense lv_html_line. MODIFY gt_html FROM lv_html_line INDEX lv_tabix. if not lcl_report_scanner=>gt_scan_results[] is initial. subtract 1 from lv_tabix. select single * from trdirt into lw_trdirt where name = lcl_report_scanner=>gv_main_program and sprsl = sy-langu. if sy-subrc <> 0. select * from trdirt into lw_trdirt up to 1 rows where name = lcl_report_scanner=>gv_main_program. endselect. if sy-subrc <> 0. clear lw_trdirt. endif. endif. Concatenate '
Main program:' lcl_report_scanner=>gv_main_program lw_trdirt-text into lv_html_line SEPARATED BY space. INSERT lv_html_line INTO gt_html INDEX lv_tabix. endif. ENDIF. ENDMETHOD. METHOD get_sap_description. DATA: lv_tabname TYPE c LENGTH 20, lv_fieldname TYPE c LENGTH 25, lv_description TYPE dd03t-ddtext, lv_rollname TYPE dd03l-rollname, lv_scrtext_m TYPE dd04t-scrtext_m, lv_translation_subtoken TYPE string, lv_abap_token TYPE string, lv_hlp TYPE string. * Fetch SAP description if possible: CLEAR lv_description. IF NOT fieldreference IS INITIAL. lv_description = co_undetermined. SPLIT fieldreference AT '-' INTO lv_tabname lv_fieldname. IF NOT lv_fieldname IS INITIAL. SELECT ddtext FROM dd03t INTO lv_description UP TO 1 ROWS WHERE tabname = lv_tabname AND fieldname = lv_fieldname AND as4local = 'A' AND ddlanguage = language. ENDSELECT. IF sy-subrc <> 0. SELECT rollname FROM dd03l INTO lv_rollname UP TO 1 ROWS WHERE tabname = lv_tabname AND fieldname = lv_fieldname AND as4local = 'A' AND as4vers = 0000. ENDSELECT. IF sy-subrc = 0. lv_scrtext_m = co_field_error. SELECT SINGLE scrtext_m FROM dd04t INTO lv_scrtext_m WHERE rollname = lv_rollname AND ddlanguage = language AND as4local = 'A' AND as4vers = 0000. lv_description = lv_scrtext_m. ENDIF. ENDIF. ELSE. * Structure name ? SELECT ddtext FROM dd02t INTO lv_description UP TO 1 ROWS WHERE tabname = lv_tabname AND as4local = 'A' AND ddlanguage = language. ENDSELECT. IF sy-subrc = 0. concatenate 'Structure' lv_description into lv_description SEPARATED BY space. ENDIF. ENDIF. ENDIF. description = lv_description. replace all OCCURRENCES OF '"' in description with '#'. ENDMETHOD. ENDCLASS. class lcl_report_scanner implementation. method initialize. data: lt_sourcecode2 type standard table of char255, lv_sourcecode type char255, lv_sourcecode2 type char255, lv_include_name type char255, lv_tabix type sy-tabix, lv_tabix_num type n length 5, lv_devclass type tadir-devclass. data: lt_keywords type standard table of char50, lt_statements type standard table of SSTMNT, lw_statement TYPE SSTMNT, lw_statement2 TYPE SSTMNT, lt_tokens type standard table of STOKES, lw_token TYPE STOKES. gv_main_program = main_program. clear: gt_sourcecode[]. * Read the main report read report gv_main_program into gt_sourcecode. check sy-subrc = 0. * Perform the SCAN - with focus on local and global data declarations append 'INCLUDE' to lt_keywords. * Position 200 onwards is used to identify the original main source and line loop at gt_sourcecode into lv_sourcecode. lv_tabix_num = sy-tabix. concatenate '"' gv_main_program lv_tabix_num into lv_sourcecode+200 SEPARATED BY space. modify gt_sourcecode from lv_sourcecode. endloop. * Resolve includes in n rounds (include in include in include in ...): do 5 times. scan abap-source gt_sourcecode KEYWORDS FROM lt_keywords STATEMENTS INTO lt_statements TOKENS INTO lt_tokens. delete lt_tokens where STR = 'INCLUDE'. sort lt_tokens by row descending. "< Insert Includes BOTTOM UP loop at lt_tokens into lw_token. lv_tabix = lw_token-row + 1. lv_include_name = lw_token-str. select single devclass from tadir into lv_devclass where pgmid = 'R3TR' and object = 'PROG' and obj_name = lv_include_name. if sy-subrc = 0 and ( lv_devclass(1) = 'Z' or lv_devclass(1) = 'Y' ). * Read include coding read report lv_include_name into lt_sourcecode2. if sy-subrc = 0. concatenate '* Resolved INCLUDE >>' lv_include_name into lv_sourcecode SEPARATED BY space. modify gt_sourcecode from lv_sourcecode index lw_token-row. loop at lt_sourcecode2 into lv_sourcecode2. * Position 200 onwards is used to identify the original include source and line lv_tabix_num = sy-tabix. concatenate '"' lv_include_name lv_tabix_num into lv_sourcecode2+200 SEPARATED BY space. modify lt_sourcecode2 from lv_sourcecode2. endloop. insert lines of lt_sourcecode2 into gt_sourcecode index lv_tabix. endif. endif. endloop. enddo. endmethod. method scan_for_DB_ACTIONS. data: lt_keywords type standard table of char50, lt_statements type standard table of SSTMNT, lw_statement TYPE SSTMNT, lt_tokens type standard table of STOKES, lw_token TYPE STOKES, lv_prelevel type c length 20, lv_level type c length 20, lv_tabname type dd02l-tabname. * Perform the SCAN - with focus on local and global data declarations append 'INSERT' to lt_keywords. append 'MODIFY' to lt_keywords. append 'UPDATE' to lt_keywords. append 'DELETE' to lt_keywords. append 'SELECT' to lt_keywords. append 'EXPORT' to lt_keywords. append 'IMPORT' to lt_keywords. scan abap-source gt_sourcecode KEYWORDS FROM lt_keywords STATEMENTS INTO lt_statements TOKENS INTO lt_tokens. clear: lv_LEVEL. loop at lt_statements into lw_statement. loop at lt_tokens into lw_token from lw_statement-from to lw_statement-to. case lw_token-STR. when 'MODIFY' or 'UPDATE' or 'INSERT' or 'DELETE'. lv_level = lw_token-STR. when 'FROM'. lv_level = 'SELECT'. when 'IMPORT' or 'EXPORT'. lv_prelevel = lw_token-STR. when 'DATABASE'. lv_level = lv_prelevel. when others. if not lv_level is initial and lw_token-STR <> 'SCREEN'. if lw_token-STR cs '('. split lw_token-STR at '(' into lw_token-STR lv_tabname. clear lv_tabname. endif. * Test the table name, which is not the active token. It this a transparent table ? select single tabname from dd02l into lv_tabname where tabname = lw_token-STR and as4local = 'A' and as4vers = 0000 and tabclass in ('TRANSP', 'CLUSTER'). if sy-subrc = 0. set_result( level = lv_level tablename = lw_token-STR ). endif. endif. clear lv_level. endcase. endloop. endloop. endmethod. method set_result. data: lw_scan_results type ty_scan_results. read table gt_scan_results with key table = tablename level = level into lw_scan_results. if sy-subrc = 0. add 1 to lw_scan_results-counter. modify gt_scan_results from lw_scan_results index sy-tabix. else. lw_scan_results-table = tablename. lw_scan_results-level = level. lw_scan_results-counter = 1. insert lw_scan_results into table gt_scan_results. endif. endmethod. endclass. *--------------------------------------------------------------------- * S E L E C T I O N - S C R E E N *--------------------------------------------------------------------- SELECTION-SCREEN BEGIN OF LINE. SELECTION-SCREEN COMMENT 1(22) lbl_01 FOR FIELD so_tabnm. SELECT-OPTIONS: so_tabnm FOR dd02l-tabname NO INTERVALS. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN BEGIN OF LINE. SELECTION-SCREEN COMMENT 1(22) lbl_02 FOR FIELD so_fldnm. SELECT-OPTIONS: so_fldnm FOR dd03l-fieldname NO INTERVALS. SELECTION-SCREEN END OF LINE. SELECTION-SCREEN SKIP. SELECTION-SCREEN BEGIN OF LINE. SELECTION-SCREEN COMMENT 1(25) lbl_03 FOR FIELD pa_main. parameter: pa_main like sy-repid. SELECTION-SCREEN END OF LINE. *--------------------------------------------------------------------- * I N I T I A L I Z A T I O N *--------------------------------------------------------------------- INITIALIZATION. if so_tabnm[] is initial and pa_main is initial. append 'ICPZ*' to so_tabnm. endif. * All texts for this report have been set up as hard-coded texts (no use * of the report text-pool). Reason: easy copying of report source code. lbl_01 = 'Table'. lbl_02 = 'Only with field'. lbl_03 = 'Main program'. *--------------------------------------------------------------------- * S T A R T - O F - S E L E C T I O N *--------------------------------------------------------------------- START-OF-SELECTION. if not pa_main is initial. lcl_report_scanner=>initialize( pa_main ). lcl_report_scanner=>scan_for_DB_ACTIONS( ). clear: lcl_controller=>gw_tabname. lcl_controller=>gw_tabname = 'IEQ'. loop at lcl_report_scanner=>gt_scan_results into lcl_report_scanner=>gw_scan_results where table in so_tabnm[]. lcl_controller=>gw_tabname-low = lcl_report_scanner=>gw_scan_results-table. append lcl_controller=>gw_tabname to lcl_controller=>gr_tabname. endloop. else. lcl_controller=>gr_tabname[] = so_tabnm[]. endif. lcl_controller=>gr_fieldname[] = so_fldnm[]. if lcl_controller=>gr_tabname[] is initial. message 'No data selected' type 'S'. else. lcl_controller=>main_selection( ). if lcl_controller=>gt_dd02l[] is initial. message 'No data selected' type 'S'. else. lcl_controller=>compose_html_report( ). CALL SCREEN 900 STARTING AT 10 2 ENDING AT 130 28. endif. endif. *--------------------------------------------------------------------- * S C R E E N M O D U L E S *--------------------------------------------------------------------- MODULE status_0900 OUTPUT. IF lcl_controller=>go_container IS INITIAL. CREATE OBJECT lcl_controller=>go_container EXPORTING container_name = 'HTML' EXCEPTIONS OTHERS = 4. IF sy-subrc = 0. CREATE OBJECT lcl_controller=>go_viewer EXPORTING parent = lcl_controller=>go_container EXCEPTIONS OTHERS = 4. IF sy-subrc = 0. lcl_controller=>go_viewer->load_data( IMPORTING assigned_url = lcl_controller=>gv_url CHANGING data_table = lcl_controller=>gt_html ). lcl_controller=>go_viewer->show_url( EXPORTING url = lcl_controller=>gv_url ). ENDIF. ENDIF. IF sy-subrc <> 0. MESSAGE 'Error from which I cannot recover... ' TYPE 'W'. ENDIF. ENDIF. ENDMODULE. MODULE user_command_0900 INPUT. LEAVE TO SCREEN 0. ENDMODULE.