동의어 정의문

CREATE SYNONYM

이미 데이터베이스에 존재하는 객체를 사용할 수 있는 또 다른 새로운 이름을 만든다. 사용자는 데이터베이스 객체를 생성할 때 지정한 이름으로 객체를 사용할 수 있고, 동의어로도 객체를 사용할 수 있다.

  1. 사용자는 전용(Private) 동의어만 생성할 수 있으며, 전용(Private) 동의어는 사용자의 스키마에서만 사용할 수 있다.

  2. 생성된 동의어의 정보는 DB_SYNONYM 시스템 가상 클래스에서 조회할 수 있다.

  3. 같은 이름의 테이블이나 뷰가 이미 존재하는 경우 해당 이름으로 동의어를 생성할 수 없다.

  4. 동의어를 생성할 때 대상 객체의 스키마가 존재하는지는 확인하지만 대상 객체가 존재하는지는 확인하지 않는다. 대상 객체가 존재하지 않으면 동의어를 사용할 때 에러가 발생한다.

  5. 사용자는 해당 사용자의 스키마에서만 동의어를 생성할 수 있지만 DBA와 DBA의 멤버는 스키마를 지정해서 동의어를 생성할 수 있다.

CREATE [OR REPLACE] [PRIVATE] SYNONYM [schema_name_of_synonym.]synonym_name
FOR [schema_name_of_target.]target_name
[COMMENT 'synonym_comment_string'] ;
  • OR REPLACE: 스키마에 synonym_name이 이미 존재하더라도 에러를 출력하지 않고 기존의 동의어가 새로운 동의어로 대체된다.

    • 새로운 동의어를 생성하기 전에 기존 동의어는 삭제된다.

  • PRIVATE: 전용(Private) 동의어를 생성하도록 지정한다. 생략해도 기본값으로 전용(Private) 동의어를 생성한다.

  • schema_name_of_synonym: 동의어의 스키마 이름을 지정한다. 생략하면 현재 세션의 스키마 이름을 사용한다.

  • synonym_name: 동의어의 이름을 지정한다.

  • schema_name_of_target: 대상 객체의 스키마 이름을 지정한다. 생략하면 현재 세션의 스키마 이름을 사용한다.

  • target_name: 대상 객체의 이름을 지정한다.

  • synonym_comment_string: 동의어의 커멘트를 지정한다.

Warning

동의어의 대상 객체는 테이블과 뷰만 지원한다. 다른 객체를 대상 객체로 사용할 수는 있지만 동의어를 사용할 때 에러가 발생한다.

Warning

아직은 공용(Public) 동의어를 지원하지 않는다.

1. 전용(Private) 동의어

아래 예제에서 u1 사용자와 u2 사용자는 같은 이름으로 동의어를 생성했지만 다른 대상 객체를 사용한다.

call login ('dba') on class db_user;

/* current_user: dba */
create user u1;
create user u2;

create table t1 (c1 varchar(100));
insert into t1 values ('private synonym for user u1.');
grant select on t1 to u1;
grant select on t1 to u2;

create table t2 (c1 varchar(100));
insert into t2 values ('private synonym for user u2.');
grant select on t2 to u1;
grant select on t2 to u2;
call login ('u1') on class db_user;

/* current_user: u1 */
create synonym s1 for dba.t1;
select * from s1;
  c1
======================
  'private synonym for user u1.'
call login ('u2') on class db_user;

/* current_user: u2 */
create synonym s1 for dba.t2;
select * from s1;
  c1
======================
  'private synonym for user u2.'

2. 동의어 정보

아래 예제에서 사용자는 DB_SYNONYM 시스템 가상 클래스에서 동의어의 정보를 확인할 수 있다.

/* There should be the result of example 1. */

call login ('dba') on class db_user;

/* current_user: dba */
select * from db_synonym;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's1'                  'U1'                  'NO'                  't1'                  'DBA'                 NULL
  's1'                  'U2'                  'NO'                  't2'                  'DBA'                 NULL
call login ('u1') on class db_user;

/* current_user: u1 */
select * from db_synonym;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's1'                  'U1'                  'NO'                  't1'                  'DBA'                 NULL
call login ('u2') on class db_user;

/* current_user: u2 */
select * from db_synonym;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's1'                  'U2'                  'NO'                  't2'                  'DBA'                 NULL
/* clean */

call login ('dba') on class db_user;

/* current_user: dba */
drop synonym if exists u1.s1;
drop synonym if exists u2.s1;
drop user u1;
drop user u2;

drop table if exists t1;
drop table if exists t2;

3. 동의어 이름

같은 이름의 테이블이나 뷰가 이미 존재하는 경우 해당 이름으로 동의어를 생성할 수 없다.

call login ('public') on class db_user;

/* current_user: public */
create table t1 (c1 varchar(100));
insert into t1 values ('table for user public.');

create table s1 (c1 varchar(100));
create view s2 as select * from t1;

/* Already used as a table name. */
create synonym s1 for t1;
ERROR: before ' ; '
Class public.s1 already exists.
/* Already used as a view name. */
create synonym s2 for t1;
ERROR: before ' ; '
Class public.s2 already exists.
create synonym s3 for t1;
select * from s3;
  c1
======================
  'table for user public.'
/* clean */

call login ('public') on class db_user;

/* current_user: public */
drop synonym if exists s1;
drop synonym if exists s2;
drop synonym if exists s3;
drop view if exists s2;
drop table if exists t1;
drop table if exists s1;

4. 동의어에 대한 동의어

동의어를 생성할 때 대상 객체가 존재하는지는 확인하지 않으므로, 사용자가 기존 동의어를 대상 객체로 지정하여 새로운 동의어를 만들 수 있다. 하지만 동의어를 사용할 때 대상 객체인 동의어의 대상 객체를 다시 찾지 않는다.

call login ('public') on class db_user;

/* current_user: public */
create table t1 (c1 varchar(100));
insert into t1 values ('synonym for synonym.');

create synonym s1 for t1;
create synonym s2 for s1;
select * from db_synonym;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's1'                  'PUBLIC'              'NO'                  't1'                  'PUBLIC'              NULL
  's2'                  'PUBLIC'              'NO'                  's1'                  'PUBLIC'              NULL
select * from s2;
ERROR: before ' ; '
Unknown class "public.s1".
select * from s1;
  c1
======================
  'synonym for synonym.'
/* clean */

call login ('public') on class db_user;

/* current_user: public */
drop synonym if exists s1;
drop synonym if exists s2;
drop table if exists t1;

5. 스키마 지정 동의어 생성

DBADBA의 멤버가 스키마를 지정하여 동의어를 생성하면, 동의어는 지정한 스키마에 만들어진다.

call login ('dba') on class db_user;

/* current_user: dba */
create user u1;
create user u2;

create table t1 (c1 varchar(100));
insert into t1 values ('private synonym for user u1.');
grant select on t1 to u1;
grant select on t1 to u2;

create table t2 (c1 varchar(100));
insert into t2 values ('private synonym for user u2.');
grant select on t2 to u1;
grant select on t2 to u2;

create synonym u1.s1 for dba.t1;
create synonym u2.s1 for dba.t2;

select * from db_synonym;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's1'                  'U1'                  'NO'                  't1'                  'DBA'                 NULL
  's1'                  'U2'                  'NO'                  't2'                  'DBA'                 NULL
call login ('u1') on class db_user;

/* current_user: u1 */
select * from s1;
  c1
======================
  'private synonym for user u1.'
call login ('u2') on class db_user;

/* current_user: u2 */
select * from s1;
  c1
======================
  'private synonym for user u2.'

사용자는 해당 사용자의 스키마에서만 동의어를 생성할 수 있다.

call login ('u1') on class db_user;

/* current_user: u1 */
create synonym u2.s2 for dba.t1;
ERROR: before ' ; '
DBA, members of DBA group, and owner can perform CREATE SYNONYM.
/* clean */

call login ('dba') on class db_user;

/* current_user: dba */
drop synonym if exists u1.s1;
drop synonym if exists u2.s1;
drop user u1;
drop user u2;

drop table if exists t1;
drop table if exists t2;

ALTER SYNONYM

동의어의 대상 객체나 커멘트를 변경한다. 사용 중인 동의어는 변경할 수 없다.

ALTER [PRIVATE] SYNONYM [schema_name_of_synonym.]synonym_name
{
    FOR [<schema_name_of_target>.]<target_name> [COMMENT 'comment_string'] |
    COMMENT 'synonym_comment_string'
} ;
  • PRIVATE: 전용(Private) 동의어를 변경하도록 지정한다. 생략해도 기본값으로 전용(Private) 동의어를 생성한다.

  • schema_name_of_synonym: 동의어의 스키마 이름을 지정한다. 생략하면 현재 세션의 스키마 이름을 사용한다.

  • synonym_name: 동의어의 이름을 지정한다.

  • schema_name_of_target: 대상 객체의 스키마 이름을 지정한다. 생략하면 현재 세션의 스키마 이름을 사용한다.

  • target_name: 대상 객체의 이름을 지정한다.

  • synonym_comment_string: 동의어의 커멘트를 지정한다.

Warning

동의어에 대한 ALTER, DROP, RENAME 문이 실행되면 쿼리 계획 캐시에서 대상 객체를 사용하는 쿼리 계획을 모두 삭제하므로 주의해야 한다.

하지만 ALTER 문을 실행할 때 같은 대상 객체로 변경하거나 커멘트만 변경하는 경우에는 쿼리 계획을 삭제하지 않는다.

대상 객체 변경

아래 예제에서 대상 객체를 변경한다.

call login ('public') on class db_user;

/* current_user: public */
create table t1 (c1 varchar(100));
insert into t1 values ('target table before change.');

create table t2 (c1 varchar(100));
insert into t2 values ('target table after change.');

create synonym s1 for t1;
select * from db_synonym;
select * from s1;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's1'                  'PUBLIC'              'NO'                  't1'                  'PUBLIC'              NULL

  c1
======================
  'target table before change.'
alter synonym s1 for t2;
select * from db_synonym;
select * from s1;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's1'                  'PUBLIC'              'NO'                  't2'                  'PUBLIC'              NULL

  c1
======================
  'target table after change.'
/* clean */

call login ('public') on class db_user;

/* current_user: public */
drop synonym if exists s1;
drop table if exists t1;
drop table if exists t2;

커멘트 변경

아래 예제에서 사용자는 동의어의 커멘트를 변경한다.

call login ('public') on class db_user;

/* current_user: public */
create table t1 (c1 varchar(100));
insert into t1 values ('change comment.');

create synonym s1 for t1 comment 'It is a synonym for the t1 table.';
select synonym_name, synonym_owner_name, is_public_synonym, comment from db_synonym;
  synonym_name          synonym_owner_name    is_public_synonym     comment
========================================================================================
  's1'                  'PUBLIC'              'NO'                  'It is a synonym for the t1 table.'

대상 객체를 지정하지 않고 커멘트를 변경할 수 있다.

alter synonym s1 comment 'the comment was changed.';
select synonym_name, synonym_owner_name, is_public_synonym, comment from db_synonym;
  synonym_name          synonym_owner_name    is_public_synonym     comment
========================================================================================
  's1'                  'PUBLIC'              'NO'                  'the comment was changed.'

대상 객체와 커멘트를 모두 지정하지 않으면 에러가 발생한다.

alter synonym s1;
ERROR: No options specified for ALTER SYNONYM.

커멘트를 NULL로 변경하려면, 커멘트를 빈 문자열로 변경하면 된다.

alter synonym s1 comment '';
select synonym_name, synonym_owner_name, is_public_synonym, comment from db_synonym;
  synonym_name          synonym_owner_name    is_public_synonym     comment
========================================================================================
  's1'                  'PUBLIC'              'NO'                  NULL
/* clean */

call login ('public') on class db_user;

/* current_user: public */
drop synonym if exists s1;
drop table if exists t1;

DROP SYNONYM

동의어를 삭제한다. 사용 중인 동의어는 삭제할 수 없다. 동의어를 삭제해도 대상 객체는 삭제되지 않는다.

DROP [PRIVATE] SYNONYM [IF EXISTS] [schema_name.]synonym_name ;
  • PRIVATE: 전용(Private) 동의어를 삭제하도록 지정한다. 생략해도 기본값으로 전용(Private) 동의어를 생성한다.

  • IF EXISTS: 스키마에 synonym_name이 존재하지 않더라도 에러가 발생하지 않는다.

  • schema_name: 동의어의 스키마 이름을 지정한다. 생략하면 현재 세션의 스키마 이름을 사용한다.

  • synonym_name: 동의어의 이름을 지정한다.

Warning

동의어에 대한 ALTER, DROP, RENAME 문이 실행되면 쿼리 계획 캐시에서 대상 객체를 사용하는 쿼리 계획을 모두 삭제하므로 주의해야 한다.

call login ('public') on class db_user;

/* current_user: public */
create table t1 (c1 varchar(100));
insert into t1 values ('The target object of the to-be-deleted synonym.');

create synonym s1 for t1;
select synonym_name, synonym_owner_name, is_public_synonym, comment from db_synonym;
select * from s1;
  synonym_name          synonym_owner_name    is_public_synonym     comment
========================================================================================
  's1'                  'PUBLIC'              'NO'                  NULL

  c1
======================
  'The target object of the to-be-deleted synonym.'
drop synonym s1;
select synonym_name, synonym_owner_name, is_public_synonym, comment from db_synonym;
There are no results.
0 row selected.
select * from s1;
ERROR: before ' ; '
Unknown class "public.s1".
select * from t1;
  c1
======================
  'The target object of the to-be-deleted synonym.'
/* clean */

call login ('public') on class db_user;

/* current_user: public */
drop synonym if exists s1;
drop table if exists t1;

RENAME SYNONYM

동의어의 이름을 변경한다. 사용 중인 동의어의 이름은 변경할 수 없다.

  1. 사용자는 동의어의 이름을 변경하면서 동의어의 스키마를 변경할 수 없다.

  2. 변경하는 이름의 테이블이나 뷰, 동의어가 이미 존재하는 경우 이름을 변경할 수 없다.

RENAME [PRIVATE] SYNONYM [schema_name_of_old_synonym.]old_synonym_name
{AS | TO} [schema_name_of_new_synonym.]new_synonym_name ;
  • PRIVATE: 전용(Private) 동의어를 변경하도록 지정한다. 생략해도 기본값으로 전용(Private) 동의어를 생성한다.

  • schema_name_of_old_synonym: 이름을 바꿀 동의어의 스키마 이름을 지정한다. 생략하면 현재 세션의 스키마 이름을 사용한다.

  • old_synonym_name: 이름을 바꿀 동의어의 이름을 지정한다.

  • schema_name_of_new_synonym: 새로운 이름의 동의어에 대한 스키마 이름을 지정한다. 생략하면 현재 세션의 스키마 이름을 사용한다.

  • new_synonym_name: 동의어의 새로운 이름을 지정한다.

Warning

동의어에 대한 ALTER, DROP, RENAME 문이 실행되면 쿼리 계획 캐시에서 대상 객체를 사용하는 쿼리 계획을 모두 삭제하므로 주의해야 한다.

1. 스키마를 변경할 수 없음

아래 예제에서 rename 시 스키마 이름을 다르게 지정할 때 에러가 발생한다.

call login ('dba') on class db_user;

/* current_user: dba */
create user u1;
create user u2;
call login ('u1') on class db_user;

/* current_user: u1 */
create table t1 (c1 varchar(100));
insert into t1 values ('private synonym for user u1.');

create synonym s1 for t1;
select synonym_name, synonym_owner_name, is_public_synonym, comment from db_synonym;
select * from s1;
  synonym_name          synonym_owner_name    is_public_synonym     comment
========================================================================================
  's1'                  'U1'                  'NO'                  NULL

  c1
======================
  'private synonym for user u1.'
rename synonym s1 as u2.s2;
rename synonym u1.s1 as u2.s2;
ERROR: before ' ; '
Rename cannot change owner.
call login ('dba') on class db_user;

/* current_user: dba */
rename synonym u1.s1 as u2.s2;
ERROR: before ' ; '
Rename cannot change owner.
call login ('u1') on class db_user;

/* current_user: u1 */
rename synonym s1 as s2;
select synonym_name, synonym_owner_name, is_public_synonym, comment from db_synonym;
select * from s2;
  synonym_name          synonym_owner_name    is_public_synonym     comment
========================================================================================
  's2'                  'U1'                  'NO'                  NULL

  c1
======================
  'private synonym for user u1.'
/* clean */

call login ('dba') on class db_user;

/* current_user: dba */
drop synonym if exists u1.s1;
drop synonym if exists u1.s2;
drop synonym if exists u2.s2;
drop table if exists u1.t1;
drop user u1;
drop user u2;

2. 이미 사용 중인 이름

아래 예제에서 변경할 이름이 이미 사용중이기 때문에 에러가 발생한다.

call login ('public') on class db_user;

/* current_user: public */
create table t1 (c1 varchar(100));
insert into t1 values ('first table for user u1.');

create table t2 (c1 varchar(100));
insert into t2 values ('second table for user u1.');

create table s_t1 (c1 varchar(100));
create table s_v1 as select * from t1;
create synonym s_s1 for t2;

create synonym s1 for t1;
select * from db_synonym;
select * from s1;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's_s1'                'PUBLIC'              'NO'                  't2'                  'PUBLIC'              NULL
  's1'                  'PUBLIC'              'NO'                  't1'                  'PUBLIC'              NULL

  c1
======================
  'first table for user u1.'
rename synonym s1 as s_t1;
ERROR: before ' ; '
Class dba.s_t1 already exists.
rename synonym s1 as s_v1;
ERROR: before ' ; '
Class dba.s_v1 already exists.
rename synonym s1 as s_s1;
ERROR: before ' ; '
Synonym "dba.s_s1" already exists.
rename synonym s1 as s2;
select * from db_synonym;
select * from s2;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's_s1'                'PUBLIC'              'NO'                  't2'                  'PUBLIC'              NULL
  's2'                  'PUBLIC'              'NO'                  't1'                  'PUBLIC'              NULL

  c1
======================
  'first table for user u1.'
/* clean */

call login ('public') on class db_user;

/* current_user: public */
drop synonym if exists s1;
drop synonym if exists s2;
drop synonym if exists s_s1;
drop table if exists t1;
drop table if exists t2;
drop table if exists s_t1;
drop table if exists s_v1;

동의어 사용

동의어는 테이블 이름과 뷰 이름을 사용할 수 있는 경우에만 사용할 수 있다.

  1. 동의어를 대상으로 GRANTREVOKE를 할 수 없다. 동의어의 스키마 이름이 지정되면 다른 스키마에 존재하는 동의어도 사용할 수 있다.

  2. 대상 객체를 변경하는 ALTER, DROP, RENAME 문과 TRUNCATE 문에서는 동의어를 사용할 수 없다.

1. 다른 스키마의 동의어 사용

call login ('dba') on class db_user;

/* current_user: dba */
create user u1;
create user u2;
call login ('u1') on class db_user;

/* current_user: u1 */
create table t1 (c1 varchar(100));
insert into t1 values ('first table for user u1.');
grant select on t1 to u2;

create synonym s1 for t1;
select * from s1;
  c1
======================
  'first table for user u1.'
call login ('u2') on class db_user;

/* current_user: u2 */
select * from s1;
select * from u1.s1;
ERROR: before ' ; '
Unknown class "u2.s1".

  c1
======================
  'first table for user u1.'
/* clean */

call login ('dba') on class db_user;

/* current_user: dba */
drop synonym if exists u1.s1;
drop table if exists u1.t1;
drop user u1;
drop user u2;

2. 동의어를 사용할 수 없는 구문

call login ('public') on class db_user;

/* current_user: public */
create table t1 (c1 varchar(100));
insert into t1 values ('first table for user public.');

create synonym s1 for t1;
select * from db_synonym;
select * from s1;
  synonym_name          synonym_owner_name    is_public_synonym     target_name           target_owner_name     comment
====================================================================================================================================
  's1'                  'PUBLIC'              'NO'                  't1'                  'PUBLIC'              NULL

  c1
======================
  'first table for user public.'
alter table s1 add column c2 int;
ERROR: before '  add column c2 int; '
Class public.s1 does not exist.
drop table s1;
ERROR: before ' ; '
Class public.s1 does not exist.
rename table s1 to s2;
ERROR: before ' ; '
Class public.s1 does not exist.
truncate s1;
ERROR: before ' ; '
Class public.s1 does not exist.
select * from s1;
  c1
======================
  'first table for user public.'
/* clean */

call login ('public') on class db_user;

/* current_user: public */
drop synonym if exists s1;
drop table if exists t1;
drop table if exists s2;