2017년 1월 30일 월요일

ZTOAD

*&---------------------------------------------------------------------*
*& Program : ZTOAD
*& Author  : S. Hermann
*& Date    : 06.07.2016
*& Version : 3.5.1
*& Required: Table ZTOAD
*&---------------------------------------------------------------------*
*& This program allow you to execute query directly on the server
*& 1/ Write your query in the editor window (ABAP SQL)
*& 2/ View the result in ALV window (in case of SELECT query)
*&
*3 Features :
*& The top center pane allow you to write your query in ABAP SQL format.
*= Query can be complex with JOIN, UNION and subqueries. You can write
*= query on several lines. You could also add spaces.
*= To add comment, start the line by * or prefix your comment by "
*&
*& You could write several queries in the query editor, separated by
*= dot ".". To execute one of them, highlight all the wanted query,
*= or just put the cursor anywhere inside the wanted query.
*= By default, the last query is executed.
*&
*& In case of error, you can display generated code to help you to
*= correct your query (only if you have S_DEVELOP access)
*&
*& F1 Help is managed to help you on ABAP SQL Syntax
*& Code completion is also available :
*& - TAB to autocomplete with tooltip word
*& - CTRL + ESPACE to display list of available words
*& Be carefull to not use with INSERT statement (see below)
*&
*& The top left pane allow you to store your query :
*& - You could save your query to reuse it later
*& - You could share your query : define users, usergroup, all
*& - You could export query into file to reuse it on another server
*&
*& The top right pane display ddic object that is currently used to help
*= you to write the proper query
*& Synergy with ZSPRO program : display tables defined in ZSPRO in the
*= ddic tree
*& Tips : You can search a table in the tree using header clic
*&
*3 Managed queries
*& SELECT, INSERT, UPDATE, DELETE, Any native SQL command
*&
*3 About New SQL Query Syntax
*& You could use new syntax (if your SAP system manage it)
*& ZTOAD autmatically detect if you are using new sytax when:
*& - You separated your selected fields with comma
*& - You prefixed your variable with @ in the INTO TABLE statement
*&
*3 Select Clause managed
*& SELECT [DISTINCT / SINGLE] select clause
*& FROM from clause
*& [UP TO x ROWS]
*& [WHERE cond1]
*& [GROUP BY fields1]
*& [HAVING cond2]
*& [ORDER BY fields2]
*& [UNION SELECT...]
*&
*& UP TO (Default max rows) ROWS added at end of query if omitted
*& You could force select without limits by adding UP TO 0 ROWS
*&
*& COUNT, AVG, MAX, MIN, SUM are managed
*& DO NOT FORGET SPACE in ( ) of aggregat
*&
*3 Insert special syntax
*& In ABAP, insert query is always used with given structure
*& In this SQL editor, you have 2 ways to do an INSERT :
*& - By passing each value, 1 by 1
*E INSERT SEOCLASSTX VALUES ( 'ZZMACLASS', ' ', 'Test claSS' )
*&
*& - By passing value of used fields only
*E INSERT SEOCLASSTX SET CLSNAME = 'ZZMACLASS' DESCRIPT = 'TeSt class'
*&
*3 Native SQL special syntax
*& To execute a native SQL command, please add the prefix NATIVE
*& before your query
*& NATIVE CREATE INDEX 'TESTINDEX' ON T001 (MANDT, WAERS, BUKRS)
*& NATIVE DROP INDEX 'TESTINDEX'
*&
*3 Sample of query :
*&
*E SELECT SINGLE * FROM VBAP WHERE VBELN = '00412345678'
*&
*E SELECT COUNT( * ) SUBC MAX( PROG ) FROM TRDIR GROUP BY SUBC
*&
*E SELECT VBAK~* from VBAK UP TO 3 ROWS ORDER BY VKORG.
*&
*E SELECT T1~VBELN T2~POSNR FROM VBAk AS T1
*E        JOIN VBAP AS T2 ON T1~VBELN = T2~VBELN
*&
*E INSERT SEOCLASSTX VALUES ( 'ZZMACLASS', ' ', 'Test claSS' )
*&
*E INSERT SEOCLASSTX SET CLSNAME = 'ZZMACLASS' DESCRIPT = 'TeSt class'
*&
*E UPDATE SEOCLASSTX SET DESCRIPT = 'txt' WHERE CLSNAME = 'ZZMACLASS'
*&
*E DELETE SEOCLASSTX WHERE CLSNAME = 'ZZMACLASS'
*&
*& Please send comment & improvements to http://quelquepart.biz
*&---------------------------------------------------------------------*
*& History :
*& 2016.07.06 v3.5.1:Fix Auth issue
*&                   Fix Dump on select with no empty selection part
*& 2016.03.28 v3.5  :Add Value Help on DDIC field. Select a value to
*&                       paste in editor
*&                   Add Button Execute into file to download results
*&                       instead of display it in ALV
*&                   Mod Use class CL_RSAWB_SPLITTER_FOR_TOOLBAR for
*&                       creation of DDIC toolbar
*&                   Add Refresh the DDIC tree when executing a query
*&                       even if error found
*& Thanks to Patrick Prime Reinoso for the following changes :
*&                   Fix Remove confirmation popup on display code for
*&                       no select statement
*&                   Add Option to display technical name in ALV
*&                   Mod Move option button to main toolbar
*&                   Mod Rename subroutines (code cleaning)
*&                   Mod Allow save on exit popup
*&                   Add New query button
*&                   Mod New query template changed
*& 2015.11.07 v3.4.3:Fix dump if cursor on first position
*&                   Fix prevent dump on too many sql run
*& 2015.11.07 v3.4.2:Fix cancel of save query popup
*&                   Fix Allow usage of " and . inside ''
*& 2015.11.01 v3.4.1:Fix issue with delete all history context menu
*& 2015.09.19 v3.4  :Add Code completion on SQL editor
*&                   Thanks to Benjamin Krencker for his code
*&                   Add Remove useless APPENDING TABLE statement in qry
*& 2015.09.13 v3.3  :Add New Options panel to save user preferences
*&                   Add Delete all history entries context menu
*&                   Add option to add linebreak after paste field from
*&                       ddic tree
*&                   Add Count column in alv grid display
*&                   Thanks again to Shai Sinai for his suggestions
*& 2015.09.06 v3.2.1:Mod Default limit to 100 rows is now optional
*& 2015.08.30 v3.2  :Add Manage new SQL Syntax introduced by NW7.40 SP5
*&                   Add Remove useless INTO TABLE statement in query
*&                   Add All NATIVE Sql commands
*&                   Mod Auth object use now the sap standard way
*&                   Fix Dump in case of up to xx rows in unioned query
*&                   Fix Dump at activation if ZSPRO does not exist
*&                   Fix Compatibility issues with older sap system
*& 2015.08.05 v3.1  :Add Manage drag&drop from DDIC tree to SQL Editor
*&                   Mod Double clic on field in DDIC tree paste field
*&                       in editor instead of filling clipboard
*&                   Thanks to Shai Sinai for his suggestions
*& 2015.06.13 v3.0  :Add INSERT, UPDATE, DELETE command
*&                   Add Authorization management
*&                   Add History tree display first query line if it
*&                       is a comment line
*&                   Mod Code cleaning
*& 2015.03.05 v2.1.1:Mod grid size is no more changed before display
*&                       query result
*& 2015.01.11 v2.1  :Add UNION instruction managed to merge 2 queries
*&                   Mod Do not refresh result grid for count(*)
*&                   Mod Back close the grid instead of leave program if
*&                       result grid is displayed
*&                   Add Display program header as default help
*&                   Add Run highlighted query
*&                   Mod Documentation rewritten
*& 2014.10.23 v2.0.2:Add Display number of entries found
*&                   Add Confirmation before exit for unsaved queries
*& 2014.10.19 v2.0.1:Fix bug on search ddic function
*& 2014.08.03 v2.0 : Completely rewritten version
*&                   - Save and share queries with colaborators
*&                   - Queries are now saved in database
*&                   - Display tables (+ fields) of the where clause
*&                   - Display ZSPRO entries in ddic tree
*&                   - Allow direct change in query after execution
*&                   - Count( * ) allowed
*&                   - Can display generated code
*&                   - Display query execution time
*&                   - Allow write of several queries (but 1 executed)
*& 2013.12.03 v1.3 : Allow case sensitive constant in where clause
*& 2012.08.30 v1.2 : Rewrite data definition to avoid dump on too long
*&                   fieldname
*& 2012.04.01 v1.1 : Updated to work also on BW system
*& 2009.10.26 v1.0 : Initial release
*&---------------------------------------------------------------------*

REPORT ztoad.
TYPE-POOLS abap.

*######################################################################*
*
*                        CUSTOMIZATION SECTION
*
*######################################################################*
DATA BEGIN OF s_customize,                                "#EC NEEDED
* Default number of lines to return for SELECT if no "up to xxx rows"
* defined in the query.
* Set to 0 if you dont want default limit.
         default_rows TYPE VALUE '100',

* When you dblclic on a field in the ddic tree, field is pasted to
* editor at the cursor position
* You could choose to add a linebreak after the field pasted
         paste_break(1TYPE VALUE space"abap_true to break

* In ALV grid result, display technical name instead of column label
         techname(1TYPE VALUE space"abap_true for technical

* You could define your authorization object to restrict
* function usage by user
* If you dont define auth object, all users will have same access as
* defined bellow
* The auth object have 2 fields TABLE and ACTVT
* ACTVT can take 5 values that you could define here. By default :
* 01 for INSERT command
* 02 for UPDATE command
* 03 for SELECT command
* 06 for DELETE command
* 16 for EXECUTE NATIVE SQL command
* TABLE contain allowed table name pattern
* '*' to allow all table, 'Z*' to allow all specific tables...
         auth_object(20TYPE VALUE ''"'ZTOAD_AUTH',
         actvt_select TYPE tactt-actvt VALUE '03',
         actvt_insert TYPE tactt-actvt VALUE '01',
         actvt_update TYPE tactt-actvt VALUE '02',
         actvt_delete TYPE tactt-actvt VALUE '06',
         actvt_native TYPE tactt-actvt VALUE '16',

* Bellow is default AUTH used if no auth_object is defined
* Allow SELECT query on SAP table (restricted by given pattern)
         auth_select TYPE string VALUE '*',
* Allow INSERT query on SAP table (restricted by given pattern)
         auth_insert TYPE string VALUE '*',
* Allow UPDATE query on SAP table (restricted by given pattern)
         auth_update TYPE string VALUE '*',
* Allow DELETE query on SAP table (restricted by given pattern)
         auth_delete TYPE string VALUE '*',
* Allow any native sql command (set value to space to disable)
         auth_native(1TYPE VALUE abap_true,

       END OF s_customize.


*######################################################################*
*
*                             DATA SECTION
*
*######################################################################*
* Objects
CLASS lcl_application DEFINITION DEFERRED.

* Screen objects
DATA o_handle_event TYPE REF TO lcl_application,
       o_container TYPE REF TO cl_gui_custom_container,
       o_splitter TYPE REF TO cl_gui_splitter_container,
       o_splitter_top TYPE REF TO cl_gui_splitter_container,
       o_splitter_top_right TYPE REF TO cl_rsawb_splitter_for_toolbar,
       o_container_top TYPE REF TO cl_gui_container,
       o_container_top_right TYPE REF TO cl_gui_container,
       o_container_repository TYPE REF TO cl_gui_container,
       o_container_query TYPE REF TO cl_gui_container,
       o_container_ddic TYPE REF TO cl_gui_container,
       o_container_result TYPE REF TO cl_gui_container,
       o_container_options TYPE REF TO cl_gui_custom_container,

* Editor data
       o_textedit TYPE REF TO cl_gui_abapedit,

* Repository data
       o_tree_repository TYPE REF TO cl_gui_simple_tree,
       BEGIN OF s_node_repository.
        INCLUDE TYPE treev_node"mtreesnode.
DATA :  text(100TYPE c,
        edit(1TYPE c,
         queryid TYPE ztoad-queryid,
       END OF s_node_repository,
       t_node_repository LIKE TABLE OF s_node_repository,

* DDIC data
       o_tree_ddic TYPE REF TO cl_gui_column_tree,
       t_node_ddic TYPE treev_ntab,
       t_item_ddic TYPE TABLE OF mtreeitm,
       o_alv_result TYPE REF TO cl_gui_alv_grid,
       w_dragdrop_handle_tree TYPE i,
* DDIC toolbar
       o_toolbar TYPE REF TO cl_gui_toolbar,
* Option panel
       o_options TYPE REF TO cl_wdy_wb_property_box,
* ZSPRO data
       t_node_zspro LIKE t_node_ddic,
       t_item_zspro LIKE t_item_ddic,

* Save option
       BEGIN OF s_options,
         name TYPE ztoad-text,
         visibility TYPE ztoad-visibility,
         visibilitygrp TYPE usr02-class,
       END OF s_options,

* Keep last loaded id
       w_last_loaded_query TYPE ztoad-queryid,

* Count number of runs
       w_run TYPE i.

DATA w_okcode LIKE sy-ucomm.

* Global types
TYPES BEGIN OF ty_fieldlist,
          field TYPE string,
          ref_table TYPE string,
          ref_field TYPE string,
        END OF ty_fieldlist,
        ty_fieldlist_table TYPE STANDARD TABLE OF ty_fieldlist.

* Constants
CONSTANTS c_ddic_col1 TYPE mtreeitm-item_name
                        VALUE 'col1',                       "#EC NOTEXT
            c_ddic_col2 TYPE mtreeitm-item_name
                        VALUE 'col2',                       "#EC NOTEXT
            c_ddic_header TYPE tv_hdrname
                          VALUE 'HierarchyHeader',          "#EC NOTEXT
            c_visibility_all TYPE ztoad-visibility VALUE '2',
            c_visibility_shared TYPE ztoad-visibility VALUE '1',
            c_visibility_my TYPE ztoad-visibility VALUE '0',
            c_nodekey_repo_my TYPE mtreesnode-node_key VALUE 'MY',
            c_nodekey_repo_shared TYPE mtreesnode-node_key
                                  VALUE 'SHARED',
            c_nodekey_repo_history TYPE mtreesnode-node_key
                                   VALUE 'HISTO',
            c_line_max TYPE VALUE 255,
            c_msg_success TYPE VALUE 'S',
            c_msg_error TYPE VALUE 'E',
            c_vers_active TYPE as4local VALUE 'A',
            c_ddic_dtelm TYPE comptype VALUE 'E',
            c_native_command TYPE string VALUE 'NATIVE',
            c_query_max_exec TYPE VALUE 36.

*######################################################################*
*
*                             CLASS SECTION
*
*######################################################################*

*----------------------------------------------------------------------*
*       CLASS lcl_drag_object DEFINITION
*----------------------------------------------------------------------*
*       Class to store object on drag & drop from DDIC to sql editor
*----------------------------------------------------------------------*
CLASS lcl_drag_object DEFINITION FINAL.
  PUBLIC SECTION.
    DATA field TYPE string.
ENDCLASS."lcl_drag_object DEFINITION

*----------------------------------------------------------------------*
*       CLASS lcl_application DEFINITION
*----------------------------------------------------------------------*
*       Class to handle application events
*----------------------------------------------------------------------*
CLASS lcl_application DEFINITION FINAL.
  PUBLIC SECTION.
    METHODS :
* Handle F1 call on ABAP editor
               hnd_editor_f1
                   FOR EVENT f1 OF cl_gui_abapedit,
* Handle Node double clic on ddic tree
               hnd_ddic_item_dblclick
                   FOR EVENT item_double_click OF cl_gui_column_tree
                   IMPORTING node_key,
* Handle context menu display on repository tree
              hnd_repo_context_menu
                   FOR EVENT node_context_menu_request
                   OF cl_gui_simple_tree
                     IMPORTING menu,
* Handle context menu clic on repository tree
               hnd_repo_context_menu_sel
                   FOR EVENT node_context_menu_select
                   OF cl_gui_simple_tree
                       IMPORTING fcode,
* Handle Node double clic on repository tree
               hnd_repo_dblclick
                   FOR EVENT node_double_click OF cl_gui_simple_tree
                   IMPORTING node_key,
* Handle toolbar display on ALV result
               hnd_result_toolbar
                   FOR EVENT toolbar OF cl_gui_alv_grid
                   IMPORTING e_object,
* Handle toolbar clic on ALV result
               hnd_result_user_command
                   FOR EVENT user_command OF cl_gui_alv_grid
                   IMPORTING e_ucomm,
* Handle DDIC tree drag
               hnd_ddic_drag
                   FOR EVENT on_drag OF cl_gui_column_tree
                   IMPORTING node_key drag_drop_object,
* Handle editor drop
               hnd_editor_drop
                   FOR EVENT on_drop OF cl_gui_abapedit
                   IMPORTING line pos dragdrop_object,
* Handle ddic toolbar clic
               hnd_ddic_toolbar_clic
                   FOR EVENT function_selected OF cl_gui_toolbar
                   IMPORTING fcode.
ENDCLASS.                    "lcl_application DEFINITION

*----------------------------------------------------------------------*
*       CLASS LCL_APPLICATION IMPLEMENTATION
*----------------------------------------------------------------------*
*       Class to handle application events                             *
*----------------------------------------------------------------------*
CLASS lcl_application IMPLEMENTATION.
*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_repo_context_menu
*&---------------------------------------------------------------------*
*       Handle context menu display on repository tree
*----------------------------------------------------------------------*
  METHOD hnd_repo_context_menu.
    DATA l_node_key TYPE tv_nodekey.

    CALL METHOD o_tree_repository->get_selected_node
      IMPORTING
        node_key l_node_key.
* For History node, add a "delete all" entry
* Only if there is at least 1 history entry
    IF l_node_key 'HISTO'.
      READ TABLE t_node_repository TRANSPORTING NO FIELDS
        WITH KEY relatkey 'HISTO'.
      IF sy-subrc 0.
        CALL METHOD menu->add_function
          EXPORTING
            text  'Delete All'(m36)
            icon  '@02@'
            fcode 'DELETE_HIST'.
      ENDIF.
      RETURN.
    ENDIF.

* Add Delete option only for own queries
    READ TABLE t_node_repository INTO s_node_repository
               WITH KEY node_key l_node_key.
    IF sy-subrc NE OR s_node_repository-edit space.
      RETURN.
    ENDIF.

    CALL METHOD menu->add_function
      EXPORTING
        text  'Delete'(m01)
        icon  '@02@'
        fcode 'DELETE_QUERY'.
  ENDMETHOD.                    "hnd_repo_context_menu

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_repo_context_menu_sel
*&---------------------------------------------------------------------*
*       Handle context menu clic on repository tree
*----------------------------------------------------------------------*
  METHOD hnd_repo_context_menu_sel.
    DATA l_node_key TYPE tv_nodekey,
           l_subrc TYPE i,
           ls_histo LIKE s_node_repository,
           lw_queryid LIKE ls_histo-queryid.
* Delete stored query
    CASE fcode.
      WHEN 'DELETE_QUERY'.
        CALL METHOD o_tree_repository->get_selected_node
          IMPORTING
            node_key l_node_key.
        PERFORM repo_delete_history USING l_node_key
                                    CHANGING l_subrc.
        IF l_subrc 0.
          MESSAGE 'Query deleted'(m02TYPE c_msg_success.
        ELSE.
          MESSAGE 'Error when deleting the query'(m03)
                  TYPE c_msg_success DISPLAY LIKE c_msg_error.
          RETURN.
        ENDIF.

      WHEN 'DELETE_HIST'.
        CONCATENATE sy-uname '+++' INTO lw_queryid.
        LOOP AT t_node_repository INTO ls_histo
                WHERE queryid CP lw_queryid.
          PERFORM repo_delete_history USING ls_histo-node_key
                                      CHANGING l_subrc.
          IF l_subrc NE 0.
            MESSAGE 'Error when deleting the query'(m03)
                    TYPE c_msg_success DISPLAY LIKE c_msg_error.
            RETURN.
          ENDIF.
        ENDLOOP.
        MESSAGE 'All history entries deleted'(m37TYPE c_msg_success.
    ENDCASE.
  ENDMETHOD.                    "hnd_repo_context_menu_sel

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_editor_f1
*&---------------------------------------------------------------------*
*       Handle F1 call on ABAP editor
*----------------------------------------------------------------------*
  METHOD hnd_editor_f1.
    DATA lw_cursor_line_from TYPE i,
           lw_cursor_line_to TYPE i,
           lw_cursor_pos_from TYPE i,
           lw_cursor_pos_to TYPE i,
           lw_offset TYPE i,
           lw_length TYPE i,
           lt_query TYPE soli_tab,
           ls_query LIKE LINE OF lt_query,
           lw_sel TYPE string.

* Find active query
    CALL METHOD o_textedit->get_selection_pos
      IMPORTING
        from_line lw_cursor_line_from
        from_pos  lw_cursor_pos_from
        to_line   lw_cursor_line_to
        to_pos    lw_cursor_pos_to.

* If nothing selected, no help to display
    IF lw_cursor_line_from lw_cursor_line_to
    AND lw_cursor_pos_to lw_cursor_pos_from.
      RETURN.
    ENDIF.

* Get content of abap edit box
    CALL METHOD o_textedit->get_text
      IMPORTING
        table  lt_query[]
      EXCEPTIONS
        OTHERS 1.


    READ TABLE lt_query INTO ls_query INDEX lw_cursor_line_from.
    IF lw_cursor_line_from lw_cursor_line_to.
      lw_length lw_cursor_pos_to lw_cursor_pos_from.
      lw_offset lw_cursor_pos_from 1.
      lw_sel ls_query+lw_offset(lw_length).
    ELSE.
      lw_offset lw_cursor_pos_from 1.
      lw_sel ls_query+lw_offset.
    ENDIF.
    CALL FUNCTION 'ABAP_DOCU_START'
      EXPORTING
        word lw_sel.
  ENDMETHOD.                    "hnd_editor_f1

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_ddic_item_dblclick
*&---------------------------------------------------------------------*
*       Handle Node double clic on ddic tree
*----------------------------------------------------------------------*
  METHOD hnd_ddic_item_dblclick.
    DATA ls_node LIKE LINE OF t_node_ddic,
           lw_line_start TYPE i,
           lw_pos_start TYPE i,
           lw_line_end TYPE i,
           lw_pos_end TYPE i,
           lw_data TYPE string.

* Check clicked node is valid
    READ TABLE t_node_ddic INTO ls_node
               WITH KEY node_key node_key.
    IF sy-subrc NE OR ls_node-isfolder abap_true.
      RETURN.
    ENDIF.

* Get text for the node selected
    PERFORM ddic_get_field_from_node USING node_key ls_node-relatkey
                                     CHANGING lw_data.

* Get current cursor position/selection in editor
    CALL METHOD o_textedit->get_selection_pos
      IMPORTING
        from_line lw_line_start
        from_pos  lw_pos_start
        to_line   lw_line_end
        to_pos    lw_pos_end
      EXCEPTIONS
        OTHERS    4.
    IF sy-subrc NE 0.
      MESSAGE 'Cannot get cursor position'(m35TYPE c_msg_error.
    ENDIF.

*   If text is selected/highlighted, delete it
    IF lw_line_start NE lw_line_end
    OR lw_pos_start NE lw_pos_end.
      CALL METHOD o_textedit->delete_text
        EXPORTING
          from_line lw_line_start
          from_pos  lw_pos_start
          to_line   lw_line_end
          to_pos    lw_pos_end.
    ENDIF.

    PERFORM editor_paste USING lw_data lw_line_start lw_pos_start.
  ENDMETHOD.                    "hnd_ddic_item_dblclick

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_repo_dblclick
*&---------------------------------------------------------------------*
*       Handle Node double clic on repository tree
*----------------------------------------------------------------------*
  METHOD hnd_repo_dblclick.
    DATA lt_query TYPE TABLE OF string.
    READ TABLE t_node_repository INTO s_node_repository
               WITH KEY node_key node_key.
    IF sy-subrc AND NOT s_node_repository-relatkey IS INITIAL.
      PERFORM query_load USING s_node_repository-queryid
                         CHANGING lt_query.

      CALL METHOD o_textedit->set_text
        EXPORTING
          table  lt_query
        EXCEPTIONS
          OTHERS 0.

      PERFORM ddic_refresh_tree.
    ENDIF.
  ENDMETHOD"hnd_repo_dblclick

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_result_toolbar
*&---------------------------------------------------------------------*
*       Handle grid toolbar to add specific button
*----------------------------------------------------------------------*
  METHOD hnd_result_toolbar.
    DATAls_toolbar  TYPE stb_button.

* Add Separator
    CLEAR ls_toolbar.
    ls_toolbar-function '&&SEP99'.
    ls_toolbar-butn_type 3.
    APPEND ls_toolbar TO e_object->mt_toolbar.

* Add button to close the grid
    CLEAR ls_toolbar.
    ls_toolbar-function 'CLOSE_GRID'.
    ls_toolbar-icon '@3X@'.
    ls_toolbar-quickinfo 'Close Grid'(m05).
    ls_toolbar-text 'Close'(m06).
    ls_toolbar-butn_type 0.
    ls_toolbar-disabled space.
    APPEND ls_toolbar TO e_object->mt_toolbar.
  ENDMETHOD.                    "hnd_result_toolbar

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_result_user_command
*&---------------------------------------------------------------------*
*       Handle grid user command to manage specific fcode
*       (menus & toolbar)
*----------------------------------------------------------------------*
  METHOD hnd_result_user_command.
    IF e_ucomm 'CLOSE_GRID'.
      CALL METHOD o_splitter->set_row_height
        EXPORTING
          id     1
          height 100.
    ENDIF.
  ENDMETHOD"hnd_result_user_command

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_ddic_drag
*&---------------------------------------------------------------------*
*       Handle drag on DDIC field (store fieldname)
*----------------------------------------------------------------------*
  METHOD hnd_ddic_drag.
    DATA lo_drag_object TYPE REF TO lcl_drag_object,
           ls_node LIKE LINE OF t_node_ddic,
           lw_text TYPE string.

    READ TABLE t_node_ddic INTO ls_node
               WITH KEY node_key node_key.
    IF sy-subrc NE OR ls_node-isfolder abap_true"may not append
      MESSAGE 'Only fields can be drag&drop to editor'(m34)
               TYPE c_msg_success DISPLAY LIKE c_msg_error.
      RETURN.
    ENDIF.

* Get text for the node selected
    PERFORM ddic_get_field_from_node USING node_key ls_node-relatkey
                                     CHANGING lw_text.

* Store the node text
    CREATE OBJECT lo_drag_object.
    lo_drag_object->field lw_text.
    drag_drop_object->object lo_drag_object.

  ENDMETHOD."hnd_ddic_drag

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_editor_drop
*&---------------------------------------------------------------------*
*       Handle drop on SQL Editor : paste fieldname at cursor position
*----------------------------------------------------------------------*
  METHOD hnd_editor_drop.
    DATA lo_drag_object TYPE REF TO lcl_drag_object.

    lo_drag_object ?= dragdrop_object->object.
    IF lo_drag_object IS INITIAL OR lo_drag_object->field IS INITIAL.
      RETURN.
    ENDIF.

* Paste fieldname to editor at drop position
    PERFORM editor_paste USING lo_drag_object->field line pos.

  ENDMETHOD."hnd_editor_drop

*&---------------------------------------------------------------------*
*&      CLASS lcl_application
*&      METHOD hnd_ddic_toolbar_clic
*&---------------------------------------------------------------------*
*       Handle DDIC toolbar button clic
*----------------------------------------------------------------------*
  METHOD hnd_ddic_toolbar_clic.

    CASE fcode.
      WHEN 'REFRESH'.
        PERFORM ddic_refresh_tree.
      WHEN 'FIND'.
        PERFORM ddic_find_in_tree.
      WHEN 'F4'.
        PERFORM ddic_f4.
    ENDCASE.
  ENDMETHOD.                    "hnd_ddic_toolbar_clic

ENDCLASS.                    "lcl_application IMPLEMENTATION


*######################################################################*
*
*                             MAIN SECTION
*
*######################################################################*
START-OF-SELECTION.
  CALL SCREEN 100.


*######################################################################*
*
*                             PBO SECTION
*
*######################################################################*
*&---------------------------------------------------------------------*
*&      Module  STATUS_0100  OUTPUT
*&---------------------------------------------------------------------*
*       Set status for main screen
*       and initialize custom container at first run
*----------------------------------------------------------------------*
MODULE status_0100 OUTPUT.
* Initialization of object screen
  IF o_container IS INITIAL.
    PERFORM screen_init.
  ENDIF.

  AUTHORITY-CHECK OBJECT 'S_DEVELOP' ID 'ACTVT' FIELD '03'
                                     ID 'DEVCLASS' DUMMY
                                     ID 'OBJTYPE' DUMMY
                                     ID 'OBJNAME' DUMMY
                                     ID 'P_GROUP' DUMMY.
  IF sy-subrc 0.
    SET PF-STATUS 'STATUS100'.
  ELSE.
* If you dont have S_DEVELOP access in display, you probably dont
* understand the code generated => do not display the button
    SET PF-STATUS 'STATUS100' EXCLUDING 'SHOWCODE'.
  ENDIF.
  SET TITLEBAR 'STATUS100'.

ENDMODULE.                 " STATUS_0100  OUTPUT

*&---------------------------------------------------------------------*
*&      Module  STATUS_0200  OUTPUT
*&---------------------------------------------------------------------*
*       Set status for modal box (save query)
*----------------------------------------------------------------------*
MODULE status_0200 OUTPUT.

* Fill dropdown listbox with values
  PERFORM screen_init_listbox_0200.

  SET PF-STATUS 'STATUS200'.
  SET TITLEBAR 'STATUS200'.

ENDMODULE.                 " STATUS_0200  OUTPUT

*&---------------------------------------------------------------------*
*&      Module  STATUS_0300  OUTPUT
*&---------------------------------------------------------------------*
*       Set status for modal box (options)
*----------------------------------------------------------------------*
MODULE status_0300 OUTPUT.

* Create option screen
  IF o_container_options IS INITIAL.
    PERFORM options_init.
  ENDIF.

  SET PF-STATUS 'STATUS300'.
  SET TITLEBAR 'STATUS300'.

ENDMODULE.                 " STATUS_0200  OUTPUT

*######################################################################*
*
*                             PAI SECTION
*
*######################################################################*

*&---------------------------------------------------------------------*
*&      Module  USER_COMMAND_0200  INPUT
*&---------------------------------------------------------------------*
*       PAI module for modal box (save query)
*----------------------------------------------------------------------*
MODULE user_command_0200 INPUT.
  CASE w_okcode.
    WHEN 'CLOSE'.
      CLEAR s_options.
      LEAVE TO SCREEN 0.
    WHEN 'OK'.
      LEAVE TO SCREEN 0.
  ENDCASE.
ENDMODULE.                 " USER_COMMAND_0200  INPUT

*&---------------------------------------------------------------------*
*&      Module  USER_COMMAND_0300  INPUT
*&---------------------------------------------------------------------*
*       PAI module for modal box (options)
*----------------------------------------------------------------------*
MODULE user_command_0300 INPUT.
  CASE w_okcode.
    WHEN 'CLOSE' OR 'OK'.
      LEAVE TO SCREEN 0.
  ENDCASE.
ENDMODULE.                 " USER_COMMAND_0200  INPUT

*&---------------------------------------------------------------------*
*&      Module  USER_COMMAND_0100  INPUT
*&---------------------------------------------------------------------*
*       User command for main screen
*----------------------------------------------------------------------*
MODULE user_command_0100 INPUT.

  CASE w_okcode.
    WHEN 'EXIT'.
      PERFORM screen_exit.
    WHEN 'EXECUTE'.
      PERFORM query_process USING space space.
    WHEN 'DOWNLOAD'.
      PERFORM query_process USING space abap_true.
    WHEN 'SAVE'.
      PERFORM repo_save_query.
    WHEN 'SHOWCODE'.
      PERFORM query_process USING abap_true space.
    WHEN 'HELP'.
      PERFORM screen_display_help.
    WHEN 'OPTIONS'.
      PERFORM options_display.
    WHEN 'NEW'.
      PERFORM editor_new_query.
  ENDCASE.
ENDMODULE.                 " USER_COMMAND_0100  INPUT

*######################################################################*
*
*                             FORM SECTION
*
*######################################################################*

*&---------------------------------------------------------------------*
*&      Form  SCREEN_INIT
*&---------------------------------------------------------------------*
*       Initialize all objects on the screen
*----------------------------------------------------------------------*
FORM screen_init.
* Get user default values
  PERFORM options_load.

* Create the handle object (required to catch events)
  CREATE OBJECT o_handle_event.

* Split the screen into 4 parts
  PERFORM screen_init_splitter.

* Init History Tree
  PERFORM repo_init.

* Init DDIC toolbar
  PERFORM ddic_toolbar_init.

* Init DDic tree
  PERFORM ddic_init.

* Init Query editor
  PERFORM editor_init.

* Init ALV result object
  PERFORM result_init.

ENDFORM.                    " SCREEN_INIT

*&---------------------------------------------------------------------*
*&      Form  SCREEN_INIT_SPLITTER
*&---------------------------------------------------------------------*
*       Split the main screen in 2 lines
* 1 line with 3 columns : Repository tree / Query code / Ddic tree
* 1 line with ALV result
*----------------------------------------------------------------------*
FORM screen_init_splitter.
  DATA lw_res TYPE i.

* Create the custom container
  CREATE OBJECT o_container
    EXPORTING
      container_name 'CUSTCONT'.

* Insert splitter into this container
  CREATE OBJECT o_splitter
    EXPORTING
      parent  o_container
      rows    2
      columns 1.

* Get the first row of the main splitter
  CALL METHOD o_splitter->get_container
    EXPORTING
      row       1
      column    1
    RECEIVING
      container o_container_top.

*  Spliter for the high part (first row)
  CREATE OBJECT o_splitter_top
    EXPORTING
      parent  o_container_top
      rows    1
      columns 3.

* Get the right part of the top part
  CALL METHOD o_splitter_top->get_container
    EXPORTING
      row       1
      column    3
    RECEIVING      "container = o_container_ddic.
      container o_container_top_right.

* Add a toolbar to the DDIC container
  CREATE OBJECT o_splitter_top_right
    EXPORTING
      i_r_container o_container_top_right.

* Affect an object to each "cell" of the high sub splitter
  CALL METHOD o_splitter_top->get_container
    EXPORTING
      row       1
      column    1
    RECEIVING
      container o_container_repository.

  CALL METHOD o_splitter_top->get_container
    EXPORTING
      row       1
      column    2
    RECEIVING
      container o_container_query.

  CALL METHOD o_splitter_top_right->get_controlcontainer
    RECEIVING
      e_r_container_control o_container_ddic.

  CALL METHOD o_splitter->get_container
    EXPORTING
      row       2
      column    1
    RECEIVING
      container o_container_result.

* Initial repartition :
*   line 1 = 100% (code+repo+ddic)
*   line 2 = 0% (result)
*   line 1 col 1 & 3 = 20% (repo & ddic)
*   line 1 col 2 = 60% (code)
  CALL METHOD o_splitter->set_row_height
    EXPORTING
      id     1
      height 100.

  CALL METHOD o_splitter_top->set_column_width
    EXPORTING
      id    1
      width 20.
  CALL METHOD o_splitter_top->set_column_width
    EXPORTING
      id    3
      width 20.

ENDFORM.                    " SCREEN_INIT_SPLITTER

*&---------------------------------------------------------------------*
*&      Form  ddic_toolbar_init
*&---------------------------------------------------------------------*
*       Initialize DDIC Toolbar
*
*----------------------------------------------------------------------*
FORM ddic_toolbar_init.
  DATAlt_button TYPE ttb_button,
        ls_button LIKE LINE OF lt_button,
        lt_events TYPE cntl_simple_events,
        ls_events LIKE LINE OF lt_events.

*  Toolbar already created by class CL_RSAWB_SPLITTER_FOR_TOOLBAR
  o_toolbar o_splitter_top_right->get_toolbar).

* Add buttons to toolbar
  CLEAR ls_button.
  ls_button-function 'REFRESH'.
  ls_button-icon '@42@'.
  ls_button-quickinfo 'Refresh DDIC tree'(m41).
  ls_button-text 'Refresh'(m40).
  ls_button-butn_type 0.
  APPEND ls_button TO lt_button.

  CLEAR ls_button.
  ls_button-function 'FIND'.
  ls_button-icon '@13@'.
  ls_button-quickinfo 'Search in DDIC tree'(m43).
  ls_button-text 'Find'(m42).
  ls_button-butn_type 0.
  APPEND ls_button TO lt_button.

  CLEAR ls_button.
  ls_button-function 'F4'.
  ls_button-icon '@6T@'.
  ls_button-quickinfo 'Display values of sel. field'(m54).
  ls_button-text 'Value list'(m55).
  ls_button-butn_type 0.
  APPEND ls_button TO lt_button.

  CALL METHOD o_toolbar->add_button_group
    EXPORTING
      data_table lt_button.

* Register events
  ls_events-eventid cl_gui_toolbar=>m_id_function_selected.
  ls_events-appl_event space.
  APPEND ls_events TO lt_events.
  CALL METHOD o_toolbar->set_registered_events
    EXPORTING
      events lt_events.

  SET HANDLER o_handle_event->hnd_ddic_toolbar_clic FOR o_toolbar.

ENDFORM.                    "ddic_toolbar_init

*&---------------------------------------------------------------------*
*&      Form  EDITOR_INIT
*&---------------------------------------------------------------------*
*       Initialize the sql editor object
*       Fill it with last query, or template if no previous query
*----------------------------------------------------------------------*
FORM editor_init.
  DATA lt_events TYPE cntl_simple_events,
         ls_event TYPE cntl_simple_event,
         lt_default TYPE TABLE OF string,
         lw_queryid TYPE ztoad-queryid,
         lo_dragrop TYPE REF TO cl_dragdrop,
         lw_dummy_date TYPE timestamp.                      "#EC NEEDED

* Get last query used
  CONCATENATE sy-uname '#%' INTO lw_queryid.
* aedat is not used but added in select for compatibility reason
  SELECT queryid aedat
         INTO (lw_queryidlw_dummy_date)
         FROM ztoad
         UP TO ROWS
         WHERE queryid LIKE lw_queryid
         AND owner sy-uname
         ORDER BY aedat DESCENDING.
  ENDSELECT.
  IF sy-subrc 0.
    PERFORM query_load USING lw_queryid
                       CHANGING lt_default.
    PERFORM repo_focus_query USING lw_queryid.
  ENDIF.

* If no last query found, use default template
  IF lt_default IS INITIAL.
    PERFORM editor_get_default_query CHANGING lt_default.
  ENDIF.

* Create the sql editor
  CREATE OBJECT o_textedit
    EXPORTING
      parent o_container_query.

* Register events
  SET HANDLER o_handle_event->hnd_editor_f1 FOR o_textedit.
  SET HANDLER o_handle_event->hnd_editor_drop FOR o_textedit.

  ls_event-eventid cl_gui_textedit=>event_f1.
  APPEND ls_event TO lt_events.

  CALL METHOD o_textedit->set_registered_events
    EXPORTING
      events                    lt_events
    EXCEPTIONS
      cntl_error                1
      cntl_system_error         2
      illegal_event_combination 3.
  IF sy-subrc <> 0.
    IF sy-msgno IS NOT INITIAL.
      MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
              DISPLAY LIKE c_msg_error
              WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4 .
    ENDIF.
  ENDIF.

* Activate Code Completion and Quickinfo
* Comment the paragraph if CL_ABAP_PARSER doesnt exists on your system
* BEGIN OF ABAP PARSER
  DATA lo_completer TYPE REF TO cl_abap_parser.
  CALL METHOD o_textedit->('INIT_COMPLETER').
  CALL METHOD o_textedit->('GET_COMPLETER')
    RECEIVING
      m_parser lo_completer.
  SET HANDLER lo_completer->handle_completion_request FOR o_textedit.
  SET HANDLER lo_completer->handle_insertion_request FOR o_textedit.
  SET HANDLER lo_completer->handle_quickinfo_request FOR o_textedit.
  o_textedit->register_event_completion).
  o_textedit->register_event_quick_info).
  o_textedit->register_event_insert_pattern).
* END OF ABAP PARSER

* Manage Drop on SQL editor
  CREATE OBJECT lo_dragrop.
  CALL METHOD lo_dragrop->add
    EXPORTING
      flavor     'EDIT_INSERT'
      dragsrc    space
      droptarget abap_true
      effect     cl_dragdrop=>copy.
  CALL METHOD o_textedit->set_dragdrop
    EXPORTING
      dragdrop lo_dragrop.

* Set Default template
  CALL METHOD o_textedit->set_text
    EXPORTING
      table  lt_default
    EXCEPTIONS
      OTHERS 0.

* Set focus
  CALL METHOD cl_gui_control=>set_focus
    EXPORTING
      control o_textedit
    EXCEPTIONS
      OTHERS  0.

  PERFORM ddic_refresh_tree.
ENDFORM.                    " EDITOR_INIT

*&---------------------------------------------------------------------*
*&      Form  query_process
*&---------------------------------------------------------------------*
*       Process selected query : execute or display code
*----------------------------------------------------------------------*
*      -->FW_DISPLAY : Flag abap_true to display code
*      -->FW_DOWNLOAD: Flag abap_true to save results into file
*----------------------------------------------------------------------*
FORM query_process USING fw_display TYPE c
                         fw_download TYPE c.
  DATA lw_query TYPE string,
         lw_select TYPE string,
         lw_from TYPE string,
         lw_where TYPE string,
         lw_union TYPE string,
         lw_query2 TYPE string,
         lw_command TYPE string,
         lw_rows(6TYPE n,
         lw_program TYPE sy-repid,
         lo_result TYPE REF TO data,
         lo_result2 TYPE REF TO data,
         lt_fieldlist TYPE ty_fieldlist_table,
         lt_fieldlist2 TYPE ty_fieldlist_table,
         lw_count_only(1TYPE c,
         lw_time TYPE p LENGTH DECIMALS 2,
         lw_time2 LIKE lw_time,
         lw_count TYPE i,
         lw_count2 LIKE lw_count,
         lw_charnumb(12TYPE c,
         lw_msg TYPE string,
         lw_noauth(1TYPE c,
         lw_newsyntax(1TYPE c,
         lw_answer(1TYPE c,
         lw_from_concat LIKE lw_from,
         lw_error(1TYPE c.

  FIELD-SYMBOLS <lft_data> TYPE STANDARD TABLE,
                  <lft_data2> TYPE STANDARD TABLE.

* Get only usefull code for current query
  PERFORM editor_get_query USING space CHANGING lw_query.

* Parse SELECT Query
  PERFORM query_parse USING lw_query
                      CHANGING lw_select lw_from lw_where
                               lw_union lw_rows lw_noauth
                               lw_newsyntax lw_error.
  IF lw_error NE space.
    MESSAGE 'Cannot parse the query'(m07TYPE c_msg_error.
  ENDIF.

* Not a select query
  IF lw_select IS INITIAL.
    PERFORM query_parse_noselect USING    lw_query
                                 CHANGING lw_noauth
                                          lw_command
                                          lw_from
                                          lw_where.
    IF lw_noauth NE space.
      PERFORM ddic_set_tree USING lw_from.
      RETURN.
    ENDIF.

* For native sql command, execute it directly
    IF lw_command c_native_command.
      PERFORM ddic_set_tree USING lw_from.
      PERFORM query_process_native USING lw_where.
      RETURN.
    ENDIF.

* For other no select command, generate program
    IF w_run LT c_query_max_exec.
      PERFORM query_generate_noselect USING lw_command lw_from
                                            lw_where fw_display
                                      CHANGING lw_program.
      w_run w_run + 1.
    ELSE.
      MESSAGE 'No more run available. Please restart program'(m50)
              TYPE c_msg_error.
    ENDIF.
    IF fw_display IS INITIAL.
      PERFORM ddic_set_tree USING lw_from.
      CONCATENATE 'Are you sure you want to do a'(m31lw_command
                  'on table'(m32lw_from '?'(m33)
                  INTO lw_msg SEPARATED BY space.
      CALL FUNCTION 'POPUP_TO_CONFIRM'
        EXPORTING
          titlebar              'Warning : critical operation'(t04)
          text_question         lw_msg
          default_button        '2'
          display_cancel_button space
        IMPORTING
          answer                lw_answer
        EXCEPTIONS
          text_not_found        1
          OTHERS                2.
      IF sy-subrc NE OR lw_answer NE '1'.
        RETURN.
      ENDIF.
    ENDIF.
    lw_count_only abap_true"no result grid to display
  ELSEIF lw_noauth NE space.
    PERFORM ddic_set_tree USING lw_from.
    RETURN.
  ELSEIF lw_from IS INITIAL.
    PERFORM ddic_set_tree USING lw_from.
    MESSAGE 'Cannot parse the query'(m07TYPE c_msg_error.
  ELSE.
* Generate SELECT subroutine
    IF w_run LT c_query_max_exec.
      PERFORM query_generate USING lw_select lw_from
                                   lw_where fw_display
                                   lw_newsyntax
                             CHANGING lw_program lw_rows
                                      lt_fieldlist lw_count_only.
      IF lw_program IS INITIAL.
        PERFORM ddic_set_tree USING lw_from.
        RETURN.
      ENDIF.
      w_run w_run + 1.
    ELSE.
      MESSAGE 'No more run available. Please restart program'(m50)
              TYPE c_msg_error.
    ENDIF.
  ENDIF.


* Call the generated subroutine
  IF NOT lw_program IS INITIAL.
    PERFORM run_sql IN PROGRAM (lw_program)
                    CHANGING lo_result lw_time lw_count.
    lw_from_concat lw_from.
* For union, process second (and further) query
    WHILE NOT lw_union IS INITIAL.
* Parse Query
      lw_query2 lw_union.
      PERFORM query_parse USING lw_query2
                          CHANGING lw_select lw_from lw_where
                                   lw_union lw_rows lw_noauth
                                   lw_newsyntax lw_error.
      CONCATENATE lw_from_concat 'JOIN' lw_from INTO lw_from_concat.
      IF lw_noauth NE space.
        PERFORM ddic_set_tree USING lw_from_concat.
        RETURN.
      ELSEIF lw_select IS INITIAL OR lw_from IS INITIAL
      OR lw_error abap_true.
        PERFORM ddic_set_tree USING lw_from_concat.
        MESSAGE 'Cannot parse the unioned query'(m08TYPE c_msg_error.
        EXIT"exit while
      ENDIF.
* Generate subroutine
      IF w_run LT c_query_max_exec.
        PERFORM query_generate USING lw_select lw_from
                                     lw_where fw_display
                                     lw_newsyntax
                               CHANGING lw_program lw_rows
                                        lt_fieldlist2 lw_count_only.
        IF lw_program IS INITIAL.
          PERFORM ddic_set_tree USING lw_from_concat.
          RETURN.
        ENDIF.
        w_run w_run + 1.
      ELSE.
        MESSAGE 'No more run available. Please restart program'(m50)
                TYPE c_msg_error.
      ENDIF.
* Call the generated subroutine
      PERFORM run_sql IN PROGRAM (lw_program)
                      CHANGING lo_result2 lw_time2 lw_count2.

* Append lines of the further queries to the first query
      ASSIGN lo_result->TO <lft_data>.
      ASSIGN lo_result2->TO <lft_data2>.
      APPEND LINES OF <lft_data2> TO <lft_data>.
      REFRESH <lft_data2>.
      lw_time lw_time + lw_time2.
      lw_count lw_count + lw_count2.
    ENDWHILE.

    PERFORM ddic_set_tree USING lw_from_concat.

* Display message
    lw_charnumb lw_time.
    CONCATENATE 'Query executed in'(m09lw_charnumb INTO lw_msg
                SEPARATED BY space.
    lw_charnumb lw_count.
    IF NOT lw_select IS INITIAL.
      CONCATENATE lw_msg 'seconds.'(m10)
                  lw_charnumb 'entries found'(m11)
                  INTO lw_msg SEPARATED BY space.
    ELSE.
      CONCATENATE lw_msg 'seconds.'(m10)
                  lw_charnumb 'entries affected'(m12)
                  INTO lw_msg SEPARATED BY space.
    ENDIF.
    CONDENSE lw_msg.
    MESSAGE lw_msg TYPE c_msg_success.


* Display result except for count(*)
    IF lw_count_only IS INITIAL.
      IF fw_download space.
        PERFORM result_display USING lo_result lt_fieldlist lw_query.
      ELSE.
        PERFORM result_save_file USING lo_result lt_fieldlist.
      ENDIF.
    ENDIF.

    PERFORM repo_save_current_query.
  ENDIF.
ENDFORM.                    " QUERY_PROCESS

*&---------------------------------------------------------------------*
*&      Form  EDITOR_GET_QUERY
*&---------------------------------------------------------------------*
*       Return active query without comment
*----------------------------------------------------------------------*
*      -->FW_FORCE_LAST  Keep last request
*      <--FW_QUERY       Query code
*----------------------------------------------------------------------*
FORM editor_get_query USING fw_force_last TYPE c
                      CHANGING fw_query TYPE string.
  DATA lt_query TYPE soli_tab,
         ls_query LIKE LINE OF lt_query,
         ls_find TYPE match_result,
         lt_find TYPE match_result_tab,
         lt_find_sub TYPE match_result_tab,
         lw_lines TYPE i,
         lw_cursor_line TYPE i,
         lw_cursor_pos TYPE i,
         lw_delto_line TYPE i,
         lw_delto_pos TYPE i,
         lw_cursor_offset TYPE i,
         lw_last TYPE c.

  CLEAR fw_query.

* Get selected content
  CALL METHOD o_textedit->get_selected_text_as_table
    IMPORTING
      table lt_query[].

* if no selected content, get complete content of abap edit box
  IF lt_query[] IS INITIAL.
    CALL METHOD o_textedit->get_text
      IMPORTING
        table  lt_query[]
      EXCEPTIONS
        OTHERS 1.
  ENDIF.

* Remove * comment
  LOOP AT lt_query INTO ls_query WHERE line(1'*'.
    CLEAR ls_query-line.
    MODIFY lt_query FROM ls_query.
  ENDLOOP.

* Remove " comment
  LOOP AT lt_query INTO ls_query WHERE line CS '"'.
*    condense ls_query-line.
    FIND ALL OCCURRENCES OF '"' IN ls_query-line RESULTS lt_find.
    IF sy-subrc NE 0"may not occurs
      CONTINUE.
    ENDIF.
    LOOP AT lt_find INTO ls_find.
      IF ls_find-offset GT 0.
* Search open '
        FIND ALL OCCURRENCES OF '''' IN ls_query-line(ls_find-offset)
             RESULTS lt_find_sub.
        IF sy-subrc 0.
          DESCRIBE TABLE lt_find_sub LINES lw_lines.
          lw_lines lw_lines MOD 2.
          IF lw_lines 1.
            CONTINUE.
          ENDIF.
        ENDIF.
        ls_query-line ls_query-line(ls_find-offset).
        EXIT"exit loop
      ELSE.
        CLEAR ls_query-line.
        EXIT"exit loop
      ENDIF.
    ENDLOOP.
    MODIFY lt_query FROM ls_query.
  ENDLOOP.

* Find active query
  CALL METHOD o_textedit->get_selection_pos
    IMPORTING
      from_line lw_cursor_line
      from_pos  lw_cursor_pos.
  lw_cursor_offset lw_cursor_pos 1.

  FIND ALL OCCURRENCES OF '.' IN TABLE lt_query RESULTS lt_find.
  CLEAR lw_delto_line,
          lw_delto_pos,
          lw_last.
  LOOP AT lt_find INTO ls_find.
    AT LAST.
      lw_last abap_true.
    ENDAT.
* Search for open '
    IF ls_find-offset GT 0.
      READ TABLE lt_query INTO ls_query INDEX ls_find-line.
      FIND ALL OCCURRENCES OF '''' IN ls_query(ls_find-offset)
           RESULTS lt_find_sub.
      DESCRIBE TABLE lt_find_sub LINES lw_lines.
      lw_lines lw_lines MOD 2.
* If open ' found, ignore the dot
      IF lw_lines 1.
        CONTINUE.
      ENDIF.
    ENDIF.

* Active Query
    IF ls_find-line GT lw_cursor_line
    OR ls_find-line lw_cursor_line
         AND ls_find-offset GE lw_cursor_offset )
    OR lw_last abap_true AND fw_force_last abap_true ).
* Delete all query after query active
      ls_find-line ls_find-line 1.
      DELETE lt_query FROM ls_find-line.
      ls_find-line ls_find-line 1.
* Do not keep the . for active query
      IF ls_find-offset 0.
        DELETE lt_query FROM ls_find-line.
      ELSE.
        ls_query-line ls_query-line(ls_find-offset).
        MODIFY lt_query FROM ls_query INDEX ls_find-line.
      ENDIF.
      EXIT.
* Query before active
    ELSE.
      lw_delto_line ls_find-line.
      lw_delto_pos ls_find-offset + 1.
    ENDIF.
  ENDLOOP.

* Delete all query before query active
  IF NOT lw_delto_line IS INITIAL.
    IF lw_delto_line GT 1.
      lw_delto_line lw_delto_line 1.
      DELETE lt_query FROM TO lw_delto_line.
    ENDIF.
    READ TABLE lt_query INTO ls_query INDEX 1.
    ls_query-line(lw_delto_pos''.
    MODIFY lt_query FROM ls_query INDEX 1.
  ENDIF.

* Delete empty lines
  DELETE lt_query WHERE line CO ' .'.

* Build query string & Remove unnessential spaces
  LOOP AT lt_query INTO ls_query.
    CONDENSE ls_query-line.
    SHIFT ls_query-line LEFT DELETING LEADING space.
    CONCATENATE fw_query ls_query-line INTO fw_query SEPARATED BY space.
  ENDLOOP.
  IF NOT fw_query IS INITIAL.
    fw_query fw_query+1.
  ENDIF.

* If no query selected, try to get the last one
  IF lt_query IS INITIAL AND fw_force_last space.
    PERFORM editor_get_query USING abap_true
                             CHANGING fw_query.
  ENDIF.
ENDFORM.                    " EDITOR_GET_QUERY

*&---------------------------------------------------------------------*
*&      Form  QUERY_PARSE
*&---------------------------------------------------------------------*
*       Split the query into 3 parts : Select / From / Where
*       - Select : List of the fields to extract
*       - From   : List of the tables - with join condition
*       - Where  : List of filters + group, order, having clauses
*----------------------------------------------------------------------*
*      -->FW_QUERY   Query to parse
*      <--FW_SELECT  Select part of the query
*      <--FW_FROM    From part of the query
*      <--FW_WHERE   Where part of the query
*      <--FW_ROWS    Number of rows to display
*      <--FW_UNION   Union part of the query
*      <--FW_NOAUTH  Unallowed table entered
*      <--FW_NEWSYNTAX Use new SQL syntax introduced with NW7.40 SP5
*      <--FW_ERROR   Cannot parse the query
*----------------------------------------------------------------------*
FORM query_parse  USING    fw_query TYPE string
                  CHANGING fw_select TYPE string
                           fw_from TYPE string
                           fw_where TYPE string
                           fw_union TYPE string
                           fw_rows TYPE n
                           fw_noauth TYPE c
                           fw_newsyntax TYPE c
                           fw_error TYPE c.

  DATA ls_find_select TYPE match_result,
         ls_find_from TYPE match_result,
         ls_find_where TYPE match_result,
         ls_sub LIKE LINE OF ls_find_select-submatches,
         lw_offset TYPE i,
         lw_length TYPE i,
         lw_query TYPE string,
         lo_regex TYPE REF TO cl_abap_regex,
         lt_split TYPE TABLE OF string,
         lw_string TYPE string,
         lw_tabix TYPE i,
         lw_table TYPE tabname.

  CLEAR fw_select,
          fw_from,
          fw_where,
          fw_rows,
          fw_union,
          fw_noauth,
          fw_newsyntax.

  lw_query fw_query.

* Search union
  FIND FIRST OCCURRENCE OF ' UNION SELECT ' IN lw_query
       RESULTS ls_find_select IGNORING CASE.
  IF sy-subrc 0.
    lw_offset ls_find_select-offset + 7.
    fw_union lw_query+lw_offset.
    lw_query lw_query(ls_find_select-offset).
  ENDIF.

* Search UP TO xxx ROWS.
* Catch the number of rows, delete command in query
  CREATE OBJECT lo_regex
    EXPORTING
      pattern     'UP TO ([0-9]+) ROWS'
      ignore_case abap_true.
  FIND FIRST OCCURRENCE OF REGEX lo_regex
       IN lw_query RESULTS ls_find_select.
  IF sy-subrc 0.
    READ TABLE ls_find_select-submatches INTO ls_sub INDEX 1.
    IF sy-subrc 0.
      fw_rows lw_query+ls_sub-offset(ls_sub-length).
    ENDIF.
    REPLACE FIRST OCCURRENCE OF REGEX lo_regex IN lw_query WITH ''.
  ELSE.
* Set default number of rows
    fw_rows s_customize-default_rows.
  ENDIF.

* Remove unused INTO (CORRESPONDING FIELDS OF)(TABLE)
* Detect new syntax in internal table name
  CONCATENATE '(INTO|APPENDING)( TABLE'
              '| CORRESPONDING FIELDS OF TABLE |'
              'CORRESPONDING FIELDS OF | )(\S*)'
              INTO lw_string SEPARATED BY space.
  CREATE OBJECT lo_regex
    EXPORTING
      pattern     lw_string
      ignore_case abap_true.
  FIND FIRST OCCURRENCE OF REGEX lo_regex
       IN lw_query RESULTS ls_find_select.
  IF sy-subrc 0.
    IF ls_find_select-length NE 0
    AND fw_query+ls_find_select-offset(ls_find_select-lengthCS '@'.
      fw_newsyntax abap_true.
    ENDIF.
    REPLACE FIRST OCCURRENCE OF REGEX lo_regex IN lw_query WITH ''.
  ENDIF.

* Search SELECT
  FIND FIRST OCCURRENCE OF 'SELECT ' IN lw_query
       RESULTS ls_find_select IGNORING CASE.
  IF sy-subrc NE 0.
    RETURN.
  ENDIF.

* Search FROM
  FIND FIRST OCCURRENCE OF ' FROM '
       IN SECTION OFFSET ls_find_select-offset OF lw_query
       RESULTS ls_find_from IGNORING CASE.
  IF sy-subrc NE 0.
    fw_error abap_true.
    RETURN.
  ENDIF.

* Search WHERE / GROUP BY / HAVING / ORDER BY
  FIND FIRST OCCURRENCE OF ' WHERE '
       IN SECTION OFFSET ls_find_from-offset OF lw_query
       RESULTS ls_find_where IGNORING CASE.
  IF sy-subrc NE 0.
    FIND FIRST OCCURRENCE OF ' GROUP BY ' IN lw_query
         RESULTS ls_find_where IGNORING CASE.
  ENDIF.
  IF sy-subrc NE 0.
    FIND FIRST OCCURRENCE OF ' HAVING ' IN lw_query
         RESULTS ls_find_where IGNORING CASE.
  ENDIF.
  IF sy-subrc NE 0.
    FIND FIRST OCCURRENCE OF ' ORDER BY ' IN lw_query
         RESULTS ls_find_where IGNORING CASE.
  ENDIF.

  lw_offset ls_find_select-offset + 7.
  lw_length ls_find_from-offset ls_find_select-offset 7.
  IF lw_length LE 0.
    fw_error abap_true.
    RETURN.
  ENDIF.
  fw_select lw_query+lw_offset(lw_length).

* Detect new syntax in comma field select separator
  IF fw_select CS ','.
    fw_newsyntax abap_true.
  ENDIF.

  lw_offset ls_find_from-offset + 6.
  IF ls_find_where IS INITIAL.
    fw_from lw_query+lw_offset.
    fw_where ''.
  ELSE.
    lw_length ls_find_where-offset ls_find_from-offset 6.
    fw_from lw_query+lw_offset(lw_length).
    lw_offset ls_find_where-offset.
    fw_where lw_query+lw_offset.
  ENDIF.

* Authority-check on used select tables
  IF s_customize-auth_object NE space OR s_customize-auth_select NE '*'.
    CONCATENATE 'JOIN' fw_from INTO lw_string SEPARATED BY space.
    TRANSLATE lw_string TO UPPER CASE.
    SPLIT lw_string AT space INTO TABLE lt_split.
    LOOP AT lt_split INTO lw_string.
      lw_tabix sy-tabix + 1.
      CHECK lw_string 'JOIN'.
* Read next line (table name)
      READ TABLE lt_split INTO lw_table INDEX lw_tabix.
      CHECK sy-subrc 0.

      IF s_customize-auth_object NE space.
        AUTHORITY-CHECK OBJECT s_customize-auth_object
                 ID 'TABLE' FIELD lw_table
                 ID 'ACTVT' FIELD s_customize-actvt_select.
      ELSEIF s_customize-auth_select NE '*'
      AND NOT lw_table CP s_customize-auth_select.
        sy-subrc 4.
      ENDIF.
      IF sy-subrc NE 0.
        CONCATENATE 'No authorisation for table'(m13lw_table
                    INTO lw_string SEPARATED BY space.
        MESSAGE lw_string TYPE c_msg_success DISPLAY LIKE c_msg_error.
        CLEAR fw_from.
        fw_noauth abap_true.
        RETURN.
      ENDIF.
    ENDLOOP.
  ENDIF.

ENDFORM.                    " QUERY_PARSE

*&---------------------------------------------------------------------*
*&      Form  add_line_to_table
*&---------------------------------------------------------------------*
*       Add a string line in a table
*       Break line at 255 char, respecting words if possible
*----------------------------------------------------------------------*
*      -->FW_LINE    Line to add in table
*      <--FT_TABLE   Table to append
*----------------------------------------------------------------------*
FORM add_line_to_table USING fw_line TYPE string
                       CHANGING ft_table TYPE table.
  DATA lw_length TYPE i,
         lw_offset TYPE i,
         ls_find TYPE match_result.

  lw_length strlenfw_line ).
  lw_offset 0.
  DO.
    IF lw_length LE c_line_max.
      APPEND fw_line+lw_offset(lw_lengthTO ft_table.
      EXIT"exit do
    ELSE.
      FIND ALL OCCURRENCES OF REGEX '\s' "search space
           IN SECTION OFFSET lw_offset LENGTH c_line_max
           OF fw_line RESULTS ls_find.
      IF sy-subrc NE 0.
        APPEND fw_line+lw_offset(c_line_maxTO ft_table.
        lw_length lw_length c_line_max.
        lw_offset lw_offset + c_line_max.
      ELSE.
        ls_find-length ls_find-offset lw_offset.
        APPEND fw_line+lw_offset(ls_find-lengthTO ft_table.
        lw_length lw_length + lw_offset ls_find-offset 1.
        lw_offset ls_find-offset + 1.
      ENDIF.
    ENDIF.
  ENDDO.

ENDFORM.                    "add_line_to_table

*&---------------------------------------------------------------------*
*&      Form  QUERY_GENERATE
*&---------------------------------------------------------------------*
*       Create SELECT SQL query in a new generated temp program
*----------------------------------------------------------------------*
*      -->FW_SELECT    Select part of the query
*      -->FW_FROM      From part of the query
*      -->FW_WHERE     Where part of the query
*      -->FW_DISPLAY   Display code instead of generated routine
*      -->FW_NEWSYNTAX Use new SQL syntax introduced with NW7.40 SP5
*      <--FW_PROGRAM   Name of the generated program
*      <--FW_ROWS      Number of rows to display
*      <--FT_FIELDLIST List of fields to display
*      <--FW_COUNT     = true if query is only count( * )
*----------------------------------------------------------------------*
FORM query_generate  USING    fw_select TYPE string
                              fw_from TYPE string
                              fw_where TYPE string
                              fw_display TYPE c
                              fw_newsyntax TYPE c
                     CHANGING fw_program TYPE sy-repid
                              fw_rows TYPE n
                              ft_fieldlist TYPE ty_fieldlist_table
                              fw_count TYPE c.

  DATA lt_code_string TYPE TABLE OF string,
         lt_split TYPE TABLE OF string,
         lw_string TYPE string,
         lw_string2 TYPE string,
         BEGIN OF ls_table_alias,
           table(50TYPE c,
           alias(50TYPE c,
         END OF ls_table_alias,
         lt_table_alias LIKE TABLE OF ls_table_alias,
         lw_select TYPE string,
         lw_from TYPE string,
         lw_index TYPE i,
         lw_select_distinct TYPE c,
         lw_select_length TYPE i,
         lw_char_10(10TYPE c,
         lw_field_number(6TYPE n,
         lw_current_line TYPE i,
         lw_current_length TYPE i,
         lw_struct_line TYPE string,
         lw_struct_line_type TYPE string,
         lw_select_table TYPE string,
         lw_select_field TYPE string,
         lw_dd03l_fieldname TYPE dd03l-fieldname,
         lw_position_dummy TYPE dd03l-position,
         lw_mess(255),
         lw_line TYPE i,
         lw_word(30),
         ls_fieldlist TYPE ty_fieldlist,
         lw_strlen_string TYPE string,
         lw_explicit TYPE string.

  DEFINE c.
    lw_strlen_string &1.
    perform add_line_to_table using lw_strlen_string
                              changing lt_code_string.
  END-OF-DEFINITION.

  CLEAR lw_select_distinct,
          fw_count.

* Write Header
  'PROGRAM SUBPOOL.'.
  '** GENERATED PROGRAM * DO NOT CHANGE IT **'.
  'TYPE-POOLS: slis.'.                                    "#EC NOTEXT
  ''.

  lw_select fw_select.
  TRANSLATE lw_select TO UPPER CASE.

  lw_from fw_from.
  TRANSLATE lw_from TO UPPER CASE.

* Search special term "single" or "distinct"
  lw_select_length strlenlw_select ).
  IF lw_select_length GE 7.
    lw_char_10 lw_select(7).
    IF lw_char_10 'SINGLE'.
* Force rows number = 1 for select single
      fw_rows 1.
      lw_select lw_select+7.
      lw_select_length lw_select_length 7.
    ENDIF.
  ENDIF.
  IF lw_select_length GE 9.
    lw_char_10 lw_select(9).
    IF lw_char_10 'DISTINCT'.
      lw_select_distinct abap_true.
      lw_select lw_select+9.
      lw_select_length lw_select_length 9.
    ENDIF.
  ENDIF.

* Search for special syntax "count( * )"
  IF lw_select 'COUNT( * )'.
    fw_count abap_true.
  ENDIF.

* Create alias table mapping
  SPLIT lw_from AT space INTO TABLE lt_split.
  LOOP AT lt_split INTO lw_string.
    IF lw_string IS INITIAL OR lw_string CO space.
      DELETE lt_split.
    ENDIF.
  ENDLOOP.
  DO.
    READ TABLE lt_split TRANSPORTING NO FIELDS WITH KEY 'AS'.
    IF sy-subrc NE 0.
      EXIT"exit do
    ENDIF.
    lw_index sy-tabix 1.
    READ TABLE lt_split INTO lw_string INDEX lw_index.
    ls_table_alias-table lw_string.
    DELETE lt_split INDEX lw_index"delete table field
    DELETE lt_split INDEX lw_index"delete keywork AS
    READ TABLE lt_split INTO lw_string INDEX lw_index.
    ls_table_alias-alias lw_string.
    DELETE lt_split INDEX lw_index"delete alias field
    APPEND ls_table_alias TO lt_table_alias.
  ENDDO.
* If no alias table found, create just an entry for "*"
  IF lt_table_alias[] IS INITIAL.
    READ TABLE lt_split INTO lw_string INDEX 1.
    ls_table_alias-table lw_string.
    ls_table_alias-alias '*'.
    APPEND ls_table_alias TO lt_table_alias.
  ENDIF.
  SORT lt_table_alias BY alias.

* Write Data declaration
  '***************************************'.              "#EC NOTEXT
  '*      Begin of data declaration      *'.              "#EC NOTEXT
  '*   Used to store lines of the query  *'.              "#EC NOTEXT
  '***************************************'.              "#EC NOTEXT
  'DATA: BEGIN OF s_result'.                              "#EC NOTEXT
  lw_field_number 1.

  lw_string lw_select.
  IF fw_newsyntax abap_true.
    TRANSLATE lw_string USING ', '.
    CONDENSE lw_string.
  ENDIF.
  SPLIT lw_string AT space INTO TABLE lt_split.

  LOOP AT lt_split INTO lw_string.
    lw_current_line sy-tabix.
    IF lw_string IS INITIAL OR lw_string CO space.
      CONTINUE.
    ENDIF.
    IF lw_string 'AS'.
      DELETE lt_split INDEX lw_current_line"delete AS
      DELETE lt_split INDEX lw_current_line"delete the alias name
      CONTINUE.
    ENDIF.
    lw_current_length strlenlw_string ).

    CLEAR ls_fieldlist.
    ls_fieldlist-ref_field lw_string.
* Manage "Count"
    IF lw_current_length GE 6.
      lw_char_10 lw_string(6).
    ELSE.
      CLEAR lw_char_10.
    ENDIF.
    IF lw_char_10 'COUNT('.
      CONCATENATE 'F' lw_field_number INTO ls_fieldlist-field.
      CONCATENATE ',' ls_fieldlist-field INTO lw_struct_line.

      lw_index lw_current_line + 1.
      DO.
        SEARCH lw_string FOR ')'.
        IF sy-subrc 0.
          EXIT.
        ELSE.
* If there is space in the "count()", delete next lines
          READ TABLE lt_split INTO lw_string INDEX lw_index.
          IF sy-subrc NE 0.
            EXIT.
          ENDIF.
          CONCATENATE ls_fieldlist-ref_field lw_string
                      INTO ls_fieldlist-ref_field SEPARATED BY space.
          DELETE lt_split INDEX lw_index.
        ENDIF.
      ENDDO.
      CONCATENATE lw_struct_line 'TYPE i'                   "#EC NOTEXT
                  INTO lw_struct_line SEPARATED BY space.
      lw_struct_line.
      APPEND ls_fieldlist TO ft_fieldlist.
      lw_field_number lw_field_number + 1.
      CONTINUE.
    ENDIF.

* Manage Agregate AVG
    IF lw_current_length GE 4.
      lw_char_10 lw_string(4).
    ELSE.
      CLEAR lw_char_10.
    ENDIF.
    IF lw_char_10 'AVG('.
      CONCATENATE 'F' lw_field_number INTO ls_fieldlist-field.
      CONCATENATE ',' ls_fieldlist-field INTO lw_struct_line.

      lw_index lw_current_line + 1.
      DO.
        SEARCH lw_string FOR ')'.
        IF sy-subrc 0.
          EXIT.
        ELSE.
* If there is space in the agregate, delete next lines
          READ TABLE lt_split INTO lw_string INDEX lw_index.
          IF sy-subrc NE 0.
            EXIT.
          ENDIF.
          CONCATENATE ls_fieldlist-ref_field lw_string
                      INTO ls_fieldlist-ref_field SEPARATED BY space.
          DELETE lt_split INDEX lw_index.
        ENDIF.
      ENDDO.
      CONCATENATE lw_struct_line 'TYPE f'                   "#EC NOTEXT
                  INTO lw_struct_line SEPARATED BY space.
      lw_struct_line.
      APPEND ls_fieldlist TO ft_fieldlist.
      lw_field_number lw_field_number + 1.
      CONTINUE.
    ENDIF.

* Manage agregate SUM, MAX, MIN
    IF lw_current_length GE 4.
      lw_char_10 lw_string(4).
    ELSE.
      CLEAR lw_char_10.
    ENDIF.
    IF lw_char_10 'SUM(' OR lw_char_10 'MAX('
    OR lw_char_10 'MIN('.
      lw_index lw_current_line + 1.
      DO.
        SEARCH lw_string FOR ')'.
        IF sy-subrc 0.
          EXIT.
        ELSE.
* Search name of the field in next lines.
          READ TABLE lt_split INTO lw_string INDEX lw_index.
          IF sy-subrc NE 0.
            EXIT.
          ENDIF.
          CONCATENATE ls_fieldlist-ref_field lw_string
                      INTO ls_fieldlist-ref_field SEPARATED BY space.
          IF lw_string2 IS INITIAL.
            lw_string2 lw_string.
          ENDIF.
* Delete lines of agregage in field table
          DELETE lt_split INDEX lw_index.
        ENDIF.
      ENDDO.
      lw_string lw_string2.
    ENDIF.

* Now lw_string contain a field name.
* We have to find the field description
    SPLIT lw_string AT '~' INTO lw_select_table lw_select_field.
    IF lw_select_field IS INITIAL.
      lw_select_field lw_select_table.
      lw_select_table '*'.
    ENDIF.
* Search if alias table used
    CLEAR ls_table_alias.
    READ TABLE lt_table_alias INTO ls_table_alias
               WITH KEY alias lw_select_table             "#EC WARNOK
               BINARY SEARCH.
    IF sy-subrc 0.
      lw_select_table ls_table_alias-table.
    ENDIF.
    ls_fieldlist-ref_table lw_select_table.
    IF lw_string '*' OR lw_select_field '*'" expansion table~*
      CLEAR lw_explicit.
      SELECT fieldname position
      INTO   (lw_dd03l_fieldname,lw_position_dummy)
      FROM   dd03l
      WHERE  tabname    lw_select_table
      AND    fieldname <> 'MANDT'
      AND    as4local   c_vers_active
      AND    as4vers    space
      AND (  comptype   c_ddic_dtelm
          OR comptype   space )
      ORDER BY position.

        lw_select_field lw_dd03l_fieldname.

        CONCATENATE 'F' lw_field_number INTO ls_fieldlist-field.
        ls_fieldlist-ref_field lw_select_field.
        APPEND ls_fieldlist TO ft_fieldlist.
        CONCATENATE ',' ls_fieldlist-field INTO lw_struct_line.

        CONCATENATE lw_select_table '-' lw_select_field
                    INTO lw_struct_line_type.
        CONCATENATE lw_struct_line 'TYPE' lw_struct_line_type
                    INTO lw_struct_line
                    SEPARATED BY space.
        lw_struct_line.
        lw_field_number lw_field_number + 1.
* Explicit list of fields instead of *
* Generate longer query but mandatory in case of T1~* or MARA~*
* Required also in some special cases, for example if table use include
        IF ls_table_alias-alias space OR ls_table_alias-alias '*'.
          CONCATENATE lw_explicit lw_select_table
                      INTO lw_explicit SEPARATED BY space.
        ELSE.
          CONCATENATE lw_explicit ls_table_alias-alias
                      INTO lw_explicit SEPARATED BY space.
        ENDIF.
        CONCATENATE lw_explicit '~' lw_select_field INTO lw_explicit.
      ENDSELECT.
      IF sy-subrc NE 0.
        MESSAGE e701(1rWITH lw_select_table"table does not exist
      ENDIF.
      IF NOT lw_explicit IS INITIAL.
        REPLACE FIRST OCCURRENCE OF lw_string
                IN lw_select WITH lw_explicit.
      ENDIF.

    ELSE"Simple field
      CONCATENATE 'F' lw_field_number INTO ls_fieldlist-field.
      ls_fieldlist-ref_field lw_select_field.
      APPEND ls_fieldlist TO ft_fieldlist.

      CONCATENATE ',' ls_fieldlist-field INTO lw_struct_line.

      CONCATENATE lw_select_table '-' lw_select_field
                  INTO lw_struct_line_type.
      CONCATENATE lw_struct_line 'TYPE' lw_struct_line_type
                  INTO lw_struct_line
                  SEPARATED BY space.
      lw_struct_line.
      lw_field_number lw_field_number + 1.
    ENDIF.
  ENDLOOP.

* Add a count field
  CLEAR ls_fieldlist.
  ls_fieldlist-field 'COUNT'.
  ls_fieldlist-ref_table ''.
  ls_fieldlist-ref_field 'Count'.
  APPEND ls_fieldlist TO ft_fieldlist.
  ', COUNT type i'.                                       "#EC NOTEXT

* End of data definition
  ', END OF s_result'.                                    "#EC NOTEXT
  ', t_result like table of s_result'.                    "#EC NOTEXT
  ', w_timestart type timestampl'.                        "#EC NOTEXT
  ', w_timeend type timestampl.'.                         "#EC NOTEXT

* Write the dynamic subroutine that run the SELECT
  'FORM run_sql CHANGING fo_result TYPE REF TO data'.     "#EC NOTEXT
  '                      fw_time type p'.                 "#EC NOTEXT
  '                      fw_count type i.'.               "#EC NOTEXT
  'field-symbols <fs_result> like s_result.'.             "#EC NOTEXT
  '***************************************'.              "#EC NOTEXT
  '*            Begin of query           *'.              "#EC NOTEXT
  '***************************************'.              "#EC NOTEXT
  'get TIME STAMP FIELD w_timestart.'.                    "#EC NOTEXT
  IF fw_count abap_true.
    CONCATENATE 'SELECT SINGLE' lw_select                   "#EC NOTEXT
                INTO lw_select SEPARATED BY space.
    lw_select.
    IF fw_newsyntax abap_true.
      'INTO @s_result-f000001'.                           "#EC NOTEXT
    ELSE.
      'INTO s_result-f000001'.                            "#EC NOTEXT
    ENDIF.
  ELSE.
    IF lw_select_distinct NE space.
      CONCATENATE 'SELECT DISTINCT' lw_select               "#EC NOTEXT
                  INTO lw_select SEPARATED BY space.
    ELSE.
      CONCATENATE 'SELECT' lw_select                        "#EC NOTEXT
                  INTO lw_select SEPARATED BY space.
    ENDIF.
    lw_select.
    IF fw_newsyntax abap_true.
      'INTO TABLE @t_result'.                             "#EC NOTEXT
    ELSE.
      'INTO TABLE t_result'.                              "#EC NOTEXT
    ENDIF.

* Add UP TO xxx ROWS
    IF NOT fw_rows IS INITIAL.
      'UP TO'.                                            "#EC NOTEXT
      fw_rows.
      'ROWS'.                                             "#EC NOTEXT
    ENDIF.
  ENDIF.

  'FROM'.                                                 "#EC NOTEXT
  lw_from.

* Where, group by, having, order by
  IF NOT fw_where IS INITIAL.
    fw_where.
  ENDIF.
  '.'.

* Display query execution time
  'get TIME STAMP FIELD w_timeend.'.                      "#EC NOTEXT
  'fw_time = w_timeend - w_timestart.'.                   "#EC NOTEXT
  'fw_count = sy-dbcnt.'.                                 "#EC NOTEXT

* If select count( * ), display number of results
  IF fw_count NE space.
    'MESSAGE i753(TG) WITH s_result-f000001.'.            "#EC NOTEXT
  ENDIF.
  'loop at t_result assigning <fs_result>.'.
  ' <fs_result>-count = 1.'.
  'endloop.'.
  'GET REFERENCE OF t_result INTO fo_result.'.            "#EC NOTEXT
  'ENDFORM.'.                                             "#EC NOTEXT
  CLEAR lw_line,
          lw_word,
          lw_mess.
  SYNTAX-CHECK FOR lt_code_string PROGRAM sy-repid
               MESSAGE lw_mess LINE lw_line WORD lw_word.
  IF sy-subrc NE AND fw_display space.
    MESSAGE lw_mess TYPE c_msg_success DISPLAY LIKE c_msg_error.
    CLEAR fw_program.
    RETURN.
  ENDIF.

  IF fw_display space.
    GENERATE SUBROUTINE POOL lt_code_string NAME fw_program.
  ELSE.
    IF lw_mess IS NOT INITIAL.
      lw_explicit lw_line.
      CONCATENATE lw_mess '(line'(m28lw_explicit ',word'(m29)
                  lw_word ')'(m30)
                  INTO lw_mess SEPARATED BY space.
      MESSAGE lw_mess TYPE c_msg_success DISPLAY LIKE c_msg_error.
    ENDIF.
    EDITOR-CALL FOR lt_code_string DISPLAY-MODE
                TITLE 'Generated code for current query'(t01).
  ENDIF.

ENDFORM.                    " QUERY_GENERATE

*&---------------------------------------------------------------------*
*&      Form  RESULT_DISPLAY
*&---------------------------------------------------------------------*
*       Display data table in the bottom ALV part of the screen
*----------------------------------------------------------------------*
*      -->FO_RESULT    Reference to data to display
*      -->FT_FIELDLIST List of fields to display
*      -->FW_TITLE     Title of the ALV
*----------------------------------------------------------------------*
FORM result_display  USING fo_result TYPE REF TO data
                           ft_fieldlist TYPE ty_fieldlist_table
                           fw_title TYPE string.
*  TYPE-POOLS lvc. "for older sap system only

  DATA ls_layout TYPE lvc_s_layo,
         lt_fieldcat TYPE lvc_t_fcat,
         ls_fieldlist TYPE ty_fieldlist,
         ls_fieldcat LIKE LINE OF lt_fieldcat.
  DATA lo_descr_table TYPE REF TO cl_abap_tabledescr,
         lo_descr_line TYPE REF TO cl_abap_structdescr,
         ls_compx TYPE abap_compdescr,
         lw_height TYPE i.

  FIELD-SYMBOLS<lft_data> TYPE ANY TABLE.

  ASSIGN fo_result->TO <lft_data>.

* Get data type for COUNT & AVG fields
  lo_descr_table ?=
    cl_abap_typedescr=>describe_by_data_reffo_result ).
  lo_descr_line ?= lo_descr_table->get_table_line_type).

  LOOP AT ft_fieldlist INTO ls_fieldlist.
    CLEAR ls_fieldcat.
    ls_fieldcat-fieldname ls_fieldlist-field.

    IF NOT ls_fieldlist-ref_table IS INITIAL.
      ls_fieldcat-ref_field ls_fieldlist-ref_field.
      ls_fieldcat-ref_table ls_fieldlist-ref_table.
      IF s_customize-techname space.
        ls_fieldcat-reptext ls_fieldlist-ref_field.
      ELSE.
        ls_fieldcat-reptext ls_fieldlist-ref_field.
        ls_fieldcat-scrtext_s ls_fieldlist-ref_field.
        ls_fieldcat-scrtext_m ls_fieldlist-ref_field.
        ls_fieldcat-scrtext_l ls_fieldlist-ref_field.
      ENDIF.
    ELSE"COUNT & AVG field
      CLEAR ls_compx.
      READ TABLE lo_descr_line->components INTO ls_compx
                 WITH KEY name ls_fieldlist-field.        "#EC WARNOK
      ls_fieldcat-intlen ls_compx-length.
      ls_fieldcat-decimals ls_compx-decimals.
      ls_fieldcat-inttype ls_compx-type_kind.
      ls_fieldcat-reptext ls_fieldlist-ref_field.
      ls_fieldcat-scrtext_s ls_fieldlist-ref_field.
      ls_fieldcat-scrtext_m ls_fieldlist-ref_field.
      ls_fieldcat-scrtext_l ls_fieldlist-ref_field.
    ENDIF.
    APPEND ls_fieldcat TO lt_fieldcat.
  ENDLOOP.

  ls_layout-smalltitle abap_true.
  ls_layout-zebra abap_true.
  ls_layout-cwidth_opt abap_true.
  ls_layout-grid_title fw_title.
  ls_layout-countfname 'COUNT'.

* Set the grid config and content
  CALL METHOD o_alv_result->set_table_for_first_display
    EXPORTING
      is_layout       ls_layout
    CHANGING
      it_outtab       <lft_data>
      it_fieldcatalog lt_fieldcat.

* Search if grid is currently displayed
  CALL METHOD o_splitter->get_row_height
    EXPORTING
      id     1
    IMPORTING
      result lw_height.
  CALL METHOD cl_gui_cfw=>flush.

* If grid is hidden, display it
  IF lw_height 100.
    CALL METHOD o_splitter->set_row_height
      EXPORTING
        id     1
        height 20.
  ENDIF.
ENDFORM.                    " RESULT_DISPLAY

*&---------------------------------------------------------------------*
*&      Form  DDIC_INIT
*&---------------------------------------------------------------------*
*       Initialize ddic tree
*----------------------------------------------------------------------*
FORM ddic_init.
  DATA ls_header TYPE treev_hhdr,
         ls_event TYPE cntl_simple_event,
         lt_events TYPE cntl_simple_events,
         lo_dragdrop TYPE REF TO cl_dragdrop,
         lw_mode TYPE i.

  ls_header-heading 'SAP Table/Fields'(t02).
  ls_header-width 30.
  lw_mode cl_gui_column_tree=>node_sel_mode_single.

  CREATE OBJECT o_tree_ddic
    EXPORTING
      parent                      o_container_ddic
      node_selection_mode         lw_mode
      item_selection              abap_true
      hierarchy_column_name       c_ddic_col1
      hierarchy_header            ls_header
    EXCEPTIONS
      cntl_system_error           1
      create_error                2
      failed                      3
      illegal_node_selection_mode 4
      illegal_column_name         5
      lifetime_error              6.
  IF sy-subrc <> 0.
    MESSAGE a000(tree_control_msg).
  ENDIF.

* Column2
  CALL METHOD o_tree_ddic->add_column
    EXPORTING
      name                         c_ddic_col2
      width                        21
      header_text                  'Description'(t03)
    EXCEPTIONS
      column_exists                1
      illegal_column_name          2
      too_many_columns             3
      illegal_alignment            4
      different_column_types       5
      cntl_system_error            6
      failed                       7
      predecessor_column_not_found 8.

* Manage Item clic event to copy value in clipboard
  ls_event-eventid cl_gui_column_tree=>eventid_item_double_click.
  ls_event-appl_event abap_true.
  APPEND ls_event TO lt_events.

  CALL METHOD o_tree_ddic->set_registered_events
    EXPORTING
      events                    lt_events
    EXCEPTIONS
      cntl_error                1
      cntl_system_error         2
      illegal_event_combination 3.
  IF sy-subrc <> 0.
    MESSAGE a000(tree_control_msg).
  ENDIF.

* Manage Drag from DDIC editor
  CREATE OBJECT lo_dragdrop.
  CALL METHOD lo_dragdrop->add
    EXPORTING
      flavor     'EDIT_INSERT'
      dragsrc    abap_true
      droptarget space
      effect     cl_dragdrop=>copy.
  CALL METHOD lo_dragdrop->get_handle
    IMPORTING
      handle w_dragdrop_handle_tree.

  SET HANDLER o_handle_event->hnd_ddic_item_dblclick FOR o_tree_ddic.
  SET HANDLER o_handle_event->hnd_ddic_drag FOR o_tree_ddic.

* Calculate ZSPRO nodes to add at the bottom of the ddic tree
  PERFORM ddic_add_tree_zspro IN PROGRAM (sy-repidIF FOUND.

ENDFORM.                    " DDIC_INIT

*&---------------------------------------------------------------------*
*&      Form  DDIC_SET_TREE
*&---------------------------------------------------------------------*
*       Refresh query with list of table/fields of the given query
*       Add User defined tree from ZSPRO (if relevant)
*----------------------------------------------------------------------*
*      -->FW_FROM  From part of the query
*----------------------------------------------------------------------*
FORM ddic_set_tree USING fw_from TYPE string.

  DATA lw_from TYPE string,
         lt_split TYPE TABLE OF string,
         lw_string TYPE string,
         lw_tabix TYPE i,
         BEGIN OF ls_table_list,
           table(30),
           alias(30),
         END OF ls_table_list,
         lt_table_list LIKE TABLE OF ls_table_list,
         lw_node_number(6TYPE n,
         ls_node LIKE LINE OF t_node_ddic,
         ls_item LIKE LINE OF t_item_ddic,
         lw_parent_node LIKE ls_node-node_key,
         BEGIN OF ls_ddic_fields,
           tabname TYPE dd03l-tabname,
           fieldname TYPE dd03l-fieldname,
           position TYPE dd03l-position,
           keyflag TYPE dd03l-keyflag,
           ddtext1 TYPE dd03t-ddtext,
           ddtext2 TYPE dd04t-ddtext,
         END OF ls_ddic_fields,
         lt_ddic_fields LIKE TABLE OF ls_ddic_fields.

  CONCATENATE 'FROM' fw_from INTO lw_from SEPARATED BY space.

  TRANSLATE lw_from TO UPPER CASE.

  SPLIT lw_from AT space INTO TABLE lt_split.
  LOOP AT lt_split INTO lw_string.
    lw_tabix sy-tabix + 1.
    CHECK sy-tabix OR lw_string 'JOIN'.
* Read next line (table name)
    READ TABLE lt_split INTO lw_string INDEX lw_tabix.
    CHECK sy-subrc 0.

    CLEAR ls_table_list.
    ls_table_list-table lw_string.

    lw_tabix lw_tabix + 1.
* Read next line (search alias)
    READ TABLE lt_split INTO lw_string INDEX lw_tabix.
    IF sy-subrc AND lw_string 'AS'.
      lw_tabix lw_tabix + 1.
      READ TABLE lt_split INTO lw_string INDEX lw_tabix.
      IF sy-subrc 0.
        ls_table_list-alias lw_string.
      ENDIF.
    ENDIF.
    APPEND ls_table_list TO lt_table_list.
  ENDLOOP.

* Get list of fields for selected tables
  IF NOT lt_table_list IS INITIAL.
    SELECT dd03l~tabname dd03l~fieldname dd03l~position
           dd03l~keyflag dd03t~ddtext dd04t~ddtext
           INTO TABLE lt_ddic_fields
           FROM dd03l
           LEFT OUTER JOIN dd03t
           ON dd03l~tabname dd03t~tabname
           AND dd03l~fieldname dd03t~fieldname
           AND dd03l~as4local dd03t~as4local
           AND dd03t~ddlanguage sy-langu
           LEFT OUTER JOIN dd04t
           ON dd03l~rollname dd04t~rollname
           AND dd03l~as4local dd04t~as4local
           AND dd04t~ddlanguage sy-langu
           FOR ALL ENTRIES IN lt_table_list
           WHERE dd03l~tabname lt_table_list-table
           AND dd03l~as4local c_vers_active
           AND dd03l~as4vers space
           AND dd03l~comptype c_ddic_dtelm
           OR    dd03l~comptype space ).
    SORT lt_ddic_fields BY tabname keyflag DESCENDING position.
    DELETE ADJACENT DUPLICATES FROM lt_ddic_fields
                               COMPARING tabname fieldname.
  ENDIF.

* Build Node & Item tree
  REFRESH t_node_ddic,
            t_item_ddic.
  lw_node_number 0.
  LOOP AT lt_table_list INTO ls_table_list.
* Check table exists (has at least one field)
    READ TABLE lt_ddic_fields TRANSPORTING NO FIELDS
               WITH KEY tabname ls_table_list-table.
    IF sy-subrc NE 0.
      DELETE lt_table_list.
      CONTINUE.
    ENDIF.

    lw_node_number lw_node_number + 1.
    CLEAR ls_node.
    ls_node-node_key lw_node_number.
    ls_node-isfolder abap_true.
    ls_node-n_image '@PO@'.
    ls_node-exp_image '@PO@'.
    ls_node-expander abap_true.
    APPEND ls_node TO t_node_ddic.

    CLEAR ls_item.
    ls_item-node_key lw_node_number.
    ls_item-class cl_gui_column_tree=>item_class_text.
    ls_item-item_name c_ddic_col1.
    IF ls_table_list-alias IS INITIAL.
      ls_item-text ls_table_list-table.
    ELSE.
      CONCATENATE ls_table_list-table 'AS' ls_table_list-alias
                   INTO ls_item-text SEPARATED BY space.
    ENDIF.
    APPEND ls_item TO t_item_ddic.
    ls_item-item_name c_ddic_col2.
    SELECT SINGLE ddtext INTO ls_item-text
           FROM dd02t
           WHERE tabname ls_table_list-table
           AND ddlanguage sy-langu
           AND as4local c_vers_active
           AND as4vers space.
    IF sy-subrc NE 0.
      ls_item-text ls_table_list-table.
    ENDIF.
    APPEND ls_item TO t_item_ddic.

* Display list of fields
    lw_parent_node ls_node-node_key.
    LOOP AT lt_ddic_fields INTO ls_ddic_fields
            WHERE tabname ls_table_list-table.
      CLEAR ls_node.
      lw_node_number lw_node_number + 1.
      ls_node-node_key lw_node_number.
      ls_node-relatkey lw_parent_node.
      ls_node-relatship cl_gui_column_tree=>relat_last_child.
      IF ls_ddic_fields-keyflag space.
        ls_node-n_image '@3W@'.
        ls_node-exp_image '@3W@'.
      ELSE.
        ls_node-n_image '@3V@'.
        ls_node-exp_image '@3V@'.
      ENDIF.
      ls_node-dragdropid w_dragdrop_handle_tree.
      APPEND ls_node TO t_node_ddic.

      CLEAR ls_item.
      ls_item-node_key lw_node_number.
      ls_item-class cl_gui_column_tree=>item_class_text.
      ls_item-item_name c_ddic_col1.
      ls_item-text ls_ddic_fields-fieldname.
      APPEND ls_item TO t_item_ddic.
      ls_item-item_name c_ddic_col2.
      IF NOT ls_ddic_fields-ddtext1 IS INITIAL.
        ls_item-text ls_ddic_fields-ddtext1.
      ELSE.
        ls_item-text ls_ddic_fields-ddtext2.
      ENDIF.
      APPEND ls_item TO t_item_ddic.
    ENDLOOP.
  ENDLOOP.

* Add User defined tree from ZSPRO (if relevant)
  IF NOT t_node_zspro IS INITIAL.
    APPEND LINES OF t_node_zspro TO t_node_ddic.
    APPEND LINES OF t_item_zspro TO t_item_ddic.
  ENDIF.

  CALL METHOD o_tree_ddic->delete_all_nodes.

  CALL METHOD o_tree_ddic->add_nodes_and_items
    EXPORTING
      node_table                     t_node_ddic
      item_table                     t_item_ddic
      item_table_structure_name      'MTREEITM'
    EXCEPTIONS
      failed                         1
      cntl_system_error              3
      error_in_tables                4
      dp_error                       5
      table_structure_name_not_found 6.
  IF sy-subrc <> 0.
    MESSAGE a000(tree_control_msg).
  ENDIF.

  DESCRIBE TABLE lt_table_list LINES lw_tabix.

* If no table found, display message
  IF lw_tabix 0.
    MESSAGE 'No valid table found'(m15TYPE c_msg_success
            DISPLAY LIKE c_msg_error.
* If 1 table found, expand it
  ELSEIF lw_tabix 1.
    o_tree_ddic->expand_root_nodes).
  ENDIF.
ENDFORM.                    " DDIC_SET_TREE

*&---------------------------------------------------------------------*
*&      Form  REPO_SAVE_QUERY
*&---------------------------------------------------------------------*
*       Save query
*----------------------------------------------------------------------*
FORM repo_save_query.
  DATA lt_query TYPE soli_tab,
         ls_query LIKE LINE OF lt_query,
         lw_query_with_cr TYPE string,
         lw_guid TYPE guid_32,
         ls_ztoad TYPE ztoad,
         lw_timestamp(14TYPE c.

* Set default options
  SELECT SINGLE class INTO s_options-visibilitygrp
         FROM usr02
         WHERE bname sy-uname.
  s_options-visibility '0'.

* Ask for options / query name
  CALL SCREEN 0200 STARTING AT 10 5
                  ENDING AT 60 7.
  IF s_options IS INITIAL.
    MESSAGE 'Action cancelled'(m14TYPE c_msg_success
            DISPLAY LIKE c_msg_error.
    RETURN.
  ENDIF.

* Get content of abap edit box
  CALL METHOD o_textedit->get_text
    IMPORTING
      table  lt_query[]
    EXCEPTIONS
      OTHERS 1.

* Serialize query into a string
  CLEAR lw_query_with_cr.
  LOOP AT lt_query INTO ls_query.
    CONCATENATE lw_query_with_cr ls_query cl_abap_char_utilities=>cr_lf
                INTO lw_query_with_cr.
  ENDLOOP.

* Generate new GUID
  DO 100 TIMES.
* Old function to get an unique id
    CALL FUNCTION 'GUID_CREATE'
      IMPORTING
        ev_guid_32 lw_guid.
* New function to get an unique id (do not work on older sap system)
*    TRY.
*        lw_guid = cl_system_uuid=>create_uuid_c32_static( ).
*      CATCH cx_uuid_error.
*        EXIT. "exit do
*    ENDTRY.

* Check that this uid is not already used
    SELECT SINGLE queryid INTO ls_ztoad-queryid
           FROM ztoad
           WHERE queryid lw_guid.
    IF sy-subrc NE 0.
      EXIT"exit do
    ENDIF.
  ENDDO.

  ls_ztoad-queryid lw_guid.
  ls_ztoad-owner sy-uname.
  lw_timestamp(8sy-datum.
  lw_timestamp+8 sy-uzeit.
  ls_ztoad-aedat lw_timestamp.
  ls_ztoad-text s_options-name.
  ls_ztoad-visibility s_options-visibility.
  ls_ztoad-visibility_group s_options-visibilitygrp.
  ls_ztoad-query lw_query_with_cr.
  INSERT ztoad FROM ls_ztoad.
  IF sy-subrc 0.
    MESSAGE s031(r9)"Query saved
  ELSE.
    MESSAGE e220(iqapi)"Error when saving the query
  ENDIF.

* Reset the modified status
  o_textedit->set_textmodified_status).

* Refresh repository to display new saved query
  PERFORM repo_fill.

* Focus repository on new saved query
  PERFORM repo_focus_query USING lw_guid.
ENDFORM.                    " REPO_SAVE_QUERY

*&---------------------------------------------------------------------*
*&      Form  REPO_INIT
*&---------------------------------------------------------------------*
*       Initialize repository tree
*----------------------------------------------------------------------*
FORM repo_init.
  DATAlt_event TYPE cntl_simple_events,
        ls_event TYPE cntl_simple_event.

* Create a tree control
  CREATE OBJECT o_tree_repository
    EXPORTING
      parent              o_container_repository
      node_selection_mode cl_gui_simple_tree=>node_sel_mode_single
    EXCEPTIONS
      lifetime_error      1
      cntl_system_error   2
      create_error        3
      failed              4
      OTHERS              5.
  IF sy-subrc <> 0.
    MESSAGE a000(tree_control_msg).
  ENDIF.

* Catch double clic to open query
  ls_event-eventid cl_gui_simple_tree=>eventid_node_double_click.
  ls_event-appl_event abap_true" no PAI if event occurs
  APPEND ls_event TO lt_event.

* Catch context menu call
  ls_event-eventid cl_gui_simple_tree=>eventid_node_context_menu_req.
  ls_event-appl_event abap_true" no PAI if event occurs
  APPEND ls_event TO lt_event.

  CALL METHOD o_tree_repository->set_registered_events
    EXPORTING
      events                    lt_event
    EXCEPTIONS
      cntl_error                1
      cntl_system_error         2
      illegal_event_combination 3.
  IF sy-subrc <> 0.
    MESSAGE a000(tree_control_msg).
  ENDIF.

* Assign event handlers in the application class to each desired event
  SET HANDLER o_handle_event->hnd_repo_dblclick
      FOR o_tree_repository.
  SET HANDLER o_handle_event->hnd_repo_context_menu
      FOR o_tree_repository.
  SET HANDLER o_handle_event->hnd_repo_context_menu_sel
      FOR o_tree_repository.

  PERFORM repo_fill.

ENDFORM.                    " REPO_INIT

*&---------------------------------------------------------------------*
*&      Form  REPO_FILL
*&---------------------------------------------------------------------*
*       Fill repository tree with all allowed queries
*----------------------------------------------------------------------*
FORM repo_fill.
  DATA lw_usergroup TYPE usr02-class,
         BEGIN OF ls_query,
           queryid TYPE ztoad-queryid,
           aedat TYPE ztoad-aedat,
           visibility TYPE ztoad-visibility,
           text TYPE ztoad-text,
           query TYPE ztoad-query,
         END OF ls_query,
         lt_query_my LIKE TABLE OF ls_query,
         lt_query_shared LIKE TABLE OF ls_query,
         lw_node_key(6TYPE n,
         lw_queryid TYPE ztoad-queryid,
         lw_dummy(1TYPE c.                                "#EC NEEDED

* Get usergroup
  SELECT SINGLE class INTO lw_usergroup
         FROM usr02
         WHERE bname sy-uname.

* Get all my queries
  SELECT queryid aedat visibility text query INTO TABLE lt_query_my
         FROM ztoad
         WHERE owner sy-uname.

* Get all queries that i can use
  SELECT queryid aedat visibility text INTO TABLE lt_query_shared
         FROM ztoad
         WHERE owner NE sy-uname
         AND visibility c_visibility_all
               OR visibility c_visibility_shared
                    AND visibility_group lw_usergroup )
             ).
  REFRESH t_node_repository.

  CALL METHOD o_tree_repository->delete_all_nodes.

  CLEAR s_node_repository.
  s_node_repository-node_key c_nodekey_repo_my.
  s_node_repository-isfolder abap_true.
  s_node_repository-text 'My queries'(m16).
  APPEND s_node_repository TO t_node_repository.

  CLEAR lw_node_key.
  CONCATENATE sy-uname '+++' INTO lw_queryid.
  LOOP AT lt_query_my INTO ls_query WHERE queryid NP lw_queryid.
    lw_node_key lw_node_key + 1.
    CLEAR s_node_repository.
    s_node_repository-node_key lw_node_key.
    s_node_repository-relatkey c_nodekey_repo_my.
    s_node_repository-relatship cl_gui_simple_tree=>relat_last_child.
    IF ls_query-visibility c_visibility_my.
      s_node_repository-n_image s_node_repository-exp_image '@LC@'.
    ELSE.
      s_node_repository-n_image s_node_repository-exp_image '@L9@'.
    ENDIF.
    s_node_repository-text ls_query-text.
    s_node_repository-queryid ls_query-queryid.
    s_node_repository-edit abap_true.
    APPEND s_node_repository TO t_node_repository.
  ENDLOOP.

  CLEAR s_node_repository.
  s_node_repository-node_key c_nodekey_repo_shared.
  s_node_repository-isfolder abap_true.
  s_node_repository-text 'Shared queries'(m17).
  APPEND s_node_repository TO t_node_repository.

  LOOP AT lt_query_shared INTO ls_query.
    lw_node_key lw_node_key + 1.
    CLEAR s_node_repository.
    s_node_repository-node_key lw_node_key.
    s_node_repository-relatkey c_nodekey_repo_shared.
    s_node_repository-relatship cl_gui_simple_tree=>relat_last_child.
    s_node_repository-n_image s_node_repository-exp_image '@L9@'.
    s_node_repository-text ls_query-text.
    s_node_repository-queryid ls_query-queryid.
    s_node_repository-edit space.
    APPEND s_node_repository TO t_node_repository.
  ENDLOOP.

* Add history node
  CLEAR s_node_repository.
  s_node_repository-node_key c_nodekey_repo_history.
  s_node_repository-isfolder abap_true.
  s_node_repository-text 'History'(m18).
  APPEND s_node_repository TO t_node_repository.

  DELETE lt_query_my WHERE queryid NP lw_queryid.
  SORT lt_query_my BY aedat DESCENDING.
  LOOP AT lt_query_my INTO ls_query.
    lw_node_key lw_node_key + 1.
    CLEAR s_node_repository.
    s_node_repository-node_key lw_node_key.
    s_node_repository-relatkey c_nodekey_repo_history.
    s_node_repository-relatship cl_gui_simple_tree=>relat_last_child.
    s_node_repository-n_image s_node_repository-exp_image '@LC@'.
    s_node_repository-text ls_query-text.
    s_node_repository-queryid ls_query-queryid.
    s_node_repository-edit abap_true.
    IF ls_query-query(1'*'.
      SPLIT ls_query-query+1 AT cl_abap_char_utilities=>cr_lf
            INTO ls_query-query lw_dummy.
      CONCATENATE s_node_repository-text ':' ls_query-query
                  INTO s_node_repository-text SEPARATED BY space.
    ENDIF.
    APPEND s_node_repository TO t_node_repository.
  ENDLOOP.

  CALL METHOD o_tree_repository->add_nodes
    EXPORTING
      table_structure_name           'MTREESNODE'
      node_table                     t_node_repository
    EXCEPTIONS
      failed                         1
      error_in_node_table            2
      dp_error                       3
      table_structure_name_not_found 4
      OTHERS                         5.
  IF sy-subrc <> 0.
    MESSAGE a000(tree_control_msg).
  ENDIF.

* Exand all root nodes (my, shared, history)
  CALL METHOD o_tree_repository->expand_root_nodes.
ENDFORM.                    " REPO_FILL

*&---------------------------------------------------------------------*
*&      Form  REPO_SAVE_CURRENT_QUERY
*&---------------------------------------------------------------------*
*       Save query in the history area
*       Keep only 100 last queries
*----------------------------------------------------------------------*
FORM repo_save_current_query.
  DATA lt_query TYPE soli_tab,
         ls_query LIKE LINE OF lt_query,
         lw_query_with_cr TYPE string,
         ls_ztoad TYPE ztoad,
         lw_number(2TYPE n,
         lw_timestamp(14TYPE c,
         lw_dummy(1TYPE c,                                "#EC NEEDED
         lw_query_last TYPE string,
         lw_date(10TYPE c,
         lw_time(8TYPE c,
         lw_dummy_date TYPE timestamp.                      "#EC NEEDED

* Get content of abap edit box
  CALL METHOD o_textedit->get_text
    IMPORTING
      table  lt_query[]
    EXCEPTIONS
      OTHERS 1.

* Serialize query into a string
  CLEAR lw_query_with_cr.
  LOOP AT lt_query INTO ls_query.
    CONCATENATE lw_query_with_cr ls_query cl_abap_char_utilities=>cr_lf
                INTO lw_query_with_cr.
  ENDLOOP.

* Define timestamp
  lw_timestamp(8sy-datum.
  lw_timestamp+8 sy-uzeit.
  ls_ztoad-aedat lw_timestamp.

* Search if query is same as last loaded
  SELECT SINGLE query INTO lw_query_last
         FROM ztoad
         WHERE queryid w_last_loaded_query.
  IF sy-subrc AND lw_query_last lw_query_with_cr.
    RETURN.
  ENDIF.

* Get usergroup
  SELECT SINGLE class INTO ls_ztoad-visibility_group
         FROM usr02
         WHERE bname sy-uname.

  CLEAR lw_number.

* Get last query from history
  CONCATENATE sy-uname '#%' INTO ls_ztoad-queryid.
* aedat is not used but added in select for compatibility reason
  SELECT queryid aedat
         INTO (ls_ztoad-queryidlw_dummy_date)
         FROM ztoad
         UP TO ROWS
         WHERE queryid LIKE ls_ztoad-queryid
         AND owner sy-uname
         ORDER BY aedat DESCENDING.
  ENDSELECT.
  IF sy-subrc 0.
    SPLIT ls_ztoad-queryid AT '#' INTO lw_dummy lw_number.
  ENDIF.

  lw_number lw_number + 1.

* For history query, guid = <sy-uname>#NN
  CONCATENATE sy-uname '#' lw_number INTO ls_ztoad-queryid.
  ls_ztoad-owner sy-uname.
  ls_ztoad-visibility c_visibility_my.

* Define text for query as timestamp
  WRITE sy-datlo TO lw_date.
  WRITE sy-timlo TO lw_time.
  CONCATENATE lw_date lw_time INTO ls_ztoad-text SEPARATED BY space.

  ls_ztoad-query lw_query_with_cr.
  MODIFY ztoad FROM ls_ztoad.

  w_last_loaded_query ls_ztoad-queryid.

* Reset the modified status
  o_textedit->set_textmodified_status).

* Refresh repository
  PERFORM repo_fill.

* Focus on new query
  PERFORM repo_focus_query USING ls_ztoad-queryid.
ENDFORM.                    " REPO_SAVE_CURRENT_QUERY

*&---------------------------------------------------------------------*
*&      Form  QUERY_LOAD
*&---------------------------------------------------------------------*
*       Load query
*----------------------------------------------------------------------*
*      -->FW_QUERYID QueryID to load
*      <--FT_QUERY   Saved query
*----------------------------------------------------------------------*
FORM query_load USING fw_queryid TYPE ztoad-queryid
                CHANGING ft_query TYPE table.
  DATA lw_query_with_cr TYPE string.
  REFRESH ft_query.

  SELECT SINGLE query INTO lw_query_with_cr
         FROM ztoad
         WHERE queryid fw_queryid.
  IF sy-subrc 0.
    SPLIT lw_query_with_cr AT cl_abap_char_utilities=>cr_lf
                           INTO TABLE ft_query.
  ENDIF.
  w_last_loaded_query fw_queryid.
ENDFORM.                    " QUERY_LOAD

*&---------------------------------------------------------------------*
*&      Form  REPO_FOCUS_QUERY
*&---------------------------------------------------------------------*
*       Focus repository tree on a given queryid
*----------------------------------------------------------------------*
*      -->FW_QUERYID  ID of the query to focus
*----------------------------------------------------------------------*
FORM repo_focus_query USING fw_queryid TYPE ztoad-queryid.

  READ TABLE t_node_repository INTO s_node_repository
             WITH KEY queryid fw_queryid.
  IF sy-subrc NE 0.
    RETURN.
  ENDIF.

  CALL METHOD o_tree_repository->set_selected_node
    EXPORTING
      node_key s_node_repository-node_key.

ENDFORM.                    " FOCUS_REPOSITORY

*&---------------------------------------------------------------------*
*&      Form  RESULT_INIT
*&---------------------------------------------------------------------*
*       Initialize ALV grid
*----------------------------------------------------------------------*
FORM result_init.

* Create ALV
  CREATE OBJECT o_alv_result
    EXPORTING
      i_parent o_container_result.

* Register event toolbar to add button
  SET HANDLER o_handle_event->hnd_result_toolbar FOR o_alv_result.
  SET HANDLER o_handle_event->hnd_result_user_command FOR o_alv_result.

ENDFORM.                    " RESULT_INIT

*&---------------------------------------------------------------------*
*&      Form  SCREEN_INIT_LISTBOX_0200
*&---------------------------------------------------------------------*
*       Fill dropdown listbox with value on screen 200
*----------------------------------------------------------------------*
FORM screen_init_listbox_0200.
  TYPE-POOLS vrm.
  DATA lt_visibility TYPE vrm_values,
         ls_visibility LIKE LINE OF lt_visibility.

  REFRESH lt_visibility.

  ls_visibility-key c_visibility_my.
  ls_visibility-text 'Personal'(m19).
  APPEND ls_visibility TO lt_visibility.

  ls_visibility-key c_visibility_shared.
  ls_visibility-text 'User group'(m20).
  APPEND ls_visibility TO lt_visibility.

  ls_visibility-key c_visibility_all.
  ls_visibility-text 'All'(m21).
  APPEND ls_visibility TO lt_visibility.

  CALL FUNCTION 'VRM_SET_VALUES'
    EXPORTING
      id     'S_OPTIONS-VISIBILITY'
      values lt_visibility.

ENDFORM.                    " SCREEN_INIT_LISTBOX_0200

*&---------------------------------------------------------------------*
*&      Form  SCREEN_EXIT
*&---------------------------------------------------------------------*
*       Close the grid. If grid is closed, leave program
*       If sql text area is modified, ask confirmation before leave
*----------------------------------------------------------------------*
FORM screen_exit.
  DATA lw_status TYPE i,
         lw_answer(1TYPE c,
         lw_size TYPE i,
         lw_string TYPE string.

* Check if grid is displayed
  CALL METHOD o_splitter->get_row_height
    EXPORTING
      id     1
    IMPORTING
      result lw_size.
  CALL METHOD cl_gui_cfw=>flush.

* If grid is displayed, BACK action is only to close the grid
  IF lw_size < 100.
    CALL METHOD o_splitter->set_row_height
      EXPORTING
        id     1
        height 100.
    RETURN.
  ENDIF.

* Check if textedit is modified
  CALL METHOD o_textedit->get_textmodified_status
    IMPORTING
      status lw_status.
  IF lw_status NE 0.
    CONCATENATE 'Current query is not saved. Do you want'(m22)
'to exit without saving or save into history then exit ?'(m56)
                INTO lw_string SEPARATED BY space.
    CALL FUNCTION 'POPUP_TO_CONFIRM'
      EXPORTING
        text_question         lw_string
        text_button_1         'Exit'(m23)
        icon_button_1         '@2M@'
        text_button_2         'Save & exit'(m24)
        icon_button_2         '@2L@'
        default_button        '2'
        display_cancel_button space
      IMPORTING
        answer                lw_answer.
    IF lw_answer '2'.
      PERFORM repo_save_current_query.
    ENDIF.
  ENDIF.

  LEAVE TO SCREEN 0.
ENDFORM.                    " SCREEN_EXIT

*&---------------------------------------------------------------------*
*&      Form  SCREEN_DISPLAY_HELP
*&---------------------------------------------------------------------*
*       Display help for this program
*----------------------------------------------------------------------*
FORM screen_display_help.
  DATA l_report TYPE string,
         l_report_char1(1TYPE c,
         l_report_char3(3TYPE c,
         l_comment_found TYPE i,
         lt_report LIKE TABLE OF l_report,
         lt_lines TYPE rcl_bag_tline,
         ls_line LIKE LINE OF lt_lines,
         ls_help TYPE help_info,
         lt_exclude TYPE STANDARD TABLE OF string.

* Get program source code
  READ REPORT sy-repid INTO lt_report.

  ls_line-tdformat 'U1'.
  ls_line-tdline sy-title.
  APPEND ls_line TO lt_lines.

  ls_line-tdformat 'U3'.
  ls_line-tdline '&PURPOSE&'.
  APPEND ls_line TO lt_lines.

  LOOP AT lt_report INTO l_report.
    l_report_char1 l_report.
    CHECK l_report_char1 '*'.

* Keep only the second block of comment
* (first block is technical info, third is history)
    l_report_char3 l_report.
    IF l_report_char3 '*&-'.
      l_comment_found l_comment_found + 1.
      IF l_comment_found LE 2.
        CONTINUE.
      ELSE"l_comment_found > 2
        EXIT.
      ENDIF.
    ENDIF.
    IF l_comment_found 2.
      l_report l_report+1.
      l_report_char1 l_report.
      CASE l_report_char1.
        WHEN '='.
          ls_line-tdformat '='.
        WHEN '3'.
          ls_line-tdformat 'U3'.
        WHEN 'E'.
          ls_line-tdformat 'PE'.
        WHEN OTHERS.
          ls_line-tdformat '*'.
      ENDCASE.
      IF NOT l_report_char1 IS INITIAL.
        l_report l_report+1.
      ENDIF.
      IF l_report IS INITIAL.
        ls_line-tdformat 'LZ'.
      ENDIF.
      ls_line-tdline l_report.
      APPEND ls_line TO lt_lines.
    ENDIF.
  ENDLOOP.

  CALL FUNCTION 'HELP_DOCULINES_SHOW'
    EXPORTING
      help_infos ls_help
    TABLES
      excludefun lt_exclude
      helplines  lt_lines.

ENDFORM.                    " SCREEN_DISPLAY_HELP

*&---------------------------------------------------------------------*
*&      Form  QUERY_PARSE_NOSELECT
*&---------------------------------------------------------------------*
*       Check if query is a known SQL command and if user is allowed
*----------------------------------------------------------------------*
*      -->FW_QUERY   Query to check
*      <--FW_NOAUTH  Unallowed table or command entered
*      <--FW_COMMAND Command to execute (INSERT, DELETE, ...)
*      <--FW_TABLE   Target table of the query
*      <--FW_PARAM   Parameters for the command (WHERE, SET, ...)
*----------------------------------------------------------------------*
FORM query_parse_noselect  USING    fw_query TYPE string
                           CHANGING fw_noauth TYPE c
                                    fw_command TYPE string
                                    fw_table TYPE string
                                    fw_param TYPE string.
  DATA lw_query TYPE string,
         lw_table TYPE tabname.

  CLEAR fw_noauth,
          fw_table,
          fw_command,
          fw_param.

  lw_query fw_query.
  SPLIT lw_query AT space INTO fw_command lw_query.
  TRANSLATE fw_command TO UPPER CASE.
  CASE fw_command.
    WHEN 'INSERT'.
      SPLIT lw_query AT space INTO fw_table fw_param.
      TRANSLATE fw_table TO UPPER CASE.
      CLEAR sy-subrc.
      IF s_customize-auth_object NE space.
        lw_table fw_table.
        AUTHORITY-CHECK OBJECT s_customize-auth_object
                 ID 'TABLE' FIELD lw_table
                 ID 'ACTVT' FIELD s_customize-actvt_insert.
      ELSEIF s_customize-auth_insert NE '*'
      AND fw_table NP s_customize-auth_insert.
        sy-subrc 4.
      ENDIF.
      IF sy-subrc NE 0.
        CONCATENATE 'No authorisation for table'(m13fw_table
                    INTO lw_query SEPARATED BY space.
        MESSAGE lw_query TYPE c_msg_success DISPLAY LIKE c_msg_error.
        fw_noauth abap_true.
        RETURN.
      ENDIF.

    WHEN 'UPDATE'.
      SPLIT lw_query AT space INTO fw_table fw_param.
      TRANSLATE fw_table TO UPPER CASE.
      CLEAR sy-subrc.
      IF s_customize-auth_object NE space.
        lw_table fw_table.
        AUTHORITY-CHECK OBJECT s_customize-auth_object
                 ID 'TABLE' FIELD lw_table
                 ID 'ACTVT' FIELD s_customize-actvt_update.
      ELSEIF s_customize-auth_update NE '*'
      AND fw_table NP s_customize-auth_update.
        sy-subrc 4.
      ENDIF.
      IF sy-subrc NE 0.
        CONCATENATE 'No authorisation for table'(m13fw_table
                    INTO lw_query SEPARATED BY space.
        MESSAGE lw_query TYPE c_msg_success DISPLAY LIKE c_msg_error.
        fw_noauth abap_true.
        RETURN.
      ENDIF.

    WHEN 'DELETE'.
      SPLIT lw_query AT space INTO fw_table fw_param.
      TRANSLATE fw_table TO UPPER CASE.
      IF fw_table 'FROM'.
        SPLIT fw_param AT space INTO fw_table fw_param.
        TRANSLATE fw_table TO UPPER CASE.
      ENDIF.
      CLEAR sy-subrc.
      IF s_customize-auth_object NE space.
        lw_table fw_table.
        AUTHORITY-CHECK OBJECT s_customize-auth_object
                 ID 'TABLE' FIELD lw_table
                 ID 'ACTVT' FIELD s_customize-actvt_delete.
      ELSEIF s_customize-auth_delete NE '*'
      AND NOT fw_table CP s_customize-auth_delete.
        sy-subrc 4.
      ENDIF.
      IF sy-subrc NE 0.
        CONCATENATE 'No authorisation for table'(m13fw_table
                    INTO lw_query SEPARATED BY space.
        MESSAGE lw_query TYPE c_msg_success DISPLAY LIKE c_msg_error.
        fw_noauth abap_true.
        RETURN.
      ENDIF.

    WHEN c_native_command.
      IF s_customize-auth_object NE space.
        AUTHORITY-CHECK OBJECT s_customize-auth_object
                 ID 'ACTVT' FIELD s_customize-actvt_native.
      ELSEIF s_customize-auth_native NE abap_true.
        sy-subrc 4.
      ENDIF.
      IF sy-subrc NE 0.
        CONCATENATE 'SQL command not allowed :'(m25fw_command
                    INTO lw_query.
        MESSAGE lw_query TYPE c_msg_success DISPLAY LIKE c_msg_error.
        fw_noauth abap_true.
        RETURN.
      ENDIF.
* For native command, replace ' by "
      TRANSLATE lw_query USING '''"'.
      fw_param lw_query.

    WHEN OTHERS.
      CONCATENATE 'SQL command not allowed :'(m25fw_command
                  INTO lw_query.
      MESSAGE lw_query TYPE c_msg_success DISPLAY LIKE c_msg_error.
      fw_noauth abap_true.
      RETURN.
  ENDCASE.
ENDFORM.                    " QUERY_PARSE_NOSELECT

*&---------------------------------------------------------------------*
*&      Form  QUERY_GENERATE_NOSELECT
*&---------------------------------------------------------------------*
*       Create all other than SELECT SQL query in a new generated
*       temp program
*----------------------------------------------------------------------*
*      -->FW_COMMAND Query type
*      -->FW_TABLE   Target table of the query
*      -->FW_PARAM   Parameters of the query
*      -->FW_DISPLAY   Display code instead of generated routine
*      <--FW_PROGRAM Name of the generated program
*----------------------------------------------------------------------*
FORM query_generate_noselect  USING    fw_command TYPE string
                                       fw_table TYPE string
                                       fw_param TYPE string
                                       fw_display TYPE c
                              CHANGING fw_program TYPE sy-repid.

  DATA lt_code_string TYPE TABLE OF string,
         lw_mess(255),
         lw_line TYPE i,
         lw_word(30),
         lw_strlen_string TYPE string,
         lw_explicit TYPE string,
         lw_length TYPE i,
         lw_pos TYPE i,
         lw_fieldnum TYPE i,
         lw_fieldval TYPE string,
         lw_fieldname TYPE string,
         lw_wait_name(1TYPE c,
         lw_char(1TYPE c,
         lw_started(1TYPE c,
         lw_started_field(1TYPE c.

  DEFINE c.
    lw_strlen_string &1.
    perform add_line_to_table using lw_strlen_string
                              changing lt_code_string.
  END-OF-DEFINITION.

* Write Header
  'PROGRAM SUBPOOL.'.                                     "#EC NOTEXT
  '** GENERATED PROGRAM * DO NOT CHANGE IT **'.           "#EC NOTEXT
  'type-pools: slis.'.                                    "#EC NOTEXT
  'DATA : w_timestart type timestampl,'.                  "#EC NOTEXT
  '       w_timeend type timestampl.'.                    "#EC NOTEXT
  ''.
  IF fw_command 'INSERT'.
    'DATA s_insert type'.                                 "#EC NOTEXT
    fw_table.
    '.'.                                                  "#EC NOTEXT
    'FIELD-SYMBOLS <fs> TYPE ANY.'.                       "#EC NOTEXT
    '.'.                                                  "#EC NOTEXT
  ENDIF.

* Write the dynamic subroutine that run the SELECT
  'FORM run_sql CHANGING fo_result TYPE REF TO data'.     "#EC NOTEXT
  '                      fw_time TYPE p'.                 "#EC NOTEXT
  '                      fw_count TYPE i.'.               "#EC NOTEXT
  '***************************************'.              "#EC NOTEXT
  '*            Begin of query           *'.              "#EC NOTEXT
  '***************************************'.              "#EC NOTEXT
  'CLEAR fw_count.'.                                      "#EC NOTEXT
  'GET TIME STAMP FIELD w_timestart.'.                    "#EC NOTEXT

  CASE fw_command.
    WHEN 'UPDATE'.
      fw_command.
      fw_table.
      fw_param.
      '.'.
    WHEN 'DELETE'.
      fw_command.
      'FROM'.                                             "#EC NOTEXT
      fw_table.
      fw_param.
      '.'.
    WHEN 'INSERT'.

      IF fw_param(6'VALUES'.
        lw_length strlenfw_param ).
        lw_pos 6.
        lw_fieldnum 0.
        WHILE lw_pos < lw_length.
          lw_char fw_param+lw_pos(1).
          lw_pos lw_pos + 1.
          IF lw_started space.
            IF lw_char NE '('"begin of the list
              CONTINUE.
            ENDIF.
            lw_started abap_true.
            CONTINUE.
          ENDIF.
          IF lw_started_field space.
            IF lw_char ')'"end of the list
              EXIT"exit while
            ENDIF.

            IF lw_char NE ''''"field value must start by '
              CONTINUE.
            ENDIF.
            lw_started_field abap_true.
            lw_fieldval lw_char.
            lw_fieldnum lw_fieldnum + 1.
            CONTINUE.
          ENDIF.
          IF lw_char space.
            CONCATENATE lw_fieldval lw_char INTO lw_fieldval
                        SEPARATED BY space.
          ELSE.
            CONCATENATE lw_fieldval lw_char INTO lw_fieldval.
          ENDIF.
          IF lw_char ''''"end of a field ?
            IF lw_pos < lw_length.
              lw_char fw_param+lw_pos(1).
            ELSE.
              CLEAR lw_char.
            ENDIF.
            IF lw_char ''''"not end !
              CONCATENATE lw_fieldval lw_char INTO lw_fieldval.
              lw_pos lw_pos + 1.
              CONTINUE.
            ELSE"end of a field!
              'ASSIGN COMPONENT'.                         "#EC NOTEXT
              lw_fieldnum.
              'OF STRUCTURE s_insert TO <fs>.'.           "#EC NOTEXT
              '<fs> = '.                                  "#EC NOTEXT
              lw_fieldval.
              '.'.                                        "#EC NOTEXT
              lw_started_field space.
            ENDIF.
          ENDIF.
        ENDWHILE.
      ELSEIF fw_param(3'SET'.


        lw_length strlenfw_param ).
        lw_pos 3.
        lw_fieldnum 0.
        lw_wait_name abap_true.
        WHILE lw_pos < lw_length.
          lw_char fw_param+lw_pos(1).
          lw_pos lw_pos + 1.
          IF lw_wait_name abap_true.
            TRANSLATE lw_char TO UPPER CASE.
            IF lw_char space OR NOT sy-abcde CS lw_char.
              CONTINUE"not a begin of fieldname
            ENDIF.
            lw_wait_name space.
            lw_started abap_true.
            CONCATENATE 's_insert-' lw_char
                        INTO lw_fieldname.                  "#EC NOTEXT
            CONTINUE.
          ENDIF.

          IF lw_started abap_true.
            IF lw_char space.
              CONCATENATE lw_fieldname lw_char INTO lw_fieldname
                          SEPARATED BY space.
            ELSE.
              CONCATENATE lw_fieldname lw_char INTO lw_fieldname.
            ENDIF.
            IF lw_char '='"end of the field name
              lw_started space.
            ENDIF.

            CONTINUE.
          ENDIF.

          IF lw_started_field NE abap_true.
            IF lw_char NE ''''"field value must start by '
              CONTINUE.
            ENDIF.
            lw_started_field abap_true.
            lw_fieldval lw_char.
            CONTINUE.
          ENDIF.

          IF lw_char space.
            CONCATENATE lw_fieldval lw_char INTO lw_fieldval
                        SEPARATED BY space.
          ELSE.
            CONCATENATE lw_fieldval lw_char INTO lw_fieldval.
          ENDIF.
          IF lw_char ''''"end of a field ?
            IF lw_pos < lw_length.
              lw_char fw_param+lw_pos(1).
            ELSE.
              CLEAR lw_char.
            ENDIF.
            IF lw_char ''''"not end !
              CONCATENATE lw_fieldval lw_char INTO lw_fieldval.
              lw_pos lw_pos + 1.
              CONTINUE.
            ELSE"end of a field!
              lw_fieldname.
              lw_fieldval.
              '.'.
              lw_started_field space.
              lw_wait_name abap_true.
            ENDIF.
          ENDIF.
        ENDWHILE.
      ELSE.
        MESSAGE 'Error in INSERT syntax : VALUES / SET required'(m26)
                TYPE c_msg_error.
      ENDIF"if fw_param(6) = 'VALUES'.
      fw_command.
      'INTO'.                                             "#EC NOTEXT
      fw_table.
      'VALUES s_insert.'.                                 "#EC NOTEXT
  ENDCASE.

* Get query execution time & affected lines
  'IF sy-subrc = 0.'.                                     "#EC NOTEXT
  '  fw_count = sy-dbcnt.'.                               "#EC NOTEXT
  'ENDIF.'.                                               "#EC NOTEXT
  'GET TIME STAMP FIELD w_timeend.'.                      "#EC NOTEXT
  'fw_time = w_timeend - w_timestart.'.                   "#EC NOTEXT
  'ENDFORM.'.                                             "#EC NOTEXT

  CLEAR lw_line,
          lw_word,
          lw_mess.
  SYNTAX-CHECK FOR lt_code_string PROGRAM sy-repid
               MESSAGE lw_mess LINE lw_line WORD lw_word.
  IF sy-subrc NE AND fw_display space.
    MESSAGE lw_mess TYPE c_msg_error.
  ENDIF.

  IF fw_display space.
    GENERATE SUBROUTINE POOL lt_code_string NAME fw_program.
  ELSE.
    IF lw_mess IS NOT INITIAL.
      lw_explicit lw_line.
      CONCATENATE lw_mess '(line'(m28lw_explicit ',word'(m29)
                  lw_word ')'(m30)
                  INTO lw_mess SEPARATED BY space.
      MESSAGE lw_mess TYPE c_msg_success DISPLAY LIKE c_msg_error.
    ENDIF.
    EDITOR-CALL FOR lt_code_string DISPLAY-MODE
                TITLE 'Generated code for current query'(t01).
  ENDIF.
ENDFORM.                    " QUERY_GENERATE_NOSELECT

*&---------------------------------------------------------------------*
*&      Form  DDIC_GET_FIELD_FROM_NODE
*&---------------------------------------------------------------------*
*       Get text for a DDIC node
*       Format of the text : tablename~fieldname
*----------------------------------------------------------------------*
*      -->FW_NODE_KEY   DDIC node key
*      -->FW_RELAT_KEY  DDIC parent node key
*      -->FW_TEXT       Text
*----------------------------------------------------------------------*
FORM ddic_get_field_from_node  USING    fw_node_key TYPE tv_nodekey
                                        fw_relat_key TYPE tv_nodekey
                               CHANGING fw_text TYPE string.
  DATA ls_item LIKE LINE OF t_item_ddic,
         ls_item_parent LIKE LINE OF t_item_ddic,
         lw_table TYPE string,
         lw_alias TYPE string.

* Get field name
  READ TABLE t_item_ddic INTO ls_item
             WITH KEY node_key fw_node_key
                      item_name c_ddic_col1.

* Get table name
  READ TABLE t_item_ddic INTO ls_item_parent
             WITH KEY node_key fw_relat_key
                      item_name c_ddic_col1.

* Search for alias
  SPLIT ls_item_parent-text AT ' AS ' INTO lw_table lw_alias.
  IF NOT lw_alias IS INITIAL.
    lw_table lw_alias.
  ENDIF.

* Build tablename~fieldname
  CONCATENATE lw_table '~' ls_item-text INTO fw_text.
  CONCATENATE space fw_text space INTO fw_text RESPECTING BLANKS.

ENDFORM.                    " DDIC_GET_FIELD_FROM_NODE

*&---------------------------------------------------------------------*
*&      Form  EDITOR_PASTE
*&---------------------------------------------------------------------*
*       Paste given text to SQL editor at given position
*----------------------------------------------------------------------*
*      -->FW_TEXT Text to paste in editor
*      -->FW_LINE Line in editor to paste
*      -->FW_POS  Position in the line in editor
*----------------------------------------------------------------------*
FORM editor_paste  USING fw_text TYPE string
                         fw_line TYPE i
                         fw_pos TYPE i.
  DATA lt_text TYPE TABLE OF string,
         lw_pos TYPE i,
         lw_line TYPE i,
         lw_message TYPE string.

*   Set text with new line
  APPEND fw_text TO lt_text.
  IF s_customize-paste_break abap_true.
    lw_pos fw_pos 1.
    CLEAR lw_message.
    DO lw_pos TIMES.
      CONCATENATE lw_message space INTO lw_message RESPECTING BLANKS.
    ENDDO.
    APPEND lw_message TO lt_text.
  ENDIF.

  CALL METHOD o_textedit->insert_block_at_position
    EXPORTING
      line     fw_line
      pos      fw_pos
      text_tab lt_text
    EXCEPTIONS
      OTHERS   0.

* Set cursor at end of pasted field
  IF s_customize-paste_break abap_true.
    lw_pos fw_pos.
    lw_line fw_line + 1.
  ELSE.
    lw_pos strlenfw_text ).
    lw_pos lw_pos + fw_pos.
    lw_line fw_line.
  ENDIF.

  CALL METHOD o_textedit->set_selection_pos_in_line
    EXPORTING
      line   lw_line
      pos    lw_pos
    EXCEPTIONS
      OTHERS 0.

* Focus on editor
  CALL METHOD cl_gui_control=>set_focus
    EXPORTING
      control o_textedit
    EXCEPTIONS
      OTHERS  0.

  CONCATENATE fw_text 'pasted to SQL Editor'(m27)
              INTO lw_message SEPARATED BY space.
  MESSAGE lw_message TYPE c_msg_success.
ENDFORM.                    " EDITOR_PASTE

*&---------------------------------------------------------------------*
*&      Form  QUERY_PROCESS_NATIVE
*&---------------------------------------------------------------------*
*       Execute a given native sql command
*----------------------------------------------------------------------*
*      -->FW_COMMAND Native SQL Command to execute
*----------------------------------------------------------------------*
FORM query_process_native USING fw_command TYPE string.
  DATA lw_lines TYPE i,
         lw_sql_code TYPE i,
         lw_sql_msg(255TYPE c,
         lw_row_num TYPE i,
         lw_command(255TYPE c,
         lw_msg TYPE string,
         lw_timestart TYPE timestampl,
         lw_timeend TYPE timestampl,
         lw_time TYPE p LENGTH DECIMALS 2,
         lw_charnumb(12TYPE c,
         lw_answer(1TYPE c.

* Have a user confirmation before execute Native SQL Command
  CONCATENATE 'Are you sure you want to do a'(m31fw_command
              '?'(m33)
              INTO lw_msg SEPARATED BY space.
  CALL FUNCTION 'POPUP_TO_CONFIRM'
    EXPORTING
      titlebar              'Warning : critical operation'(t04)
      text_question         lw_msg
      default_button        '2'
      display_cancel_button space
    IMPORTING
      answer                lw_answer
    EXCEPTIONS
      text_not_found        1
      OTHERS                2.
  IF sy-subrc NE OR lw_answer NE '1'.
    RETURN.
  ENDIF.

  lw_command fw_command.
  lw_lines strlenlw_command ).
  GET TIME STAMP FIELD lw_timestart.
  CALL 'C_DB_EXECUTE'
       ID 'STATLEN' FIELD lw_lines
       ID 'STATTXT' FIELD lw_command
       ID 'SQLERR'  FIELD lw_sql_code
       ID 'ERRTXT'  FIELD lw_sql_msg
       ID 'ROWNUM'  FIELD lw_row_num.
  IF sy-subrc NE 0.
    MESSAGE lw_sql_msg TYPE c_msg_success DISPLAY LIKE c_msg_error.
    RETURN.
  ELSE.
    GET TIME STAMP FIELD lw_timeend.
    lw_time lw_timeend lw_timestart.
    lw_charnumb lw_time.
    CONCATENATE 'Query executed in'(m09lw_charnumb 'seconds.'(m10)
                INTO lw_msg SEPARATED BY space.
    CONDENSE lw_msg.
    MESSAGE lw_msg TYPE c_msg_success.
  ENDIF.
ENDFORM.                    " QUERY_PROCESS_NATIVE

*&---------------------------------------------------------------------*
*&      Form  ddic_add_tree_zspro
*&---------------------------------------------------------------------*
*       Add nodes from table ZSPRO
*       You can delete this form if not use ZSPRO or dont have a table
*       hierarchy in ZSPRO
*----------------------------------------------------------------------*
FORM ddic_add_tree_zspro.
  DATA lo_zspro TYPE REF TO data,
         ls_node LIKE LINE OF t_node_ddic,
         ls_item LIKE LINE OF t_item_ddic,
         lw_nodekey TYPE tv_nodekey,
         BEGIN OF ls_ddic_fields,
           tabname TYPE dd03l-tabname,
           fieldname TYPE dd03l-fieldname,
           position TYPE dd03l-position,
           keyflag TYPE dd03l-keyflag,
           ddtext1 TYPE dd03t-ddtext,
           ddtext2 TYPE dd04t-ddtext,
         END OF ls_ddic_fields,
         lt_ddic_fields LIKE TABLE OF ls_ddic_fields,
         lw_node_number(11TYPE n,
         lw_found(1TYPE c.
  CONSTANTS lc_zspro(30TYPE VALUE 'ZSPRO'.
  FIELD-SYMBOLS <ft_zspro> TYPE table,
                  <fs_zspro> TYPE any,
                  <fw_zspro> TYPE any.

* Try to create zspro internal table
  TRY.
      CREATE DATA lo_zspro TYPE TABLE OF (lc_zspro).
    CATCH cx_sy_create_data_error.
* If ZSPRO does not exist, leave the subroutine
      RETURN.
  ENDTRY.
  ASSIGN lo_zspro->TO <ft_zspro>.

* Get all data from ZSPRO (node or table entry)
  SELECT FROM (lc_zspro)
           INTO TABLE <ft_zspro>
           WHERE nodetype 0
           OR nodetype 1
           OR nodetype space
           ORDER BY relatkey sort.
* If ZSPRO does not contain any valuable data, leave the subroutine
  IF sy-subrc NE 0.
    RETURN.
  ENDIF.

* Get field list for each table
  LOOP AT <ft_zspro> ASSIGNING <fs_zspro>.
    ASSIGN COMPONENT 'NODETYPE' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
    IF sy-subrc NE OR <fw_zspro> NE 1.
      CONTINUE.
    ENDIF.
    ASSIGN COMPONENT 'NODEPARAM' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
    IF sy-subrc 0.
      ls_ddic_fields-tabname <fw_zspro>.
      APPEND ls_ddic_fields TO lt_ddic_fields.
    ENDIF.
  ENDLOOP.
  IF NOT lt_ddic_fields IS INITIAL.
    SELECT dd03l~tabname dd03l~fieldname dd03l~position
           dd03l~keyflag dd03t~ddtext dd04t~ddtext
           INTO TABLE lt_ddic_fields
           FROM dd03l
           LEFT OUTER JOIN dd03t
           ON dd03l~tabname dd03t~tabname
           AND dd03l~fieldname dd03t~fieldname
           AND dd03l~as4local dd03t~as4local
           AND dd03t~ddlanguage sy-langu
           LEFT OUTER JOIN dd04t
           ON dd03l~rollname dd04t~rollname
           AND dd03l~as4local dd04t~as4local
           AND dd04t~ddlanguage sy-langu
           FOR ALL ENTRIES IN lt_ddic_fields
           WHERE dd03l~tabname lt_ddic_fields-tabname
           AND dd03l~as4local c_vers_active
           AND dd03l~as4vers space
           AND dd03l~comptype c_ddic_dtelm
           OR    dd03l~comptype space ).
    SORT lt_ddic_fields BY tabname keyflag DESCENDING position.
    DELETE ADJACENT DUPLICATES FROM lt_ddic_fields
           COMPARING tabname fieldname.
  ENDIF.

  CLEAR ls_node.
  ls_node-node_key 'ZSPRO'.
  ls_node-isfolder abap_true.
  ls_node-expander abap_true.
  APPEND ls_node TO t_node_zspro.

  CLEAR ls_item.
  ls_item-node_key 'ZSPRO'.
  ls_item-class cl_gui_column_tree=>item_class_text.
  ls_item-item_name c_ddic_col1.
  ls_item-text 'ZSPRO'.
  APPEND ls_item TO t_item_zspro.

  ls_item-item_name c_ddic_col2.
  ls_item-text space.
  APPEND ls_item TO t_item_zspro.

  LOOP AT <ft_zspro> ASSIGNING <fs_zspro>.
    ASSIGN COMPONENT 'NODE_KEY' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
    CONCATENATE 'Z' <fw_zspro>+1 INTO lw_nodekey.
    CLEAR ls_node.
    ls_node-node_key lw_nodekey.

    ASSIGN COMPONENT 'RELATKEY' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
    IF <fw_zspro> IS INITIAL.
      ls_node-relatkey 'ZSPRO'.
    ELSE.
      CONCATENATE 'Z' <fw_zspro>+1 INTO ls_node-relatkey.
    ENDIF.
    ls_node-isfolder abap_true.

    ASSIGN COMPONENT 'NODETYPE' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
    IF <fw_zspro> 1"table entry
      ls_node-n_image '@PO@'.
      ls_node-exp_image '@PO@'.
    ENDIF.
    ls_node-expander abap_true.
    APPEND ls_node TO t_node_zspro.

    CLEAR ls_item.
    ls_item-node_key lw_nodekey.
    ls_item-class cl_gui_column_tree=>item_class_text.
    ls_item-item_name c_ddic_col1.
    IF <fw_zspro> 1"table entry
      ASSIGN COMPONENT 'NODEPARAM' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
      ls_item-text <fw_zspro>.
    ELSE.
      ASSIGN COMPONENT 'TEXT' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
      ls_item-text <fw_zspro>.
    ENDIF.
    APPEND ls_item TO t_item_zspro.

    ls_item-item_name c_ddic_col2.
    ASSIGN COMPONENT 'NODETYPE' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
    IF <fw_zspro> 1"table entry
      ASSIGN COMPONENT 'TEXT' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
      ls_item-text <fw_zspro>.
    ELSE.
      ls_item-text space.
    ENDIF.
    APPEND ls_item TO t_item_zspro.

* For each table entry, add all fields
    ASSIGN COMPONENT 'NODETYPE' OF STRUCTURE <fs_zspro> TO <fw_zspro>.
    IF <fw_zspro> 1.
      ASSIGN COMPONENT 'NODEPARAM' OF STRUCTURE <fs_zspro>
                                   TO <fw_zspro>.
      LOOP AT lt_ddic_fields INTO ls_ddic_fields
                             WHERE tabname <fw_zspro>.
        CLEAR ls_node.
        lw_node_number lw_node_number + 1.
        CONCATENATE 'F' lw_node_number INTO ls_node-node_key.
        ls_node-relatkey lw_nodekey.
        ls_node-relatship cl_gui_column_tree=>relat_last_child.
        IF ls_ddic_fields-keyflag space.
          ls_node-n_image '@3W@'.
          ls_node-exp_image '@3W@'.
        ELSE.
          ls_node-n_image '@3V@'.
          ls_node-exp_image '@3V@'.
        ENDIF.
        ls_node-dragdropid w_dragdrop_handle_tree.
        APPEND ls_node TO t_node_zspro.

        CLEAR ls_item.
        ls_item-node_key ls_node-node_key.
        ls_item-class cl_gui_column_tree=>item_class_text.
        ls_item-item_name c_ddic_col1.
        ls_item-text ls_ddic_fields-fieldname.
        APPEND ls_item TO t_item_zspro.
        ls_item-item_name c_ddic_col2.
        IF NOT ls_ddic_fields-ddtext1 IS INITIAL.
          ls_item-text ls_ddic_fields-ddtext1.
        ELSE.
          ls_item-text ls_ddic_fields-ddtext2.
        ENDIF.
        APPEND ls_item TO t_item_zspro.
      ENDLOOP.
    ENDIF.
  ENDLOOP.

* Clean Empty nodes
  DO.
    lw_found space.
    LOOP AT t_node_zspro INTO ls_node WHERE isfolder abap_true.
      READ TABLE t_node_zspro WITH KEY relatkey ls_node-node_key
                 TRANSPORTING NO FIELDS.
      IF sy-subrc NE 0.
        lw_found abap_true.
        DELETE t_node_zspro.
        DELETE t_item_zspro WHERE node_key ls_node-node_key.
      ENDIF.
    ENDLOOP.
    IF lw_found space.
      EXIT.
    ENDIF.
  ENDDO.
ENDFORM.                    "ddic_add_tree_zspro

*&---------------------------------------------------------------------*
*&      Form  REPO_DELETE_HISTORY
*&---------------------------------------------------------------------*
*       Delete given history entry
*----------------------------------------------------------------------*
*      -->FW_NODE_KEY Node key of history to delete
*      <--FW_SUBRC    Return code
*----------------------------------------------------------------------*
FORM repo_delete_history USING fw_node_key TYPE tv_nodekey
                         CHANGING fw_subrc TYPE i.
  DATA ls_histo LIKE s_node_repository.

  READ TABLE t_node_repository INTO ls_histo
             WITH KEY node_key fw_node_key.
  IF sy-subrc AND ls_histo-edit NE space.
    DELETE FROM ztoad WHERE queryid ls_histo-queryid.
    IF sy-subrc 0.
      CALL METHOD o_tree_repository->delete_node
        EXPORTING
          node_key fw_node_key.
    ENDIF.
  ENDIF.
  fw_subrc sy-subrc.
ENDFORM.                    " REPO_DELETE_HISTORY

*&---------------------------------------------------------------------*
*&      Form  options_load
*&---------------------------------------------------------------------*
*       Get saved options from user parameters table
*----------------------------------------------------------------------*
FORM options_load.
  DATA lw_options TYPE usr05-parva,
         lw_rows(10TYPE c.
  GET PARAMETER ID 'ZTOAD' FIELD lw_options.
  IF sy-subrc 0.
    SPLIT lw_options AT ';' INTO lw_rows
                                 s_customize-paste_break
                                 s_customize-techname
                                 lw_options"dummy
    s_customize-default_rows lw_rows.
  ENDIF.
ENDFORM.                    " options_load

*&---------------------------------------------------------------------*
*&      Form  options_save
*&---------------------------------------------------------------------*
*       Save user options in standard user parameters table
*----------------------------------------------------------------------*
FORM options_save.
  DATA lw_options TYPE usr05-parva,
         lw_rows(10TYPE c.

  lw_rows =   s_customize-default_rows.
  CONDENSE lw_rows NO-GAPS.
  CONCATENATE lw_rows
              s_customize-paste_break
              s_customize-techname
              INTO lw_options
              SEPARATED BY ';'.

  CALL FUNCTION 'SMAN_SET_USER_PARAMETER'
    EXPORTING
      parameter_id    'ZTOAD'
      parameter_value lw_options
    EXCEPTIONS
      OTHERS          2.
  IF sy-subrc <> 0.
    MESSAGE e082(s1)"Error saving parameter changes
  ENDIF.

ENDFORM.                    "options_save

*&---------------------------------------------------------------------*
*&      Form  DDIC_REFRESH_TREE
*&---------------------------------------------------------------------*
*       Refresh DDIC tree with current query
*----------------------------------------------------------------------*
FORM ddic_refresh_tree.
  DATA lw_query TYPE string,
         lw_query2 TYPE string,
         lw_select TYPE string,
         lw_from TYPE string,
         lw_from2 TYPE string,
         lw_where TYPE string,
         lw_union TYPE string,
         lw_rows(6TYPE n,
         lw_noauth(1TYPE c,
         lw_newsyntax(1TYPE c,
         lw_error(1TYPE c.

* Get only usefull code for current query
  PERFORM editor_get_query USING space CHANGING lw_query.

* Parse Query
  PERFORM query_parse USING lw_query
                      CHANGING lw_select lw_from lw_where
                               lw_union lw_rows lw_noauth
                               lw_newsyntax lw_error.

  IF lw_noauth NE space OR lw_error NE space.
    RETURN.
  ELSEIF lw_select IS INITIAL.
    PERFORM query_parse_noselect USING lw_query
                                 CHANGING lw_noauth lw_select
                                          lw_from lw_where.
    IF lw_noauth NE space OR lw_select c_native_command.
      RETURN.
    ENDIF.
  ENDIF.
* Manage unioned queries
  WHILE NOT lw_union IS INITIAL.
* Parse Query
    lw_query2 lw_union.
    PERFORM query_parse USING lw_query2
                        CHANGING lw_select lw_from2 lw_where
                                 lw_union lw_rows lw_noauth
                                 lw_newsyntax lw_error.
    IF NOT lw_from2 IS INITIAL.
      CONCATENATE lw_from 'JOIN' lw_from2
                  INTO lw_from SEPARATED BY space.
    ENDIF.
    IF lw_noauth NE space OR lw_error NE space.
      RETURN.
    ENDIF.
  ENDWHILE.

* Refresh ddic tree with list of table/fields of the actual query
  PERFORM ddic_set_tree USING lw_from.
ENDFORM.                    " DDIC_REFRESH_TREE

*&---------------------------------------------------------------------*
*&      Form  DDIC_FIND_IN_TREE
*&---------------------------------------------------------------------*
*       Display popup to search a table in DDIC tree
*----------------------------------------------------------------------*
FORM ddic_find_in_tree.
  DATA ls_sval TYPE sval,
         lt_sval LIKE TABLE OF ls_sval,
         lw_returncode TYPE c,
         lw_search TYPE string,
         lt_search LIKE TABLE OF lw_search,
         ls_item_ddic LIKE LINE OF t_item_ddic,
         lw_search_term TYPE string,
         lw_search_line TYPE i,
         lw_rest TYPE i,
         lw_node_key TYPE tv_nodekey,
         lt_nodekey TYPE TABLE OF tv_nodekey.

* Build search table
  REFRESH lt_search.
  LOOP AT t_item_ddic INTO ls_item_ddic.
    lw_search ls_item_ddic-text.
    APPEND lw_search TO lt_search.
    APPEND ls_item_ddic-node_key TO lt_nodekey.
  ENDLOOP.

* Ask for selection search
  ls_sval-tabname 'RSDXX'.
  ls_sval-fieldname 'FINDSTR'.
  ls_sval-value space.
  APPEND ls_sval TO lt_sval.
  DO.
    CALL FUNCTION 'POPUP_GET_VALUES'
      EXPORTING
        popup_title     space
      IMPORTING
        returncode      lw_returncode
      TABLES
        fields          lt_sval
      EXCEPTIONS
        error_in_fields 1
        OTHERS          2.
    IF sy-subrc NE OR lw_returncode NE space.
      EXIT"exit do
    ENDIF.
    READ TABLE lt_sval INTO ls_sval INDEX 1.
    IF ls_sval-value space.
      EXIT"exit do
    ENDIF.

* For new search, start from line 1
    IF lw_search_term NE ls_sval-value.
      lw_search_term ls_sval-value.
      lw_search_line 1.
* For next result of same search, start from next line
    ELSE.
      lw_rest lw_search_line MOD 2.
      lw_search_line lw_search_line + + lw_rest.
    ENDIF.

    FIND FIRST OCCURRENCE OF ls_sval-value IN TABLE lt_search
         FROM lw_search_line
         IN CHARACTER MODE IGNORING CASE
         MATCH LINE lw_search_line.

* Search string &1 not found
    IF sy-subrc NE AND lw_search_line 1.
      MESSAGE s065(0kWITH lw_search_term DISPLAY LIKE c_msg_error.
      CLEAR lw_search_line.
      CLEAR lw_search_term.

* Last selected entry reached
    ELSEIF sy-subrc NE 0.
      MESSAGE s066(0kDISPLAY LIKE c_msg_error.
      CLEAR lw_search_line.
      CLEAR lw_search_term.

* Found
    ELSE.
      MESSAGE 'String found'(m04TYPE c_msg_success.
      READ TABLE lt_nodekey INTO lw_node_key INDEX lw_search_line.
      CALL METHOD o_tree_ddic->set_selected_node
        EXPORTING
          node_key lw_node_key.
      CALL METHOD o_tree_ddic->ensure_visible
        EXPORTING
          node_key lw_node_key.
    ENDIF.

  ENDDO.
ENDFORM.                    " DDIC_FIND_IN_TREE

*&---------------------------------------------------------------------*
*&      Form  OPTIONS_INIT
*&---------------------------------------------------------------------*
*       Create option panel
*----------------------------------------------------------------------*
FORM options_init.
  DATA lt_ptab TYPE wdy_wb_property_tab,
         ls_ptab TYPE wdy_wb_property.

* Create a custom container linked to the custom controm on screen 300
  CREATE OBJECT o_container_options
    EXPORTING
      container_name              'CUSTCONT2'
    EXCEPTIONS
      cntl_error                  1
      cntl_system_error           2
      create_error                3
      lifetime_error              4
      lifetime_dynpro_dynpro_link 5
      OTHERS                      6.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

* Create the property object and link it to the custom controm
  CREATE OBJECT o_options
    EXPORTING
      parent                    o_container_options
    EXCEPTIONS
      cntl_error                1
      cntl_system_error         2
      illegal_event_combination 3
      OTHERS                    4.
  IF sy-subrc <> 0.
    MESSAGE ID sy-msgid TYPE sy-msgty NUMBER sy-msgno
               WITH sy-msgv1 sy-msgv2 sy-msgv3 sy-msgv4.
  ENDIF.

  DATA lt_btn TYPE lvc_t_info.

* Define Column title of the property object
  CALL METHOD o_options->initialize
    EXPORTING
      property_column_title 'Property'(m44)
      value_column_title    'Value'(m45)
      focus_row             1
      scrollable            abap_true.

  o_options->set_enabledabap_true ).

* paste_break
  ls_ptab-name 'PB'.
  ls_ptab-type cl_wdy_wb_property_box=>property_type_boolean.
  ls_ptab-enabled abap_true.
  ls_ptab-value s_customize-paste_break.
  CONCATENATE '@74\Q'
    'Add break line after pasting ddic field into sql editor'(m46)
    '@' 'Line Break'(m47INTO ls_ptab-display_name.
  APPEND ls_ptab TO lt_ptab.

* default up to xxx rows
  ls_ptab-name 'MAXROWS'.
  ls_ptab-type cl_wdy_wb_property_box=>property_type_integer.
  ls_ptab-enabled abap_true.
  ls_ptab-value s_customize-default_rows.
  CONCATENATE '@3W\Q'
    'Default max number of displayed lines for SELECT'(m48)
    '@' 'Max Rows'(m49INTO ls_ptab-display_name.
  APPEND ls_ptab TO lt_ptab.

* default up to xxx rows
  ls_ptab-name 'TECH'.
  ls_ptab-type cl_wdy_wb_property_box=>property_type_boolean.
  ls_ptab-enabled abap_true.
  ls_ptab-value s_customize-techname.
  CONCATENATE '@AJ\Q'
    'Display technical name in query result display'(m52)
    '@' 'Technical name'(m53INTO ls_ptab-display_name.
  APPEND ls_ptab TO lt_ptab.

* Fill properties/values
  CALL METHOD o_options->set_properties
    EXPORTING
      properties lt_ptab
      refresh    abap_true.
ENDFORM.                    " OPTIONS_INIT

*&---------------------------------------------------------------------*
*&      Form  OPTIONS_DISPLAY
*&---------------------------------------------------------------------*
*       Display options panel
*----------------------------------------------------------------------*
FORM options_display.
  DATA lt_ptab TYPE wdy_wb_property_tab,
         ls_ptab TYPE wdy_wb_property.

* If not first display, refresh properties values
  IF NOT o_options IS INITIAL.
    lt_ptab o_options->get_properties).
    LOOP AT lt_ptab INTO ls_ptab.
      CASE ls_ptab-name.
        WHEN 'PB'.
          ls_ptab-value s_customize-paste_break.
        WHEN 'MAXROWS'.
          ls_ptab-value s_customize-default_rows.
        WHEN 'TECH'.
          ls_ptab-value s_customize-techname.
      ENDCASE.
      CALL METHOD o_options->update_property
        EXPORTING
          property ls_ptab.
    ENDLOOP.
  ENDIF.

* Display properties panel
  CALL SCREEN 300 STARTING AT 60 10
                  ENDING AT 90 16.
  IF w_okcode NE 'OK'.
    RETURN.
  ENDIF.

* Update values if not well refreshed in o_options
  CALL METHOD o_options->dispatch
    EXPORTING
      cargo             w_okcode
      eventid           18
      is_shellevent     space
      is_systemdispatch space
    EXCEPTIONS
      OTHERS            0.

* Update values in s_customize
  lt_ptab o_options->get_properties).
  LOOP AT lt_ptab INTO ls_ptab.
    CASE ls_ptab-name.
      WHEN 'PB'.
        s_customize-paste_break ls_ptab-value.
      WHEN 'MAXROWS'.
        s_customize-default_rows ls_ptab-value.
      WHEN 'TECH'.
        s_customize-techname ls_ptab-value.
    ENDCASE.
  ENDLOOP.

* Save values in user parameters
  PERFORM options_save.
ENDFORM.                    " OPTIONS_DISPLAY

*&---------------------------------------------------------------------*
*&      Form  RESULT_SAVE_FILE
*&---------------------------------------------------------------------*
*       Save results into local file
*       - 1 line of header is written with technical column name
*       - Fields are separated by TAB
*       - Blank at end of char fields are removed
*----------------------------------------------------------------------*
*      -->FO_RESULT    Reference to data to display
*      -->FT_FIELDS    Field list
*----------------------------------------------------------------------*
FORM result_save_file USING fo_result TYPE REF TO data
                            ft_fields TYPE ty_fieldlist_table.

  DATA lw_filename TYPE string,
         lt_file_f4 TYPE filetable,
         ls_file_f4 LIKE LINE OF lt_file_f4,
         l_rc TYPE i,
         l_filter TYPE string,
         BEGIN OF ls_field_out,
           name TYPE char30,
         END OF ls_field_out,
         lt_fields LIKE TABLE OF ls_field_out,
         ls_field_in LIKE LINE OF ft_fields.

  FIELD-SYMBOLS<lft_data> TYPE ANY TABLE.

  l_filter 'CSV File (*.csv)|*.csv'(m51).
  CALL METHOD cl_gui_frontend_services=>file_open_dialog
    EXPORTING
      window_title 'Download results into file'
      file_filter  l_filter
    CHANGING
      file_table   lt_file_f4
      rc           l_rc
    EXCEPTIONS
      OTHERS       0.
  READ TABLE lt_file_f4 INTO ls_file_f4 INDEX 1.
  IF sy-subrc 0.
    lw_filename ls_file_f4.
  ENDIF.
  IF lw_filename IS INITIAL.
    RETURN.
  ENDIF.

  ASSIGN fo_result->TO <lft_data>.
  LOOP AT ft_fields INTO ls_field_in.
    APPEND ls_field_in-ref_field TO lt_fields.
  ENDLOOP.
  CALL METHOD cl_gui_frontend_services=>gui_download
    EXPORTING
      filename              lw_filename
      write_field_separator abap_true
      trunc_trailing_blanks abap_true
      fieldnames            lt_fields
    CHANGING
      data_tab              <lft_data>
    EXCEPTIONS
      OTHERS                0.

ENDFORM.                    " RESULT_SAVE_FILE

*&---------------------------------------------------------------------*
*&      Form  DDIC_F4
*&---------------------------------------------------------------------*
*       Display F4 help on selected DDIC tree field
*       Paste selected value in SQL Editor
*----------------------------------------------------------------------*
FORM ddic_f4.
  DATA lw_table TYPE dfies-tabname,
         lw_field TYPE dfies-fieldname,
         lt_val TYPE TABLE OF ddshretval,
         ls_val LIKE LINE OF lt_val,
         lw_nodekey TYPE tv_nodekey,
         lw_item TYPE tv_itmname,
         ls_node LIKE LINE OF t_node_ddic,
         ls_item LIKE LINE OF t_item_ddic,
         lw_line_start TYPE i,
         lw_pos_start TYPE i,
         lw_line_end TYPE i,
         lw_pos_end TYPE i,
         lw_val TYPE string,
         lw_dummy.

* Get selection in ddic tree
  CALL METHOD o_tree_ddic->get_selected_node "line selected
    IMPORTING
      node_key lw_nodekey.
  IF lw_nodekey IS INITIAL.
    CALL METHOD o_tree_ddic->get_selected_item "item selected
      IMPORTING
        node_key  lw_nodekey
        item_name lw_item.
  ENDIF.
  IF lw_nodekey IS INITIAL.
    RETURN.
  ENDIF.

* Check selection is a field
  READ TABLE t_node_ddic INTO ls_node
             WITH KEY node_key lw_nodekey.
  IF sy-subrc NE OR ls_node-isfolder abap_true.
    RETURN.
  ENDIF.

* Get field name
  READ TABLE t_item_ddic INTO ls_item
             WITH KEY node_key lw_nodekey
                      item_name c_ddic_col1.
  lw_field ls_item-text.

* Get table name
  READ TABLE t_item_ddic INTO ls_item
             WITH KEY node_key ls_node-relatkey
                      item_name c_ddic_col1.
  SPLIT ls_item-text AT ' AS ' INTO lw_table lw_dummy.

* Display standard value-list
  CALL FUNCTION 'F4IF_FIELD_VALUE_REQUEST'
    EXPORTING
      fieldname  lw_field
      tabname    lw_table
    TABLES
      return_tab lt_val
    EXCEPTIONS
      OTHERS     1.

  IF sy-subrc 0.
    READ TABLE lt_val INTO ls_val INDEX 1.
    CONCATENATE '''' ls_val-fieldval '''' INTO lw_val.
    CONCATENATE space lw_val INTO lw_val RESPECTING BLANKS.

* Get current cursor position/selection in editor
    CALL METHOD o_textedit->get_selection_pos
      IMPORTING
        from_line lw_line_start
        from_pos  lw_pos_start
        to_line   lw_line_end
        to_pos    lw_pos_end
      EXCEPTIONS
        OTHERS    4.
    IF sy-subrc NE 0.
      MESSAGE 'Cannot get cursor position'(m35TYPE c_msg_error.
    ENDIF.

*   If text is selected/highlighted, delete it
    IF lw_line_start NE lw_line_end
    OR lw_pos_start NE lw_pos_end.
      CALL METHOD o_textedit->delete_text
        EXPORTING
          from_line lw_line_start
          from_pos  lw_pos_start
          to_line   lw_line_end
          to_pos    lw_pos_end.
    ENDIF.

    PERFORM editor_paste USING lw_val lw_line_start lw_pos_start.
  ENDIF.

ENDFORM.                    " DDIC_F4

*&---------------------------------------------------------------------*
*&      Form  EDITOR_GET_DEFAULT_QUERY
*&---------------------------------------------------------------------*
*       Get default query
*----------------------------------------------------------------------*
*      <--FT_QUERY  Default query content
*----------------------------------------------------------------------*
FORM editor_get_default_query  CHANGING ft_query TYPE table.
  DATA lw_string TYPE string.

  APPEND '* Type here your query title' TO ft_query.        "#EC NOTEXT
  APPEND '' TO ft_query.
  APPEND 'SELECT *' TO ft_query.                            "#EC NOTEXT
  APPEND 'FROM <table_name>' TO ft_query.                   "#EC NOTEXT

  IF s_customize-default_rows NE 0.
    lw_string s_customize-default_rows.
    CONDENSE lw_string NO-GAPS.
    CONCATENATE 'UP TO'
                lw_string
                'ROWS'
                INTO lw_string SEPARATED BY space.
    APPEND lw_string TO ft_query.                           "#EC NOTEXT
  ENDIF.

  APPEND 'WHERE <conditions>' TO ft_query.                  "#EC NOTEXT
  APPEND '.' TO ft_query.                                   "#EC NOTEXT

ENDFORM.                    " EDITOR_GET_DEFAULT_QUERY

*&---------------------------------------------------------------------*
*&      Form  EDITOR_NEW_QUERY
*&---------------------------------------------------------------------*
*       Reset SQL editor to default query
*----------------------------------------------------------------------*
FORM editor_new_query.
  DATA lt_query TYPE TABLE OF string.

* Get default query text
  PERFORM editor_get_default_query CHANGING lt_query.

* Load default query text into editor
  CALL METHOD o_textedit->set_text
    EXPORTING
      table  lt_query
    EXCEPTIONS
      OTHERS 0.

* Refresh ddic tree
  PERFORM ddic_refresh_tree.

* Hide result panel
  CALL METHOD o_splitter->set_row_height
    EXPORTING
      id     1
      height 100.

ENDFORM.                    " EDITOR_NEW_QUERY


Transparent Table - ZTOAD
QUERYID GUID_32 CHAR 32 0 GUID in 'CHAR' Format in Uppercase
OWNER SYUNAME CHAR 12 0 User Name
AEDAT TIMESTAMP DEC 15 0 UTC Time Stamp in Short Form (YYYYMMDDhhmmss)
VISIBILITY CHAR 1 0 Visibility (0:owner, 1:usergroup, 2:all)
VISIBILITY_GROUP XUCLASS CHAR 12 0 User group in user master maintenance
TEXT CHAR 30 0 Description of the query
QUERY STRING 0 0 Query


댓글 1개: