DeepEdit!

Программирование баз данных на Oracle, техническая документация, литература, статьи и публикации

  • Увеличить размер шрифта
  • Размер шрифта по умолчанию
  • Уменьшить размер шрифта

Контекст сеанса в Oracle


Аннотация
В каждом сеансе работы с СУБД можно использовать так называемые контексты, формально представляющие собой именованный набор пар "параметр/значение". Контексты сеансов обладают рядом интересных свойств, существенно повышающих "внутренние" возможности Oracle по созданию приложений. В статье рассматриваются два предопределенных контекста Oracle: USERENV и CLIENTCONTEXT. 
Введение
В каждом сеансе работы с СУБД можно использовать так называемые контексты. Каждый контекст - это именованный набор пар "параметр/значение". Oracle называет каждый конкретный подобный набор пространством имен (namespace), а элементы пространства имен атрибутами, способными принимать значения. 
Создаются контексты SQL-предложением CREATE CONTEXT. Из-за этого далее вместо "пространства имен" предпочтение отдается термину "контекст". Параметры контекста ("атрибуты") устанавливаются процедурой DBMS_SESSION.SET_CONTEXT, а вот вычитываются в программу стандартной функцией SYS_CONTEXT. Пакет DBMS_SESSION содержит ряд других подпрограмм для работы с контекстами. 
Здесь рассматривается лишь формальная сторона контекста сеанса, а способ его применения разработчик может определить сам или почерпнуть из описаний избирательного доступа к данным (FGAC или Label Security) и сервера приложений Oracle. 
Готовый справочный контекст сеанса USERENV
Один контекст, с названием USERENV, создавать явным образом не требуется. Он доступен любому сеансу связи с СУБД Oracle в виде готового набора значений, разрешающего только прочтение, но не правку. Он позволяет узнать всевозможные сведения о сеансе, полезные для прикладного программирования. Ранее в Oracle существовала одноименная функция, но сейчас она поддерживается ради старых программ. 
Пример информации, которую можно получить из контекста USERENV в программу:
COLUMN authent FORMAT A10
COLUMN curr_schema FORMAT A10
COLUMN curr_user FORMAT A10
COLUMN db_name FORMAT A10
COLUMN db_domain FORMAT A10
COLUMN host FORMAT A15
COLUMN ip_address FORMAT A15
COLUMN os_user FORMAT A15

SELECT 
 SYS_CONTEXT ( "userenv", "AUTHENTICATION_TYPE" ) authent
, SYS_CONTEXT ( "userenv", "CURRENT_SCHEMA" ) curr_schema
, SYS_CONTEXT ( "userenv", "CURRENT_USER" ) curr_user
, SYS_CONTEXT ( "userenv", "DB_NAME" ) db_name
, SYS_CONTEXT ( "userenv", "DB_DOMAIN" ) db_domain
, SYS_CONTEXT ( "userenv", "HOST" ) host
, SYS_CONTEXT ( "userenv", "IP_ADDRESS" ) ip_address
, SYS_CONTEXT ( "userenv", "OS_USER" ) os_user
FROM dual
;
Полный список атрибутов контекста USERENV можно узнать из документации (в справочнике по SQL, в разделе, посвященному функции SYS_CONTEXT). 
Вот, пример, как сведения из этого контекста помогают различить разные условия употребления конкретной программы:
CONNECT scott/tiger

CREATE PROCEDURE whoowns 
AS
BEGIN
DBMS_OUTPUT.PUT_LINE ( SYS_CONTEXT ( "userenv", "CURRENT_SCHEMA" ) );
DBMS_OUTPUT.PUT_LINE ( SYS_CONTEXT ( "userenv", "CURRENT_USER" ) );
DBMS_OUTPUT.PUT_LINE ( user );
END;
/
Проверка:
SQL> SET SERVEROUTPUT ON
SQL> EXECUTE whoowns
SCOTT
SCOTT
SCOTT

PL/SQL procedure successfully completed.

SQL> ALTER SESSION SET CURRENT_SCHEMA = system;

Session altered.

SQL> EXECUTE scott.whoowns
SCOTT
SCOTT
SCOTT

PL/SQL procedure successfully completed.

SQL> CONNECT / as sysdba
Connected.
SQL> SET SERVEROUTPUT ON
SQL> EXECUTE scott.whoowns
SCOTT
SCOTT
SYS

PL/SQL procedure successfully completed.
Перетранслируем процедуру для работы с правами запускающего:
CONNECT scott/tiger

CREATE OR REPLACE PROCEDURE whoowns
AUTHID CURRENT_USER
AS
BEGIN
DBMS_OUTPUT.PUT_LINE ( SYS_CONTEXT ( "userenv", "CURRENT_SCHEMA" ) );
DBMS_OUTPUT.PUT_LINE ( SYS_CONTEXT ( "userenv", "CURRENT_USER" ) );
DBMS_OUTPUT.PUT_LINE ( user );
END;
/
Снова проверка:
SQL> SET SERVEROUTPUT ON
SQL> EXECUTE whoowns
SCOTT
SCOTT
SCOTT

PL/SQL procedure successfully completed.

SQL> ALTER SESSION SET CURRENT_SCHEMA = system;

Session altered.

SQL> EXECUTE scott.whoowns
SYSTEM
SCOTT
SCOTT

PL/SQL procedure successfully completed.

SQL> CONNECT / as sysdba
Connected.
SQL> SET SERVEROUTPUT ON
SQL> EXECUTE scott.whoowns
SYS
SYS
SYS

PL/SQL procedure successfully completed.

SQL> ALTER SESSION SET CURRENT_SCHEMA = system;

Session altered.

SQL> EXECUTE scott.whoowns
SYSTEM
SYS
SYS
Примеры поясняют отличие атрибутов CURRENT_SCHEMA и CURRENT_USER контекста USERENV друг от друга и от системной переменной USER. 
Готовый изменяемый контекст сеанса CLIENTCONTEXT
Еще один предопределенный контекст, с именем CLIENTCONTEXT, также не требует специального создания, однако в отличие от USERENV он позволяет сеансу создавать собственные атрибуты и задавать им значения. Особенность этого контекста в том, что он, в дополнение к обычному способу (изнутри сеанса), позволяет устанавливать значения атрибутам заранее, при открытии соединения с СУБД клиентской программой, и передавать их для обработки в сеанс. Делается это 
либо через библиотеку OCI с помощью специального вызова OCIAppCtxSet 
либо из программы на Java с помощью методов класса oracle.jdbc.internal.OracleConnection
Значения переданных в сеанс атрибутов контекста CLIENTCONTEXT можно читать как обычно функцией SYS_CONTEXT, и изменять, но можно заводить и новые атрибуты:
SQL> CONNECT scott/tiger
Connected.
SQL> EXECUTE DBMS_SESSION.SET_CONTEXT ( "CLIENTCONTEXT", "a", "b" )

PL/SQL procedure successfully completed.

SQL> SELECT SYS_CONTEXT ("CLIENTCONTEXT", "a" ) FROM dual;

SYS_CONTEXT("CLIENTCONTEXT","A")
--------------------------------------------------------------------

Если бы атрибут A был установлен клиентской программой на C или на Java перед установлением соединения, значение B мы бы увидели сразу. 
Второе отличительное свойство контекста CLIENTCONTEXT в том, что Oracle разрешает именно для него обращаться к DBMS_SESSION.SET_CONTEXT напрямую (см. выше). Это исключение: контексты, которые разработчик пожелает создавать сам, позволят обращаться к DBMS_SESSION.SET_CONTEXT только из текста своей доверительной программной единицы. 

Создаваемый контекст сеанса
Для самостоятельного создания контекста служит специальная команда CREATE CONTEXT. Выдать ее (то есть создать контекст) может сеанс, имеющий полномочие CREATE ANY CONTEXT. Слово ANY в названии полномочия (привилегии) свидетельствует о том, что контекст - внесхемный объект в БД Oracle, такой, например, как роль, и отличный, например, от таблицы. 
Для каждого контекста требуется указать специальную "доверительную" программную единицу: процедуру, функцию или пакет. Именно из тела этой программной единицы 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")
------------------------------------------------------------
 

SQL> EXECUTE sys.set_mycontext_value ( "sesame", "123" )

PL/SQL procedure successfully completed.

SQL> SELECT SYS_CONTEXT ( "mycontext", "sesame" ) FROM dual;

SYS_CONTEXT("MYCONTEXT","SESAME")
------------------------------------------------------------
123
Выше серым фоном выделена пустая строка. 
С помощью контекста 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
Вариация в технологии: использование доверительного пакета
Если запросить структуру справочной таблицы доступных контекстов, то видно, что поле для доверительной программной единицы названо PACKAGE:
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")
---------------------------------------------------------------------
 

SQL> EXECUTE sys.mycontext_pckg.set_value ( "sesame", "123" )

PL/SQL procedure successfully completed.

SQL> SELECT sys.mycontext_pckg.get_value ( "sesame" ) FROM dual;

SYS.MYCONTEXT_PCKG.GET_VALUE("SESAME")
---------------------------------------------------------------------
123
Пакет можно спроектировать и иначе, закрыв, например, для пользователя имя атрибута или даже контекста. Можно запрограммировать все, что требует логика предметной области. 
Начальные значения атрибутов контекста
Выше было показано, как атрибуты контекстов выставляются в процессе сеанса связи с СУБД. Однако по подобию с CLIENTCONTEXT создаваемый контекст тоже можно обеспечить начальными значениями требуемых атрибутов из программы, открывающий сеанс. Это можно сделать: 
средствами OCI (вызовы OCIAttrSet и OCISessionBegin) и 
через сервер имен (каталог) LDAP. 
Возможность таких начальных присвоений обеспечивается соответствующими указаниями при создании контекста: 
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")
--------------------------------------------------------------------
 

SQL> EXECUTE DBMS_SESSION.SET_IDENTIFIER ( "XYZ32A6" );

PL/SQL procedure successfully completed.

SQL> SELECT SYS_CONTEXT ( "globalcontext", "sesame" ) FROM dual;

SYS_CONTEXT("GLOBALCONTEXT","SESAME")
--------------------------------------------------------------------
123

SQL> EXECUTE DBMS_SESSION.SET_IDENTIFIER ( "XYZ32A6ZZZ" );

PL/SQL procedure successfully completed.

SQL> SELECT SYS_CONTEXT ( "globalcontext", "sesame" ) FROM dual;

SYS_CONTEXT("GLOBALCONTEXT","SESAME")
----------------------------------------------------------------------
 
Тут есть сразу несколько интересных новшеств. 

То, что контекст глобальный, было указано словами ACCESSED GLOBALLY при его создании. 

В процедуре DBMS_SESSION.SET_CONTEXT именно для глобального контекста существуют два дополнительных параметра. Первый сообщает, сеансам чьего пользователя будет доступен этот контекст (для каждого такого пользователя нужно будет выполнить отдельный вызов SET_CONTEXT), а второй - условное значение, которое необходимо будет сообщить для возможности прочитать установленное другим сеансом значения атрибута, своего рода пароль. 

Сообщение этого условного значения выполняется специальной процедурой DBMS_SESSION.SET_IDENTIFIER. 

Таким образом, мало войти в СУБД под "правильным" пользователем; для того, чтобы получить в сеансе значение желаемого атрибута (глобального контекста), нужно будет еще сообщить условную строку. Излишне напоминать, что очевидным кандидатом на такую строку является cookie сеанса общения с web. И только благодаря этому, а также механизму избирательного доступа к частям таблицы в Oracle ("виртуальные частные базы данных", VPD/FGAC) и возможности сервера приложений автоматически выдавать SET_IDENTIFIER при обращении к БД, многочисленные пользователи web, формально подключаемые к СУБД под одними и теми же именами пользователей Oracle, смогут увидеть в базе каждый собственные данные. 


 


коттеджный посёлок . купить дипломный проект







jAntivirus