Часть 2: создание своими руками |
Часть 1: предопределенные контексты |
Сама садик я садила,
Сама буду поливать,
Сама милого любила,
Сама буду забывать.
Русская народная песня
Для каждого контекста требуется указать специальную «доверительную» программную единицу: процедуру, функцию или пакет. Именно из тела этой программной единицы Oracle разрешит обращаться к процедуре DBMS_SESSION.SET_CONTEXT. Принято такое неочевидное решение во имя безопасности, так как доступ к хранимым программным единицам регулируется уже готовым механизмом привилегий.
Положим, доверительной программной единицей должна быть процедура SET_MYCONTEXT_VALUE:
CONNECT / as sysdba CREATE OR REPLACE CONTEXT mycontext USING set_mycontext_value;
Обратите внимание, что процедура не обязана существовать в момент создания контекста. Но в конце концов ее-таки потребуется создать:
CREATE OR REPLACE PROCEDURE set_mycontext_value ( par IN VARCHAR2 , val IN VARCHAR2 ) AS BEGIN DBMS_SESSION.SET_CONTEXT ( 'mycontext', par, val ); END; / GRANT EXECUTE ON set_mycontext_value TO scott;
Проверка:
SQL> CONNECT scott/tiger
Connected.
SQL> SELECT SYS_CONTEXT ( 'mycontext', 'sesame' ) FROM dual;
SYS_CONTEXT('MYCONTEXT','SESAME')
------------------------------------------------------------
Выше серым фоном выделена пустая строка.
С помощью контекста MYCONTEXT и доступной ему процедуры пользователь SCOTT завел значение, которое сможет читать и переустанавливать в собственном сеансе вплоть до завершения. Другой сеанс пользователя SCOTT создаст и будет использовать с помощью этого же контекста свои значения, то есть значения контекста являются собственностью сеанса.
Значения атрибутов контекста живут не долее пределов сеанса и защищены от доступа из других сеансов. В течение сеанса значения переменных пакета могут пропасть («сброс» пакета, хотя пользователи и нечасто прибегают к нему), и значения атрибутов контекста тоже (с помощью пакета DBMS_SESSION). Этим атрибуты схожи с переменными пакета. Но есть и отличия:
Вот еще пример использования нашего контекста:
SQL> EXECUTE set_mycontext_value -
> ( 'start work', TO_CHAR ( SYSDATE, 'hh24:mi:ss' ) )
PL/SQL procedure successfully completed.
SQL> REMARK выполняем работу, после чего смотрим когда начинали ...
SQL> SELECT SYS_CONTEXT ( 'mycontext', 'start work' ) FROM dual;
SYS_CONTEXT('MYCONTEXT','STARTWORK')
--------------------------------------------------------------------
13:58:06
SQL> SELECT * FROM all_context; NAMESPACE SCHEMA PACKAGE ---------------------- ---------------------- ---------------------- MYCONTEXT SYS SET_CONTEXT_VALUE
Это не случайно: на практике часто более технологично установку контекста выполнять с помощью доверительного пакета, а не самостоятельной процедуры или функции. Ведь в состав пакета можно включить и прочие программные элементы, моделирующие логику предметной области.
Пример:
CONNECT / as sysdba
CREATE OR REPLACE CONTEXT mycontext USING mycontext_pckg;
CREATE OR REPLACE PACKAGE mycontext_pckg IS
PROCEDURE set_value ( par VARCHAR2, val VARCHAR2 );
FUNCTION get_value ( par VARCHAR2 ) RETURN VARCHAR2;
END;
/
CREATE OR REPLACE PACKAGE BODY mycontext_pckg IS
PROCEDURE set_value ( par VARCHAR2, val VARCHAR2 )
IS
BEGIN
DBMS_SESSION.SET_CONTEXT ( 'mycontext', par, val );
END;
FUNCTION get_value ( par VARCHAR2 ) RETURN VARCHAR2
IS
BEGIN
RETURN SYS_CONTEXT ( 'mycontext', par );
END;
END;
/
GRANT EXECUTE ON mycontext_pckg TO scott;
Проверка:
SQL> CONNECT scott/tiger
Connected.
SQL> SELECT sys.mycontext_pckg.get_value ( 'sesame' ) FROM dual;
SYS.MYCONTEXT_PCKG.GET_VALUE('SESAME')
---------------------------------------------------------------------
Пакет можно спроектировать и иначе, закрыв, например, для пользователя имя атрибута или даже контекста. Можно запрограммировать все, что требует логика предметной области.
Возможность таких начальных присвоений обеспечивается соответствующими указаниями при создании контекста:
CREATE CONTEXT ... INITIALIZED EXTERNALLY и CREATE CONTEXT ... INITIALIZED EXTERNALLY
Начальные значения атрибутов контекста для сеансов - очень сильное средство, позволяющее наложить на относительно примитивный механизм внутренних пользователей БД инфраструктуру внешних пользователей, часто более проработанную и универсальную. Например, сервер приложений может поддерживать очень много пользователей web-страниц, обладающих собственными свойствами. Моделировать их отдельными локальными для Oracle пользователями может оказаться крайне неэффективно, и в этом случае возможность предварительного установления атрибутов перед обращением к БД будет давать единственный ключ к построению решения.
CONNECT / AS SYSDBA
CREATE OR REPLACE CONTEXT globalcontext
USING globalcontext_pckg
ACCESSED GLOBALLY
/
CREATE OR REPLACE PACKAGE globalcontext_pckg AS
PROCEDURE set_value (
par VARCHAR2
, val VARCHAR2
, usr VARCHAR2
, usrid VARCHAR2
);
END;
/
CREATE OR REPLACE PACKAGE BODY globalcontext_pckg AS
PROCEDURE set_value (
par VARCHAR2
, val VARCHAR2
, usr VARCHAR2
, usrid VARCHAR2
)
AS
BEGIN
DBMS_SESSION.SET_CONTEXT (
'globalcontext'
, par
, val
, usr
, usrid
);
END;
END;
/
EXECUTE globalcontext_pckg.set_value -
( 'sesame' , '123', 'SCOTT', 'XYZ32A6' )
Проверка:
SQL> CONNECT scott/tiger
Connected.
SQL> SELECT SYS_CONTEXT ( 'globalcontext', 'sesame' ) FROM dual;
SYS_CONTEXT('GLOBALCONTEXT','SESAME')
--------------------------------------------------------------------
Тут есть сразу несколько интересных новшеств.
Таким образом, мало войти в СУБД под «правильным» пользователем; для того, чтобы получить в сеансе значение желаемого атрибута (глобального контекста), нужно будет еще сообщить условную строку. Излишне напоминать, что очевидным кандидатом на такую строку является cookie сеанса общения с web. И только благодаря этому, а также механизму избирательного доступа к частям таблицы в Oracle («виртуальные частные базы данных», VPD/FGAC) и возможности сервера приложений автоматически выдавать SET_IDENTIFIER при обращении к БД, многочисленные пользователи web, формально подключаемые к СУБД под одними и теми же именами пользователей Oracle, смогут увидеть в базе каждый собственные данные.
| Часть 1: предопределенные контексты |