|
Программирование >> Oracle
Тщательный контроль доступа 1473 с запросом и как это происходит при использовании различных сред: PL/SQL, Pro*C, OCI, JDBC, ODBC и т.д. Предположим, имеется следующая функция, возвращающая условие: SQL> create or replace function rls examp 2 (p schema in varchar2, p object in varchar2) 3 return varchar2 4 as 5 begin 6 if (sys context(myctx, x) is not null) 7 then 8 return x > 0; 9 else 10 return l=0 ; 11 end if; 12 end; 13 / Function created. Она реализует такой алгоритм: если в контексте установлен атрибут x, возвращается условие x > 0; если же в контексте атрибут x не установлен, возвращается условие 1 = 0. создать таблицу T, поместить в нее данные и добавить правила и контекст следующим образом: SQL> create table t (x int); Table created. SQL> insert into t values (1234); 1 row created. SQL> begin 2 dbms rls.add policy 3 (object schema => user, 4 object name => T, 5 policy name => T POLICY, 6 function schema => user, 7 policy function => rls examp, 8 statement types => select); 9 end; 10 / PL/SQL procedure successfully completed. SQL> create or replace procedure set ctx(p val in varchar2) 2 as 3 begin 4 dbms session.set context(myctx, x, p val); 5 end; Procedure created. SQL> create or replace context myctx using set ctx; Context created. 1474 Глава 21 Предполагается, что в случае установки контекста мы должны получить одну строку. Если же контекст не установлен, мы ни одной строки получить не должны. Если проверить это в среде SQL*Plus с помощью простых SQL-операторов, именно так и окажется: SQL> exec set ctx(null); PL/SQL procedure successfully completed. SQL> select * from t; no rows selected SQL> exec set ctx(1); PL/SQL procedure successfully completed. SQL> select * from t; 1234 Итак, казалось бы, все в порядке. Динамически формируемое условие применяется так, как предполагалось. Фактически же, если использовать язык PL/SQL (или Pro*C, или правильно написанное приложение, использующее интерфейсы OCI/JDBC/ODBC, да и многие другие среды), оказывается, что это не так. Создадим, например, небольшую PL/SQL-процедуру: SQL> create or replace procedure dump t 10 11 12 13 14 15 -> * 18 19 20 21 in number default NULL) (some input begin dbms output.put line С** Результат выполнения оператора SELEGT for x in (select * from t) loop dbms output.put line(x.x); end loop; FROM T); if (some input then is not null) FROM T); dbms output.put line Результат выполнения другого оператора for x in (select * from t) loop dbms output.put line(x.x); end loop; SELEGT end if; end; Procedure created. Эта процедура выполняет оператор SELECT * FROM T один раз, если входные данные не переданы, и два раза, если переданы какие-либо входные данные. Выполним эту Тщательный контроль доступа 1475 процедуру и посмотрим результаты. Выполнение процедуры начнем, установив в контексте значение Null (поэтому будет применяться условие 1-0, другими словами, не будет возвращена ни одна строка): ;L> set serveroutput on exec set ctx(NULL) PL/SQL procedure successfully completed. SQL> exec dump t *** Результат выполнения оператора SELECT * FROM T PL/SQL procedure successfully completed. Как и ожидалось, данные не получены. Теперь установим значение в контексте так, чтобы возвращалось условие x > 0. Затем вызовем процедуру DUMP T так, чтобы она выполняла оба запроса. В версиях Oracle 8.1.5 и 8.1.6 при этом произойдет следующее: SQL> exec set ctx(l) PL/SQL procedure successfully completed. SQL> exec dump t(0) *** Результат выполнения оператора SELECT * FROM Т *** Результат выполнения другого оператора SELECT * FROM T 1234 PL/SQL procedure successfully completed. Перв1й запрос, первоначально выполненный при значении Null в контексте, по-прежнему не возвращает данн1х. Его курсор б1л сохранен в кэше и повторно не анализировался. При выполнении процедуры со значением Null атрибута x в контексте, получаем предполагаемые результаты (потому что это было первое выполнение данной процедуры в сеансе). Устанавливаем атрибуту x непустое значение и получаем неоднозначные резтатт Первый оператор SELECT * FROM T в процедуре по-прежнему не возвращает ни одной строки - он, видимо, продолжает использовать условие 1=0. Второй запрос (который первый раз мы не выполняли) возвращает, как и предполагалось, пра-вильн1е результаты. Он использует условие x > 0, как и было задумано. Почему первый оператор SELECT в этой процедуре не использует условие, которое мы предполагали? Это связано с оптимизацией, называемой кэшированием курсора. Язык PL/SQL и многие другие среды выполнения не закрывают курсор, когда этого требует разработчик. Представленный пример можно легко воспроизвести в Pro*C, если оставить опции прекомпилятора release cursor стандартное значение NO. Если тот же код обработать с опцией release cursor=YES, программа Pro*C будет работать аналогично запросам в среде SQL*Plus. Условие, используемое пакетом DBMS RLS, связывается с запросом на стадии анализа. Первый запрос SELECT * FROM T анализируется при первом выполнении хранимой процедуры, когда фактически возвращалось условие 1=0. PL/SQL-машина автоматически кэширует проанализированный курсор. При втором выполнении хранимой процедуры PL/SQL-машина повторно использует проанализированный курсор первого запроса SELECT * FROM T. Этот проанализированный курсор
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |