Программирование >>  Oracle 

1 ... 372 373 374 [ 375 ] 376 377 378 ... 469


Права вызывающего и создателя 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), +



1 ... 372 373 374 [ 375 ] 376 377 378 ... 469

© 2006 - 2025 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика