ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Modularization] Subroutine
    SAP/Abap 2022. 1. 17. 11:01

    [Subroutine]

    특정 스크립트의 모듈화, 구조화를 통한 재사용을 목적으로 구성된 구문으로 프로그램 내/외부에서 모두 호출이 가능하다.
    * Subroutine 호출부
    PERFORM write_data.
    
    * Subroutine 정의부
    FORM write_data.
      WRITE :/ 'Subroutine TEST'.
    ENDFORM.

     

     

    [Subroutine: Parameter(1)]

    Parameter: Subroutine의 정의부와 호출부 사이에서 주고받는 데이터로 모든 data type, field symbol, internal table 등이 사용 가능하며, subroutine 내에서는 일반적인 local 변수처럼 사용된다.
       - Actual parameter: Subroutine 호출 시 사용되는 parameter.
       - Formal parameter: Subroutine에서 사용되는 parameter.

    0) Parameter의 전달방법

    call-by-value actual parameter와 formal parameter가 서로 다른 메모리 영역에 존재  => value 복사 개념
    call-by-reference actual parameter와 formal parameter가 서로 같은 메모리 영역에 존재  => object 참조 개념
    call-by-value_and_result actual parameter와 formal parameter가 서로 다른 메모리 영역에 존재, 작업 성공시에만 값 반환

     

    1) Call-by-Value

    PERFORM subr [USING | CHANGING] <ap>
    FORM subr USING VALUE(<fp>)
    REPORT ZA04_02.
    
    DATA : gv_val TYPE c LENGTH 20 VALUE 'Call by Value test'.
    
    PERFORM call_byvalue USING gv_val.
    WRITE :/ 'gv_val: ', gv_val.
    
    FORM call_byvalue USING VALUE(p_val).
      WRITE :/ 'p_val: ', p_val.
      p_val = 'Data changed'.
      WRITE :/ 'p_val: ', p_val.
    ENDFORM.

     

    2) Call-by-Reference

    PERFROM subr [USING | CHANGING] <ap>
    FORM subr [USING | CHANGING] <fp>
    REPORT ZA04_03.
    
    DATA : gv_val TYPE c LENGTH 30 VALUE 'Call by Reference test'.
    
    PERFORM call_byref CHANGING gv_val.
    WRITE :/ 'gv_val: ', gv_val.
    
    FORM call_byref CHANGING p_val.
      WRITE :/ 'p_val: ', p_val.
      p_val = 'Data changed'.
      WRITE :/ 'p_val: ', p_val.
    ENDFORM.

     

    3) Call-by-Value_and_Result

    Call-by-reference와 비슷한 의미를 갖는다.
    해당 subroutine이 정상종료될 경우 actual parameter값이 formal parameter값으로 변경된다.
    PERFORM subr [USING | CHANGING] <ap>
    FORM subr CHANGING VALUE(<fp>)
    REPORT ZA04_04.
    
    DATA : gv_val1    TYPE i VALUE 2,
           gv_val2    TYPE i VALUE 3,
           gv_sum     TYPE i.
    
    PERFORM sum_data USING     gv_val1        " call_by_value
                               gv_val2        " call_by_value
                     CHANGING  gv_sum.        " call_by_reference
    
    WRITE :/ 'Result: ', gv_sum.
    
    
    FORM sum_data USING       value(p_val1)   " call_by_value
                              value(p_val2)   " call_by_value
                  CHANGING    value(p_sum).   " call_by_value_and_result
      p_sum = p_val1 + p_val2.
    ENDFORM.

     

    4) 정리

    • PERFORM(호출부) 구문에서는 USING, CHANGING이 모두 사용 가능하지만, 의미를 다르게 하기위해 나눠 사용한다.
      • USING: 값을 사용한다는 의미               => 메모리가 별도로 존재
      • CHANGING: 값을 변경한다는 의미       => 동일한 메모리를 참조
    • FORM(정의부) 구분에서는 USING VALUE, CHANGING VALUE에 따라 동작이 달라진다.
      • USING VALUE (<fp>): formal parameter의 메모리가 할당되고, 값이 복사되어 전달받는다. => Call-by-Value
      • CHANGING VALUE (<fp>): actual parameter의 주소값을 전달받는다. => Call-by-Reference | Call-by-ValueAndResult

     

    [Subroutine: Parameter(2)]

    1) Parameter 타입 정의

    FORM 구문 내의 formal parameter는 TYPE, LIKE구문을 사용해 모든 abap data type을 사용할 수 있다.
    • Generic type: 특정 type을 명시적으로 지정하지 않으면 actual parameter의 기술적 속성을 상속받게 된다.
      • 이때는 actual param, formal param 간의 type conversion이 가능해야한다.
    # 1. Generic type 사용
    FORM subr CHANGING p_val.
    # 2. Abap 기본 data type 사용
    FORM subr CHANGING p_val TYPE d.
    # 3. Actual parameter와 같은 type 사용.
    FORM subr CHANGING p_val LIKE gv_val.
    • Generic type을 사용할때, actual param, formal param간 type conversion이 불가능하다면 구문에러가 발생한다.
    REPORT ZA04_05.
    
    DATA : gv_val TYPE c.                      " actual param: Type c
    
    PERFORM call_byref CHANGING gv_val.
    
    WRITE :/ gv_val.
    
    
    FORM call_byref CHANGING p_val TYPE i.     " formal param: Type i
      p_val = 'Value is changed'.
    ENDFORM.

     

     

    2) Parameter와 구조체

    FORM subr CHANGING <param> [TYPE | LIKE | STRUCTURE] <str>
    REPORT ZA04_06.
    
    DATA : BEGIN OF gs_str,
      col1 VALUE 'A',
      col2 VALUE 'B',
    END OF gs_str.
    
    PERFORM write_data CHANGING gs_str.
    
    
    FORM write_data USING ps_str STRUCTURE gs_str.
      WRITE : ps_str-col1, ps_str-col2.
    ENDFORM.
    • Parameter type으로 구조체를 사용할때 명시적으로 type을 지정하지 않으면 구조체 내 컬럼을 찾을수 없으므로 에러가 발생한다.
      • 이후 배울 필드 심볼을 통해 명시적 type 지정 없이 사용이 가능하다.

     

     

    3) Paramter와 인터널 테이블

    • USING 및 CHANGING 구문: TYPE 및 LIKE를 사용한다.
    FORM subr CHANGING <param> [TYPE | LIKE] <itab>
    REPORT ZA04_07.
    
    TYPES : BEGIN OF t_str,
      col1 TYPE c,
      col2 TYPE i,
    END OF t_str.
    
    TYPES : t_itab TYPE TABLE OF t_str.
    
    DATA : gs_str     TYPE t_str,
           gt_itab    TYPE t_itab.
    
    gs_str-col1 = 'A'.
    gs_str-col2 = 1.
    APPEND gs_str TO gt_itab.
    
    gs_str-col1 = 'B'.
    gs_str-col2 = 2.
    APPEND gs_str TO gt_itab.
    
    PERFORM test_itab USING gt_itab.
    
    
    FORM test_itab USING pt_itab TYPE t_itab.
      READ TABLE pt_itab WITH KEY col1 = 'A' INTO gs_str.
      IF sy-subrc EQ 0.
        WRITE :/ gs_str-col1, gs_str-col2.
      ENDIF.
    ENDFORM.
    • TABLES 구문: 이전 프로그램에서 USING, CHANGING 대신 사용되던 구문이지만 호환성 문제로 현재도 사용되고 있다.
    REPORT ZA04_08.
    
    TYPES : BEGIN OF t_str,
      col1 TYPE c,
      col2 TYPE i,
    END OF t_str.
    
    TYPES : t_itab TYPE TABLE OF t_str.
    
    DATA : gt_itab    TYPE t_itab.
    
    PERFORM test_itab  TABLES gt_itab.
    PERFORM write_data TABLES gt_itab.
    
    
    FORM test_itab TABLES pt_itab TYPE t_itab.
      DATA ls_str TYPE t_str.
      ls_str-col1 = 'A'.
      ls_str-col2 = 1.
      APPEND ls_str TO pt_itab.
    
      ls_str-col1 = 'B'.
      ls_str-col2 = 2.
      APPEND ls_str TO pt_itab.
    ENDFORM.
    
    FORM write_data TABLES pt_itab LIKE gt_itab.
      DATA ls_str TYPE t_str.
      LOOP AT pt_itab INTO ls_str.
        WRITE :/ ls_str-col1, ls_str-col2.
      ENDLOOP.
    ENDFORM.

     

     

     

    [Subroutine 호출]

    Subroutine은 internal / external 두가지 방식으로 호출이 가능하다.
    # 1. Internal call.
    PERFORM subr.
    # 2. External call
    PERFORM subr (prog) [IF FOUND]

     

    1) Internal subroutine call

    REPORT ZA04_09.
    
    DATA : gv_val1(10) TYPE c VALUE 'Enjoy',
           gv_val2(10) TYPE c VALUE 'Abap',
           gv_val3(20) TYPE c.
    
    PERFORM concate_string USING     gv_val1 gv_val2
                           CHANGING  gv_val3.
    
    
    FORM concate_string USING     VALUE(p_val1) VALUE(p_val2)
                        CHANGING  VALUE(p_val3).
      CONCATENATE p_val1 p_val2 INTO p_val3 SEPARATED BY space.
      PERFORM write_data USING p_val3.
    ENDFORM.
    
    FORM write_data USING VALUE(p_val).
      WRITE :/ p_val.
    ENDFORM.

     

    2) External subroutine call

    • 명시된 프로그램에 subroutine이 존재하지 않는다면 덤프에러가 발생한다.

    • [IF FOUND] 키워드 추가시 해당 프로그램에 해당 subroutine이 존재하는 경우에만 실행한다.
      • 해당 프로그램에 해당 subroutine이 존재하지 않으면 해당 subroutine은 호출되지 않는다.
    REPORT ZA04_10.
    
    DATA : gv_val1(10) TYPE c VALUE 'External',
           gv_val2(10) TYPE c VALUE 'Call',
           gv_val3(20) TYPE c.
    
    PERFORM concate_string(ZA04_09) IF FOUND USING gv_val1 gv_val2
                                              CHANGING gv_val3.

     

    3) Subroutine 동적 호출

    • Subroutine name 동적 설정
      • 동적 호출시에는 프로그램명과 서브루틴명을 반드시 대문자로 지정해야 한다.
    PERFORM (fsubr) [IN PROGRAM (fprog)] ...
    REPORT ZA04_11.
    
    DATA : gv_first(10)     TYPE c VALUE 'Dynamic',
           gv_second(10)    TYPE c VALUE 'Call',
           gv_result(20)    TYPE c.
    
    DATA : gv_pname(10)     TYPE c VALUE 'za04_09',
           gv_sname(20)     TYPE c VALUE 'concate_string'.
    
    TRANSLATE gv_pname TO UPPER CASE.
    TRANSLATE gv_sname TO UPPER CASE.
    
    PERFORM (gv_sname) IN PROGRAM (gv_pname) IF FOUND
                              USING gv_first gv_second
                              CHANGING gv_result.​

     

    • LIST를 이용한 Subroutine 호출
      • 시스템의 index 순서에 따라 subroutine을 호출한다.
      • 오직 Internal subroutine call만 가능하며 parameter 사용이 불가능하다.
    PERFORM idx OF subr1 subr2 ...
    REPORT ZA04_12.
    
    DO 2 TIMES.
      PERFORM sy-index OF subr1 subr2.
    ENDDO.
    
    
    FORM subr1.
      WRITE :/ '1 subroutine is called'.
    ENDFORM.
    
    FORM subr2.
      WRITE :/ '2 subroutine is callled'.
    ENDFORM.

     

     

    #) Abap 언어의 반복문

    3가지 형태의 반복문이 있으며 각 반복문에서의 반복횟수는 SY-INDEX 시스템 변수에 저장된다.

    1. DO ~ ENDDO 구문

    DO n TIMES.
         ...
    ENDDO.

    2. WHILE ~ ENDWHILE 구문

    WHILE flag = 'X'.
         ...
    ENDWHILE.

    3. LOOP ~ ENDLOOP 구문

    LOOP AT  itab TO  wa.
         ...
    ENDLOOP.

     

     

     

    [Subroutine 종료]

    일반적으로 Subroutine은 ENDFORM문을 만나면 정상 종료되지만, EXIT 또는 CHECK구문을 통해 서브루틴 수행중에 종료할 수 있다.
    • EXIT구문: Subroutine을 바로 종료시킨다.
    • CHECK구문: 해당 구문이 거짓이면 Subroutine을 종료시킨다.
    REPORT ZA04_13.
    
    PARAMETERS : p_val TYPE char10.
    
    PERFORM end_subr USING p_val.
    
    
    FORM end_subr USING VALUE(p_val).
      CASE p_val.
        WHEN 'EXIT'.
          WRITE :/ 'Subroutine exit'.
          EXIT.
        WHEN 'CHECK'.
          WRITE :/ 'Value check'.
          CHECK p_val NE 'CHECK'.
        WHEN OTHERS.
      ENDCASE.
    
      WRITE :/ 'Subroutine is nomally end'.
    ENDFORM.

     

    #) Abap 프로그램의 분기문

    1. IF ~ ENDIF 분기문

    IF 조건문.
         ...
    [ELSEIF 조건문].
         ...
    ELSE.
         ...
    ENDIF

    2. CASE ~ ENDCASE 분기문

    CASE 변수.
         WHEN 'val1'.
              ...
         WHEN 'val2'.
              ...
         WHEN OTHERS.
              ...
    ENDCASE.

     

     

     

    [Temporary Subroutine]

    실행중인 프로그램의 메모리에 Subroutine pool을 생성하여 동적으로 subroutine을 정의할 수 있다.
    GENERATE SUBROUTINE POOL <itab> NAME <prog>
    • <itab>: 생성할 subroutine의 소스코드를 삽입할 인터널 테이블
    • <prog>: 생성할 subroutine 프로그램
    • 사용자의 입력에 따라 인터널테이블을 동적으로 생성해야 하는 경우 유용하게 사용된다.
      • ex) 매출 조회 프로그램: 입력일에 따라 조회할 데이터(인터널테이블)가 달라진다.
    REPORT ZA04_14.
    
    DATA : gt_code(72) OCCURS 10,
           gs_code(72),
           gv_prog(8),
           gv_msg(120).
    
    APPEND 'PROGRAM SUBPOOL.' TO gt_code.
    APPEND 'FORM dynamic_subr.' TO gt_code.
    APPEND 'WRITE / ''Dynamic Subroutine is called''.' TO gt_code.
    APPEND 'ENDFORM.' TO gt_code.
    
    LOOP AT gt_code INTO gs_code.
      WRITE :/ 'gs_code: ', gs_code.
    ENDLOOP.
    
    GENERATE SUBROUTINE POOL gt_code NAME gv_prog MESSAGE gv_msg.
    
    IF sy-subrc <> 0.
      WRITE :/ 'Subroutine POOL is failed'.
    ELSE.
      WRITE :/ 'Subroutine POOL name: ', gv_prog.
      SKIP 1.
      PERFORM dynamic_subr IN PROGRAM (gv_prog).
    ENDIF.

     

     

     

    [Perform on Commit]

    Subroutine 호출 시 ON [COMMIT | ROLLBACK] 옵션을 사용하면 [COMMIT WORK | ROLLBACK WORK] 구문을 만날때 해당 FORM이 실행된다.
    • PERFORM insert_data ON COMMIT 명령어가 실행되면
      • insert_data subroutine이 실행되지 않는다.
      • 이후 COMMIT WORK 명령어가 실행되야 insert_data subroutine이 실행된다.
    REPORT ZA04_15.
    
    DATA : gs_scarr LIKE scarr,
           gv_flg   TYPE c.
    
    SELECT SINGLE *
      FROM scarr
      INTO gs_scarr
      WHERE carrid = 'AA'.
    
    WRITE :/ 'delete_data call'.
    PERFORM delete_data USING gs_scarr.
    
    WRITE :/ 'insert_data call ON COMMIT'.
    PERFORM insert_data ON COMMIT.
    
    IF gv_flg = 'X'.
      WRITE :/ 'COMMIT WORK'.
      COMMIT WORK.
    ENDIF.
    
    
    FORM delete_data USING value(ps_scarr) TYPE scarr.
      WRITE :/ 'delete_data called'.
      DELETE scarr FROM ps_scarr.
      IF sy-subrc EQ 0.
        gv_flg = 'X'.
      ENDIF.
    ENDFORM.
    
    FORM insert_data.
      WRITE :/ 'insert_data called'.
      INSERT scarr FROM gs_scarr.
    ENDFORM.

     

     

    [Macro]

    'SAP > Abap' 카테고리의 다른 글

    [Internal Table] Internal table 개념  (0) 2022.01.19
    [Modularization] Function  (0) 2022.01.18
    [Open SQL & Native SQL] Native SQL  (0) 2022.01.14
    [Open SQL & Native SQL] SQL else  (0) 2022.01.14
    [Open SQL & Native SQL] INSERT & UPDATE & DELETE & MODIFY  (0) 2022.01.14
Designed by Tistory.