[ABAP] Dynamisches Selektionsbild-Popup erzeugen

CLASS lcl_dynamic_popup DEFINITION.
  PUBLIC SECTION.
    CLASS-METHODS
      show
        RETURNING VALUE(rv_ok) TYPE abap_bool.
ENDCLASS.

CLASS lcl_dynamic_popup IMPLEMENTATION.
  METHOD show.

    rv_ok = abap_true.

* Werte für Selektionbild definieren
    DATA: p_carrid TYPE s_carr_id.
    DATA: so_werks TYPE gds_selrange_werks_tab.
    DATA: p_werks_no TYPE werks.
    DATA: p_check  TYPE xfeld.
    DATA: rb_1 TYPE xfeld.
    DATA: rb_2 TYPE xfeld.
    DATA: lb_language TYPE spras.

    lb_language = sy-langu.

* Selektionsbildelemente für das Popup
* die Eingabewerte werden mit den Variablen über die Felder "ref" verknüpft
    DATA(it_attr) = VALUE sci_atttab(
* Group1 für die folgenden Felder
                                      (
                                        kind = 'G'
                                        text = 'Gruppe1'
                                        ref  = REF #( sy-index )
                                      )
* Parameter
                                      (
                                          kind       = 'S'
                                          text       = 'Carrid'
                                          obligatory = abap_true
                                          ref        = REF #( p_carrid )
                                      )
* SELECT-OPTIONS
                                      (
                                          kind       = 'S'
                                          text       = 'Werk'
                                          ref        = REF #( so_werks )
                                      )
* SELECT-OPTIONS NO INTERVALS
                                      (
                                          kind       = 'T'
                                          text       = 'Werk2'
                                          ref        = REF #( p_werks_no )
                                      )
* Group2 für die folgenden Felder
                                      (
                                        kind = 'G'
                                        text = 'Gruppe2'
                                        ref  = REF #( sy-index )
                                      )
* Checkbox
                                      (
                                          kind       = 'C'
                                          text       = 'Check'
                                          ref        = REF #( p_check )
                                      )
* Radiobuttons mit Group
                                      (
                                          kind         = 'R'
                                          text         = 'Radiobutton1'
                                          button_group = 'GR1'
                                          ref          = REF #( rb_1 )
                                      )
                                      (
                                          kind         = 'R'
                                          text         = 'Radiobutton2'
                                          button_group = 'GR1'
                                          ref          = REF #( rb_2 )
                                      )
* Listbox
                                      (
                                          kind = 'L'
                                          text = 'Sprache'
                                          ref  = REF #( lb_language )
                                      )
                                    ).

* Selektionsbild erzeugen und Popup anzeigen
    IF abap_true = cl_ci_query_attributes=>generic( p_name       = CONV #( sy-repid )
                                                    p_title      = 'Dynamisches Popup'
                                                    p_display    = abap_false " abap_true: Anzeige im READONLY-Modus
                                                    p_attributes = it_attr ).
      rv_ok = abap_false.
    ENDIF.

* Werte ausgeben
    WRITE: / 'CARRID:', p_carrid.
    WRITE: / 'WERKS:', COND string( WHEN lines( so_werks ) > 0 THEN so_werks[ 1 ]-low ELSE '' ).
    WRITE: / 'WERKS2:', p_werks_no.
    WRITE: / 'Check:', p_check.
    WRITE: / 'RB1:', rb_1.
    WRITE: / 'RB2:', rb_2.
    WRITE: / 'LANGUAGE:', lb_language.

  ENDMETHOD.
ENDCLASS.

START-OF-SELECTION.
  IF abap_true = lcl_dynamic_popup=>show( ).
    WRITE: / 'Ok.'.
  ELSE.
    WRITE: / 'Abbruch.'.
  ENDIF.

[ABAP] ABAP Database Connectivity (ADBC) – CASE-insensitive Suche auf der Datenbank

* ab Version 7.51 auch im OpenSQL verfügbar (LOWER, UPPER)
* https://help.sap.com/doc/abapdocu_751_index_htm/7.51/de-DE/abenopen_sql_functions.htm
* https://archive.sap.com/discussions/thread/3470652

DATA: o_salv TYPE REF TO cl_salv_table.        " Anzeigeobjekt SALV Grid
DATA: it_cols TYPE adbc_column_tab.            " Selektierte Spalten
DATA: it_makt TYPE STANDARD TABLE OF makt.     " Ausgabetabelle

START-OF-SELECTION.

* zu verarbeitende Spalten
  it_cols = VALUE #( ( 'MATNR' )
                     ( 'SPRAS' )
                     ( 'MAKTX' )
                     ( 'MAKTG' ) ).

* Spaltennnamen durch Komma trennen
  DATA(cols) = to_lower( concat_lines_of( table = it_cols sep = ',' ) ).

* Spaltennamen und Parameter in SQL einfügen, alle Bezeichner suchen, die mit 'sch*' beginnen
  DATA(lv_query) = |SELECT { cols } FROM makt WHERE spras = 'D' AND upper(maktx) LIKE 'SCH%'|.

  TRY.
* SQL-Connection öffnen
      DATA(o_sql_connection) = NEW cl_sql_connection( ).

      IF abap_true <> o_sql_connection->is_closed( ).
* SQL-Statement erzeugen
        DATA(o_sql) = NEW cl_sql_statement( con_ref = o_sql_connection ).

* Query ausführen
        DATA(o_result) = o_sql->execute_query( lv_query ).

* Ergebnismenge soll in interne Tabelle it_makt und nur die Spalten, welche in it_cols stehen
        o_result->set_param_table( itab_ref             = REF #( it_makt )
                                   corresponding_fields = it_cols ).

* Ergebnismenge in interne Tabelle lesen
* cnt enthält die Anzahl der gelesenen Datensätze
        DATA(cnt) = o_result->next_package( ).
* Ergebnismenge schließen
        o_result->close( ).
* SQL-Connection schließen
        o_sql_connection->close( ).

        IF cnt > 0.
          cl_salv_table=>factory( IMPORTING
                                    r_salv_table = o_salv
                                  CHANGING
                                    t_table = it_makt ).

          o_salv->get_display_settings( )->set_list_header( |DBMS: { o_sql_connection->get_dbms( ) }| ).
          o_salv->get_functions( )->set_all( abap_true ).
          o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
          o_salv->display( ).
        ENDIF.
      ENDIF.
    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.

[ABAP] Arbeit mit Referenzen

einfache Wertänderung über Referenz

* int-Variable anlegen, Wert 1
DATA(lv_int) = 1.
* Referenz auf int
DATA(o_int) = REF #( lv_int ).

* Änderung auf Wert 2
lv_int = 2.

* Ausgabe Wert 2
WRITE: / o_int->*.

* Änderung auf 3
o_int->* = 3.

* Ausgabe Wert 3
WRITE: / lv_int.

mehrfache Wertänderung über Referenz

* int-Variable anlegen, Wert 1
DATA(lv_int) = 1.
* generische Referenz auf die int-Variable
DATA(o_int) = REF data( lv_int ).
* Variable auf Wert 2 ändern
lv_int = 2.

* Zwei Feldsymbole (<i1> und <i2>) mit der Referenz verknüpfen
ASSIGN o_int->* TO FIELD-SYMBOL(<i1>).
ASSIGN o_int->* TO FIELD-SYMBOL(<i2>).

* den Wert eines der Feldsymbole ändern
<i1> = 4.

* es ändern sich durch den Bezug sogleich alle anderen Feldsymbole und Variablen mit :)
WRITE: / lv_int.
WRITE: / <i1>.
WRITE: / <i2>.

generische Referenz auf interne Tabelle

* Stringtable aus DDIC (gefüllt)
DATA(it_stringtab) = VALUE stringtab( ( |Udo| )
                                      ( |Heinz| )
                                      ( |Klaus| ) ).

* generische Referenz auf die Stringtable
DATA(o_tab) = REF data( it_stringtab ).

* Feldsymbol explizit als generische Table definieren
FIELD-SYMBOLS: <tab> TYPE ANY TABLE.
* Feldsymbol auf die interne Tabelle mit der generischen Referenz verknüpfen
ASSIGN o_tab->* TO <tab>.

* Tabelleninhalt darstellen
LOOP AT <tab> ASSIGNING FIELD-SYMBOL(<l>).
  WRITE: / <l>.
ENDLOOP.

referentieller Zugriff auf eine interne Tabelle

* Typdeklaration
TYPES: ty_it_sflight TYPE STANDARD TABLE OF sflight WITH DEFAULT KEY.

* Tabelle anlegen
DATA(it_sflight) = VALUE ty_it_sflight( ( carrid = 'AA' connid = '0123' )
                                        ( carrid = 'LH' connid = '3210' ) ).

* generische Referenz auf die Table
DATA(o_tab) = REF data( it_sflight ).

* Feldsymbol explizit als generische Table definieren
FIELD-SYMBOLS: <tab> TYPE ty_it_sflight. " hier auch STANDARD TABLE möglich
* Feldsymbol auf die interne Tabelle mit der generischen Referenz verknüpfen
ASSIGN o_tab->* TO <tab>.

* wenn Zeilen in der Tabelle vorhanden
IF lines( <tab> ) > 0.
* erste Zeile holen und mit Feldsymbol verknüpfen
  ASSIGN <tab>[ 1 ] TO FIELD-SYMBOL(<row>).
* Struktur (Felder) der ersten Zeile ermitteln
  DATA(o_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( <row> ) ).
* Anzahl Felder in der Struktur ermitteln
  DATA(lv_cnt) = lines( o_struct->get_components( ) ).

* Tabelleninhalt darstellen
  LOOP AT <tab> ASSIGNING <row>.

    DATA(lv_row) = ||.

* Felder durchgehen
    DO lv_cnt TIMES.
* Zellen einer zeile holen
      ASSIGN COMPONENT sy-index OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
* Zellinhalt ausgeben
      IF sy-index = 0.
        lv_row = |{ <cell> }|.
      ELSE.
        lv_row = |{ lv_row } \| { <cell> }|.
      ENDIF.
    ENDDO.

    WRITE: / lv_row.
  ENDLOOP.

ENDIF.

[ABAP] OO: Variablen, Strukturen, interne Tabellen, Objektreferenzen anlegen

Variable anlegen

* int
DATA(lv_int) = 1.
DATA(lv_int_empty) = VALUE i( ).
 
* float
DATA(lv_float_empty) = VALUE f( ).
DATA(lv_float) = CONV f( '0.1' ).
 
* char
DATA(lv_char) = 'ABCD'.
 
* string
DATA(lv_empty_string) = ||.
DATA(lv_string) = |Text|.
 
* bool
DATA(lv_bool) = abap_true.
 
* DDIC-Typ (z.B. MATNR)
DATA(lv_matnr) = CONV matnr( '1234567890' ).
DATA(lv_matnr_empty) = VALUE matnr( ).

Struktur anlegen

* definiert vom Anwender
TYPES: BEGIN OF ty_sflight,
         carrid TYPE sflight-carrid,
         connid TYPE sflight-connid,
       END OF ty_sflight.

DATA(lv_struct) = VALUE ty_sflight( carrid = 'LH'
                                    connid = '0123' ).

* Strukturtyp aus DDIC (leer)
DATA(lv_headdata_empty) = VALUE bapimathead( ).

* Strukturtyp aus DDIC (gefüllt)
DATA(lv_headdata) = VALUE bapimathead( material      = '1234567890'
                                       basic_view    = abap_true
                                       purchase_view = abap_true
                                       account_view  = abap_true ).

interne Tabelle anlegen

* definiert vom Anwender
TYPES: BEGIN OF ty_sflight,
         carrid TYPE sflight-carrid,
         connid TYPE sflight-connid,
       END OF ty_sflight.

TYPES: ty_it_sflight TYPE STANDARD TABLE OF ty_sflight WITH DEFAULT KEY.

DATA(it_tab) = VALUE ty_it_sflight( ( carrid = 'LH' connid = '0123' )
                                    ( carrid = 'AA' connid = '3210' ) ).

* Stringtable aus DDIC (leer)
DATA(it_stringtab_empty) = VALUE stringtab( ).

* Stringtable aus DDIC (gefüllt)
DATA(it_stringtab) = VALUE stringtab( ( |Udo| )
                                      ( |Heinz| )
                                      ( |Klaus| ) ).

Objektreferenz anlegen

* Objektreferenz auf Klasse ALV-Grid
DATA(o_alv) = NEW cl_gui_alv_grid( i_parent      = cl_gui_container=>default_screen
                                   i_appl_events = abap_true ).

* Referenz auf int
DATA(lv_int) = 1.
DATA(o_int) = REF #( lv_int ).

* Referenz auf stringtab
DATA(it_stringtab) = VALUE stringtab( ).
DATA(o_tab) = REF #( it_stringtab ).

[ABAP] Objekt-Referenzen in interner Tabelle (Liste) speichern

TYPES: BEGIN OF ty_user,
         bname      TYPE usr21-bname,
         persnumber TYPE adr6-persnumber,
         addrnumber TYPE adr6-addrnumber,
         smtp_addr  TYPE adr6-smtp_addr,
       END OF ty_user.

CLASS cl_person DEFINITION.
  PUBLIC SECTION.
    METHODS: constructor
      IMPORTING
        i_userdata TYPE ty_user.
    METHODS: print_mail.
  private SECTION.
    DATA: userdata TYPE ty_user.
ENDCLASS.

CLASS cl_person IMPLEMENTATION.
  METHOD constructor.
    userdata = i_userdata.
  ENDMETHOD.

  METHOD print_mail.
    WRITE: / userdata-bname, userdata-smtp_addr.
  ENDMETHOD.
ENDCLASS.

DATA: it_userdata TYPE TABLE OF ty_user.

* interne Tabelle zur Speicherung der Objektreferenzen
DATA: it_persons TYPE TABLE OF REF TO cl_person.
* Objektreferenz
DATA: o_person TYPE REF TO cl_person.

START-OF-SELECTION.
* Daten holen
  SELECT u~bname, u~persnumber, u~addrnumber, a~smtp_addr
    INTO CORRESPONDING FIELDS OF TABLE @it_userdata
    FROM usr21 AS u
    INNER JOIN adr6 AS a ON a~persnumber = u~persnumber AND a~addrnumber = u~addrnumber
    UP TO 10 ROWS.

* Objekte erzeugen und an Referenztabelle anhängen
  LOOP AT it_userdata INTO DATA(wa_user).
    o_person = new cl_person( wa_user ).
    APPEND o_person TO it_persons.
  ENDLOOP.

* Referenztabelle durchloopen und Objekte aufrufen
  LOOP AT it_persons INTO o_person.
    o_person->print_mail( ).
  ENDLOOP.

[ABAP] Generische Verarbeitung von internen Tabellen / Verwendung von Referenzen

* irgendeine interne Tablelle anlegen
DATA: it_tab TYPE STANDARD TABLE OF ...
* generische Tabellenreferenz anlegen
DATA: o_ref_table TYPE REF TO data.
 
...
 
* Tabellenreferenz übergeben
o_ref_table = REF #( it_tab ).
 
* Referenz auf generisches Feldsymbol mappen
FIELD-SYMBOLS: <tab> TYPE ANY TABLE.
ASSIGN o_ref_table->* TO <tab>.
 
* Tabellen-Zeile erzeugen
* muss hier erfolgen, damit man ein "greifbares" Tabellen-Zeilen-Objekt
* für die Strukturermittlung (describe_by_data) hat
DATA: o_row TYPE REF TO data.
CREATE DATA o_row LIKE LINE OF <tab>.
FIELD-SYMBOLS: <row> TYPE any.
ASSIGN o_row->* TO <row>.
 
* Komponenten (Spalten) einer Tabellenzeile ermitteln
DATA(o_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( <row> ) ).
DATA(it_comp_tab) = o_struct->get_components( ).
 
* Anzahl Spalten der Tabellen-Zeile holen
DATA(lv_colcnt) = lines( it_comp_tab ).
 
* Tabelle durchloopen
LOOP AT <tab> ASSIGNING <row>.

* Spalten der akt. Zeile durchgehen
  DO lv_colcnt TIMES.
* Zelle: n-tes Element der akt. Zeile holen
    ASSIGN COMPONENT sy-index OF STRUCTURE <row> TO FIELD-SYMBOL(<cell>).
    
* Trennzeichen vor die Spalte einfügen, wenn nicht 1. Spalte
    IF sy-index > 1.
      WRITE: '|'.
    ENDIF.

* Achtung: Zell-Typ beachten! Es können hier nur flache Typen (Keine Strukturen, Tabellen) ausgegeben werden, der Rest muss gesondert behandelt werden
    IF CAST cl_abap_elemdescr( it_comp_tab[ sy-index ]-type )->kind = cl_abap_elemdescr=>kind_elem.
* Ausgabe Zellinhalt mit vordefinierter Spaltenbreite
      WRITE: |{ <cell> WIDTH = 20 |.
    ENDIF.
  ENDDO.

  NEW-LINE.
ENDLOOP.

[ABAP] ADBC – ABAP Database Connectivity

* ab V6.10 verfügbar
* http://zevolving.com/2013/05/abap-database-connectivity-adbc/
* https://archive.sap.com/discussions/thread/447887

* DEMO_ADBC_DDL_DML
* DEMO_ADBC_DDL_DML_BINDING
* DEMO_ADBC_DDL_DML_BULK_ACCESS
* DEMO_ADBC_PREPARED_STATEMENT
* DEMO_ADBC_QUERY
* DEMO_ADBC_STORED_PROCEDURE

DATA: o_salv TYPE REF TO cl_salv_table.        " Anzeigeobjekt SALV Grid
DATA: it_cols TYPE adbc_column_tab.            " Selektierte Spalten
DATA: it_tsp01 TYPE STANDARD TABLE OF tsp01.   " Ausgabetabelle
DATA: par TYPE i VALUE 2000.                   " Parameter für Selektion

START-OF-SELECTION.

* zu verarbeitende Spalten
  it_cols = VALUE #( ( 'RQIDENT' )
                     ( 'RQDEST' )
                     ( 'RQPAPER' )
                     ( 'RQO1NAME' ) ).

* Spaltennnamen durch Komma trennen
  DATA(cols) = to_lower( concat_lines_of( table = it_cols sep = ',' ) ).
* Spaltennamen und Parameter in SQL einfügen
  DATA(lv_query) = |SELECT { cols } FROM tsp01 WHERE rqident > '{ par }'|.

  TRY.
* SQL-Connection öffnen
      DATA(o_sql_connection) = NEW cl_sql_connection( ).

      IF abap_true <> o_sql_connection->is_closed( ).
* SQL-Statement erzeugen
        DATA(o_sql) = NEW cl_sql_statement( con_ref = o_sql_connection ).
* Query ausführen
        DATA(o_result) = o_sql->execute_query( lv_query ).
* Ergebnismenge soll in interne Tabelle it_tsp01 und nur die Spalten, welche in it_cols stehen
        o_result->set_param_table( itab_ref             = REF #( it_tsp01 )
                                   corresponding_fields = it_cols ).
* Ergebnismenge in interne Tabelle lesen
* cnt enthält die Anzahl der gelesenen Datensätze
        DATA(cnt) = o_result->next_package( ).
* Ergebnismenge schließen
        o_result->close( ).
* SQL-Connection schließen
        o_sql_connection->close( ).

        IF cnt > 0.
          cl_salv_table=>factory( IMPORTING
                                    r_salv_table = o_salv
                                  CHANGING
                                    t_table = it_tsp01 ).

          o_salv->get_display_settings( )->set_list_header( |DBMS: { o_sql_connection->get_dbms( ) }| ).
          o_salv->get_functions( )->set_all( abap_true ).
          o_salv->get_display_settings( )->set_striped_pattern( abap_true ).
          o_salv->display( ).
        ENDIF.
      ENDIF.
    CATCH cx_root INTO DATA(e_text).
      WRITE: / e_text->get_text( ).
  ENDTRY.