-
[Modularization] SubroutineSAP/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.
...
ENDIF2. 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 - PERFORM(호출부) 구문에서는 USING, CHANGING이 모두 사용 가능하지만, 의미를 다르게 하기위해 나눠 사용한다.