diff --git a/src/zcl_demo_abap_dynamic_prog.clas.abap b/src/zcl_demo_abap_dynamic_prog.clas.abap index 26210c6..79acb19 100644 --- a/src/zcl_demo_abap_dynamic_prog.clas.abap +++ b/src/zcl_demo_abap_dynamic_prog.clas.abap @@ -942,7 +942,44 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION. ********************************************************************** - output->next_section( `25) Dynamic Invoke` ). + output->next_section( `25) Excursion: Multiple Dynamically Specified ` && + `Clauses in an ABAP SQL SELECT Statement` ). + + "In this nonsense example, multiple clauses in a SELECT statement are + "determined at runtime to demonstrate the rich variety of possibilities. + "Note: The rows and target table specifications are not real dynamic specifications in the + "SELECT statement in the sense of syntax elements enclosed by parentheses. Here, they are just + "included to provide some more 'dynamic' touch of the statement :) + + "Getting all clauses of the SELECT statement + DATA(dyn_syntax_elem) = lcl_det_at_runtime=>get_dyn_syntax_elements( ). + + IF dyn_syntax_elem-table IS NOT INITIAL + AND dyn_syntax_elem-select_list IS NOT INITIAL + AND dyn_syntax_elem-where_clause IS NOT INITIAL + AND dyn_syntax_elem-order_by IS NOT INITIAL + AND dyn_syntax_elem-target IS BOUND + AND dyn_syntax_elem-rows IS NOT INITIAL. + + output->display( `Dynamically determined syntax elements:` ). + output->display( input = dyn_syntax_elem name = `dyn_syntax_elem` ). + + SELECT (dyn_syntax_elem-select_list) + FROM (dyn_syntax_elem-table) + WHERE (dyn_syntax_elem-where_clause) + ORDER BY (dyn_syntax_elem-order_by) + INTO CORRESPONDING FIELDS OF TABLE @dyn_syntax_elem-target->* + UP TO @dyn_syntax_elem-rows ROWS. + + output->display( input = dyn_syntax_elem-target->* name = `dyn_syntax_elem-target->*` ). + + ELSE. + output->display( `There's an issue with syntax elements.` ). + ENDIF. + +********************************************************************** + + output->next_section( `26) Dynamic Invoke` ). "In the example, both class and method are determined at runtime for "the method call. The suitable parameter table is filled in the @@ -983,7 +1020,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION. ********************************************************************** - output->next_section( `26) RTTI: Determining Data and Object Types at Runtime` ). + output->next_section( `27) RTTI: Determining Data and Object Types at Runtime` ). "The example demonstrates RTTI as follows: "- The method call takes care of providing the name of a type. It is implemented @@ -1122,7 +1159,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION. ********************************************************************** - output->next_section( `27) RTTC: Dynamically Creating Elementary Data Objects` ). + output->next_section( `28) RTTC: Dynamically Creating Elementary Data Objects` ). "The example demonstrates RTTC as follows: "- The method call takes care of providing the name of a built-in data type and more @@ -1161,7 +1198,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION. ********************************************************************** - output->next_section( `28) RTTC: Dynamically Creating Structured Data Object (1)` ). + output->next_section( `29) RTTC: Dynamically Creating Structured Data Object (1)` ). "The example demonstrates RTTC as follows: "- The method call takes care of providing the name of a database table name. @@ -1199,7 +1236,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION. ********************************************************************** - output->next_section( `29) RTTC: Dynamically Creating Structured Data Object (2)` ). + output->next_section( `30) RTTC: Dynamically Creating Structured Data Object (2)` ). "This example includes the dynamic definition of a structure with three components "using the GET method of the CL_ABAP_STRUCTDESCR class. @@ -1255,7 +1292,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION. ********************************************************************** - output->next_section( `30) RTTC: Dynamically Creating Internal Table (1)` ). + output->next_section( `31) RTTC: Dynamically Creating Internal Table (1)` ). "The example demonstrates RTTC as follows: "- The method call takes care of providing the name of a database table name. @@ -1282,7 +1319,7 @@ CLASS zcl_demo_abap_dynamic_prog IMPLEMENTATION. ********************************************************************** - output->next_section( `31) RTTC: Dynamically Creating Internal Table (2)` ). + output->next_section( `32) RTTC: Dynamically Creating Internal Table (2)` ). "In the example an internal table type is created based on a DDIC type. "See the comments in the code. diff --git a/src/zcl_demo_abap_dynamic_prog.clas.locals_imp.abap b/src/zcl_demo_abap_dynamic_prog.clas.locals_imp.abap index 7ff183e..9fe4f4f 100644 --- a/src/zcl_demo_abap_dynamic_prog.clas.locals_imp.abap +++ b/src/zcl_demo_abap_dynamic_prog.clas.locals_imp.abap @@ -20,6 +20,15 @@ CLASS lcl_det_at_runtime DEFINITION. dec TYPE i, END OF struc_builtin. + TYPES: BEGIN OF struc_dyn, + table TYPE string, + select_list TYPE string, + where_clause TYPE string_table, + order_by TYPE string, + target TYPE REF TO data, + rows TYPE i, + END OF struc_dyn. + CLASS-METHODS: get_dyn_table_name RETURNING VALUE(tab) TYPE string, get_dyn_dobj RETURNING VALUE(dobj) TYPE string, @@ -31,6 +40,7 @@ CLASS lcl_det_at_runtime DEFINITION. get_dyn_class_meth EXPORTING cl TYPE string meth TYPE string ptab TYPE abap_parmbind_tab, + get_dyn_syntax_elements RETURNING VALUE(syntax_elements) TYPE struc_dyn, fill_string. PROTECTED SECTION. @@ -289,6 +299,81 @@ CLASS lcl_det_at_runtime IMPLEMENTATION. dyn_meth_call_result = |Hallo { sy-uname }. The string was filled at { utclong_current( ) }.|. ENDMETHOD. + METHOD get_dyn_syntax_elements. + + "FROM clause + DATA(flight_tables) = VALUE string_table( + ( `ZDEMO_ABAP_CARR` ) ( `ZDEMO_ABAP_FLSCH` ) ( `ZDEMO_ABAP_FLI` ) ). + + "Getting random number to determine the table index at runtime. + DATA(idx_table) = cl_abap_random_int=>create( + seed = cl_abap_random=>seed( ) + min = 1 + max = lines( flight_tables ) )->get_next( ). + + syntax_elements-table = VALUE #( flight_tables[ idx_table ] DEFAULT `ZDEMO_ABAP_CARR` ). + + "SELECT list + DATA(comp) = CAST cl_abap_structdescr( + cl_abap_typedescr=>describe_by_name( syntax_elements-table ) )->components. + + "At least 3 components + DATA(idx_comp) = cl_abap_random_int=>create( + seed = cl_abap_random=>seed( ) + min = 3 + max = lines( comp ) )->get_next( ). + + DELETE comp FROM idx_comp + 1 TO lines( comp ). + + LOOP AT comp ASSIGNING FIELD-SYMBOL(). + syntax_elements-select_list = syntax_elements-select_list && `, ` && -name. + ENDLOOP. + + "Replacing initial comma + REPLACE PCRE `^,\s` IN syntax_elements-select_list WITH ``. + + "WHERE clause + "Excluding the client field + DELETE comp WHERE name = 'MANDT'. + + "A maximum of 4 fields are to be respected because that is the maximum of possible fields + "available in table zdemo_abap_carr (without the client field) + DATA(idx_where) = cl_abap_random_int=>create( + seed = cl_abap_random=>seed( ) + min = 1 + max = 4 )->get_next( ). + + "In the example, the WHERE clause consists of an internal table of type string. + "The clause is set up with fields and only IS NOT INITIAL to be on the safe side for a + "somewhat 'meaningful' clause and in the interest of simplicity. + LOOP AT comp ASSIGNING FIELD-SYMBOL() TO idx_where. + IF sy-tabix = 1. + APPEND -name && ` IS NOT INITIAL` TO syntax_elements-where_clause. + ELSE. + APPEND `OR ` && -name && ` IS NOT INITIAL` TO syntax_elements-where_clause. + ENDIF. + ENDLOOP. + + "ORDER BY clause + DATA(idx_order) = cl_abap_random_int=>create( + seed = cl_abap_random=>seed( ) + min = 1 + max = lines( comp ) )->get_next( ). + + syntax_elements-order_by = VALUE #( comp[ idx_order ]-name DEFAULT `CARRID` ). + + "INTO clause + CREATE DATA syntax_elements-target TYPE TABLE OF (syntax_elements-table). + + "UP TO ... ROWS + "A minimum of 2 and a maximum of 6 rows are to be retrieved by the SELECT statement + syntax_elements-rows = cl_abap_random_int=>create( + seed = cl_abap_random=>seed( ) + min = 2 + max = 6 )->get_next( ). + + ENDMETHOD. + ENDCLASS. CLASS lcl_demo1 DEFINITION.