1e3a5f4d

Это старое решение, которое давно


Это старое решение, которое давно практикуется в поставках Oracle для организации удобного доступа к таблицам словаря-справочника. В самом деле, известно, что каждый пользователь Oracle, даже при наличии у него всего-навсего привилегии CREATE SESSION, имеет возможность обратиться к примеру, к таблице USER_TABLES, чтобы посмотреть список своих собственных таблиц. Каждый пользователь обращается к одной и той же таблице (USER_TABLES), но видит в ней только свои данные.
Строго говоря, в прозвучавшей только что формулировке кроется подлог: реально USER_TABLES – это выводимая таблица (view) в схеме SYS, в определении которой присутствует ссылка на имя текущего пользователя, и для которой создан одноименный публичный (PUBLIC, то есть общедоступный) синоним. От этого-то синонима, для которого не требуется уточнения имени владельца (согласно общему правилу ссылки на небольшое количество «общесистемных» объектов, не принадлежащих никакой одной схеме), и разворачивается запрос к реальным таблицам словаря-справочника при обращении конкретного пользователя Oracle к USER_TABLES.
Как эта механика оформлена, желающие могут подсмотреть в файле-сценарии $ORACLE_HOME/rdbms/admin/catalog.sql. Он запускается (автоматически, вручную ли) при заведении базы данных почти любой конфигурации (за исключением вариантов typical и наиболее типичных в версии 10, где БД заводится не прогоном команд SQL, а копированием готовых образов с установочного клмплекта дисков). Для нашего примера эта механика будет выглядеть так.
Зайдем для начала в систему от имени SYS и заведем пользователя ALLEN:
CONNECT / AS SYSDBA (в версиях 8, 7 лучше CONNECT INTERNAL)
CREATE USER ALLEN IDENTIFIED BY ALLEN;
GRANT CREATE SESSION TO ALLEN;
Тут же, заодно, выдадим право пользователю SCOTT создавать публичные синонимы, так как изначально этого права у него нет:
GRANT CREATE PUBLIC SYNONYM TO SCOTT;
Теперь войдем как SCOTT:
CONNECT scott/tiger
CREATE VIEW emps AS SELECT * FROM emp WHERE deptno = (SELECT deptno FROM emp WHERE ename = USER);


Выше решение № 1 было названо «правильным». Почему ? Дело в том, что оно базируется на использовании выводимых таблиц, views, которые были придуманы еще в реляционной модели (приведшей к появлению SQL) как раз для целей разграничения видимости общих данных разными приложениями (у views есть и иное предназначение, для темы этой статьи несущественное). То есть оно правильно с точки зрения старой реляционной модели.
Это «правильное» решение, однако, как и многие другие «правильные решения» не всегда оказывается эффективным или удобным на практике (только не надо последним тезисом злоупотреблять !) Иногда разработчику приложения может оказаться удобным при обращении к одной и той же таблице в течение одного и того же сеанса давать возможность предъявлять разные данные. Иногда одни и те же данные таблицы желательно предъявлять группам приложений (сеансов, пользователей). Техника использования views в таких случаях может оказаться недостаточно гибка или экономна; ей приходится искать замену.
Итак, другой способ решения нашей конкретной задачи – воспользоваться системным пакетом DBMS_RLS, поставляемым в версиях Oracle Enterprise Edition.
Он более трудоемок, и о нем будет рассказано в .


CREATE PUBLIC SYNONYM emps FOR emps;


GRANT SELECT ON emps TO allen;
А теперь проверка:
SQL> SELECT ename FROM emps;
ENAME

----------

SMITH

JONES

SCOTT

ADAMS

FORD

5 rows selected.
А вот, что увидит ALLEN:
SQL> CONNECT allen/allen
SQL> SELECT ename FROM emps;
ENAME

----------

ALLEN

WARD

MARTIN

BLAKE

TURNER

JAMES
6 rows selected.
Замечание. При создании выводимой таблицы EMPS молчаливо подразумевалось, что в EMP имя сотрудника уникально. В существующих данных это действительно так, но в описании таблицы это обстоятельство никак не обозначено, так что при обращение к EMPS при других данных мы рискуем получить ошибку. Здесь мы закрываем на это глаза, но в промышленных системах к формулировке схемы (таблиц базовых и выводимых) нужно подходить более тщательно: в нашем случае или сделать поле EMP.ENAME уникальным, или же заменить формулировку EMPS, убрав оттуда вложенный запрос и применив соединение.

Содержание раздела