|
Программирование >> Oracle
Права вызывающего и создателя 1547 Итак, мы создали процедуру, показывающую содержимое таблицы Т. Значение которое она выдает в столбце MSG, я использую, чтобы продемонстрировать предполага-емгй ответ. Кроме того, она выдает значения столбцов C1 и C2. Все просто и понятно. Теперь давайте посмотрим, что произойдет, если выполнить процедуру от имени другого пользователя, со своей собственной таблицей T: tkyte@TKYTE816> ©connectul/pw ul@TKYTE816> drop table t; Table dropped. ul@TKYTE816> create table t (msg varchar2(25) , c2 int, c1 int) ; Table created. ul@TKYTE816> insert into t values (cl=2, c2 = l, 1, 2); 1 row created. Обратите внимание, что при создании таблицы я изменил порядок столбцов C1 и C2. Здесь я предполагаю, что C1 = 2 и C2 = 1. При выполнении процедуры, однако, получаем следующее: ul@TKYTE816> exec tkyte.p msg= cl=2, c2=l C1 = 1 C2 = 2 PL/SQL procedure successfully completed. Не совсем так, как ожидалось, но если вдуматься глубже... При компиляции была автоматически создана неявная запись X. Запись X - это просто структура данных с тремя элементами - MSG VARCHAR2, C1 NUMBER и C2 NUMBER. Когда список столбцов SELECT * формировался на этапе анализа запроса от имени пользователя TKYTE, были получены столбцы MSG, C1 и C2 (именно в таком порядке). При выполнении процедуры пользователем U1 были, однако, получены столбцы MSG, C2 и C1. Поскольку все типы данных совпадают с типами полей неявно созданной записи X, мы не получили сообщения об ошибке INCONSISTENT DATATYPE (это тоже могло произойти, если бы типы данных оказались несовместимыми, с точностью до неявного преобразования). Данные были успешно выбраны, но значение столбца C2 помещено в поле записи C1. Это вполне предсказуемый побочный эффект и еще одна причина не использовать операторы SELECT * в производственном коде. Помните о скрытых столбцах Это очень похоже на представленную ранее проблему SELECT *. Она тоже связана с тем, как компилируется PL/SQL-процедура с правами вызывающего и как разрешаются имена и ссглки на объекты. Рассмотрим оператор UPDATE, который при выполнении непосредственно в среде SQL*Plus даст другой результат, чем при выполнении в подпрограмме с правами вызывающего. Он работает правильно в обеих средах, просто - по-разному. Когда PL/SQL-код компилируется в базе данных, каждый статический SQL-опера-тор анализируется и уточняются все идентификаторы. Эти идентификаторы могут быть 1548 Глава 23 именами столбцов или именами PL/SQL-переменных (связываемых переменных). ли это имена столбцов, они оставляются в запросе без изменений. Если же это имена переменных PL/SQL, они заменяются в запросе ссылкой :BIND VARIABLE. Эта замена производится при компиляции, а не при выполнении. Рассмотрим пример: tkyte@TKYTE816> create table t (cl int) ; Table created. tkyte@TKYTE816> insert into t values (1); 1 row created. tkyte@TKYTE816> create or replace procedure P 2 authid current user 3 as 4 c2 number default 5; 5 begin 6 update t set cl = c2; 7 end; Procedure created. tkyte@TKYTE816> exec p PL/SQL procedure successfully completed. tkyte@TKYTE816> select * from t; tkyte@TKYTE816> grant execute on P to ul; Grant succeeded. Пока все выглядит нормально. C1 - это столбец в таблице T, a C2 - переменная PL/SQL. Оператор UPDATE T SET C1 = C2 обрабатывается сервером при компиляции и преобразуется в UPDATE T SET C1 = :BIND VARIABLE, а значение :BIND VARIABLE передается при выполнении. Теперь, если зарегистрироваться как U1, и создать в этой схеме таблицу T: tkyte@TKYTE816> connect ul/pw ui@TKYTE816> drop table t; Table dropped. ul@TKYTE816> create table t (cl int, c2 int) ; Table created. ul@TKYTE816> insert into t values (1, 2) ; 1 row created. ul@TKYTE816> exec tkyte.p PL/SQL procedure successfully completed. ul@TKYTE816> select * from t; Права в1зывающего и создателя 1549 C1 C2 Это может показаться правильным или неправильным - смотря как к этому подойти. Мы выполнили оператор UPDATE T SET C1 = C2, но если бы мы это сделали в командной строке SQL*Plus, то столбец C1 получил бы значение 2, а не 5. Однако, поскольку сервер переписал этот запрос при перекомпиляции так, что в нем не осталось ссылок на C2, он делает то же самое с нашим экземпляром T, что и с другим экземпляром T: устанавливает столбцу C1 значение 5. Эта PL/SQL-процедура не может видеть столбец C2, поскольку C2 не существует в объекте, с которым она была скомпилирована. Сначала это кажется странным, поскольку оператора UPDATE в переписанном виде мы обычно не видим, но если вы знаете об этом, результат становится вполне объясни-м1м. Java и права вызывающего PL/SQL-процедуры по умолчанию компилируются с правами создателя. Чтобы такая процедура работала с правами вызывающего, надо это специально указать. Java-процедура по умолчанию работает с правами вызывающего. Если необходимо, чтобы она выполнялась с правами создателя, надо явно указать это при загрузке. В качестве примера я создал таблицу T, такую, что: ops$tkyte@DEV816> create table t (msg varchar2(5 0)); Table created. ops$tkyte@DEV816> insert into t values (Зто таблица Т, принадлежащая -> пользователю user) ; 1 row created. Я также создал и загрузил две хранимые процедуры на Java (для выполнения этого примера необходима привилегия CREATE PUBLIC SYNONYM). Эти хранимые процедуры на Java очень похожи на рассмотренные ранее примеры PL/SQL. Они обращаются к таблице T, которая содержит строку, со сведениями о том, кому принадлежит эта таблица, и выдают информацию о пользователе сеанса, о текущем пользователе (схеме, определяющей привилегии) и текущей схеме: tkyte@TKYTE816>host type ir java.java import java.sql.*; import oracle.jdbc.driver.*; public class ir java public static void test() throws SQLException Connectioncnx = new OracleDriver().defaultConnection() ; String sql = SELECT MSG, sys context(userenv,session user), + sys context(userenv,current user), +
|
© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |