현재 파견나와 있는 고객사의 개발환경에서 spring을 사용중인데, Service 레벨의 Mgr 선언부 class가 존재하고, 실제 구현부에 해당하는 MgrImpl 파일이 따로 존재한다.
eclipse에서 다른 클래스의 메소드를 호출하고 있는 경우 해당 메소드로 바로 이동하여 구현내역을 확인하고 싶다면 메소드 위에 커서를 옮기고 F3 버튼을 누르면 해당 클래스의 해당 메소드로 이동하게 된다.
그런데 현재 프로젝트와 같이 메소드의 선언부와 구현부가 *Mgr.java와 *MgrImpl.java 형태로 분리되어 있는 경우 F3버튼을 누르면 그냥 *Mgr.java로 이동하기 때문에 실제 구현내역을 확인하는데 애로사항이 있다.
물론 마우스의 ctrl 키를 누른 상태에서 해당 메소드에 커서를 올려두면 Open Declaration과 Open Implementation 중에서 선택해서 바로 이동할 수도 있긴하다.
하지만 키보드를 주로 사용하는 내 경우에는 일일이 마우스에 손을 옮기는게 귀찮아서….키보드 단축키를 아래와 같은 방법으로 등록해서 사용한다.
Window – Preferences – General – Keys 메뉴를 열어서…. Open Implementation 항목을 찾아보면 Binding 부분이 비어있는게 단축키가 설정된게 없음을 확인할 수 있다.
Binding에 커서를 옮기고 Shift + F3을 누르고 적용버튼을 클릭해주면 이후에는 Shift+F3만 누르면 바로 해당 메소드의 구현부로 이동할 수 있다.
아울러 eclipse 안에서 여러개의 파일을 열어서 편집하는 도중에 이전/다음 파일을 오가는 경우 보통 윈도우 환경에서 공통적으로 사용하는 Ctrl + Tab 버튼이 아니라, Ctrl + F6 버튼으로 설정되어 있는데, 같은 방법으로 Next Editor 항목을 찾아서 기존의 설정된 Ctrl + F6을 지우고, Ctrl + Tab으로 변경하여 사용할 수도 있다.
create or replace function func1
return obj_tbl_type1
pipelined
is
v_obj obj_type1;
begin
for idx in 1 .. 100 loop
v_obj := obj_type1(idx, idx);
pipe row(v_obj);
end loop;
end;
/
좀 더 재미있는 테스트를 위해 다음과 같이 Argument를 받는 Function을 생성한다.
create or replace function func2(p1 int, p2 int, p3 int)
return obj_tbl_type1
pipelined
is
v_obj obj_type1;
begin
for idx in 1 .. p3 loop
v_obj := obj_type1(p1+idx, p2+idx);
pipe row(v_obj);
end loop;
end;
/
drop table t1 purge;
create table t1(c1)
as
select level from dual connect by level <= 100
;
이런 방식은 지원되지 않는다.
select *
from t1, table(func2(p1, p2, 10)) x
where t1.c1 = x.c1
;
다음과 같은 문법이 사용된다.
select *
from t1, table(func2(t1.c1, t1.c1, 10))
;
C1 C1 C2
———- ———- ———-
1 2 2
1 3 3
…
즉, t1의 결과가 Function의 인자로 바로 사용된다. 이때 순서가 중요하다.
다음과 같이 순서가 바뀌면 Oracle은 처리하지 못한다.
select *
from table(func2(t1.c1, t1.c1, 10)), t1
;
ERROR at line 2:
ORA-00904: “T1”.”C1″: invalid identifier
이 사실을 응용하면 다음과 같이 자유롭게 Join에 사용할 수 있다.
select *
from
(select null as c1, null as c2 from dual connect by level <= 100) s,
table(func2(s.c1, s.c1, 10))
;
잘 이용하면 매우 강력한 Query를 만들 수 있다.
가령 아래 Query를 보자. Shared Pool(v$sql)에 Cache되어 있는 Query들 중 buffer_gets(logical reads) 수치가 높은 순으로 Runtime 실행 계획을 추출한다. 이런 복잡해 보이는 요구 사항도 Table Function의 Join 기능을 잘 이용하면 매우 간단한게 구현할 수 있다.
select plan_table_output
from
(select * from
(select s.sql_id, s.child_number
from v$sql s
where exists(select 1 from v$sql_plan p where p.plan_hash_value = s.plan_hash_value)
order by s.buffer_gets desc)
where rownum <= 10
) s,
table(dbms_xplan.display_cursor(s.sql_id, s.child_number, ‘allstats last’))
;
(출력 문제로 짤림)
PLAN_TABLE_OUTPUT
——————————————————————————-
SQL_ID 803b7z0t84sq7, child number 0
————————————-
select job, nvl2(last_date, 1, 0) from sys.job$ where (((:1 <= next_date) and (
((last_date is null) and (next_date < :3))) and (field1 = :4 or (field1 = 0 and
(this_date is null) order by next_date, job