* _______ _______ _______ _______ _______ _______ ______ _______ _______ ______ _______ * | _ | _ | _ | | | _ | || _ | _ | _ | | _ | * | |_| | |_| | |_| | _ | | |_| | _ | |_| | |_| | | || | |_| | * | | | | |_| | | | | | | | | |_||_| | * | | _ || | ___| _| | |_| | | _ || __ | | * | _ | |_| | _ | | | |_| _ | | _ | |_| | | | | _ | * |__| |__|_______|__| |__|___| |_______|__| |__|______||__| |__|_______|___| |_|__| |__| * 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: '', '
' 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.