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

1 ... 360 361 362 [ 363 ] 364 365 366 ... 469


Права вызывающего и создателя 1511

цедурных языках программирования), выполняется с привилегиями текущего зарегистрированного пользователя (вызывающего) и разрешением имен в его схеме. Теперь можно писать на PL/SQL код, который ранее приходилось писать на обычных языках программирования вне базы данных.

Когда использовать права вызывающего

В этом разделе мы рассмотрим различные причины и случаи, когда может потребоваться выполнение с правами вызывающего. Мы сконцентрируемся на правах вызывающего, поскольку это новая возможность, пока еще являющаяся исключением. Хранимые процедуры ранее всегда выполнялись сервером Oracle c правами создателя.

Необходимость работать с правами вызывающего чаще всего возникает, когда универсальный фрагмент кода создается одним пользователем, а используется - множеством других. Разработчик не имеет доступа к объектам, к которым будут иметь доступ пользователи. Именно привилегии пользователя будут определять, к каким объектам этот код может обращаться. Другая потенциальная причина использования прав вызывающего - необходимость создать набор процедур, централизованно выбирающих данные из нескольких различных схем. При использовании процедур, работающих с правами создателя, как было показано, привилегии и схема, относительно которой выполняется разрешение имен, - статичны и определяются во время компиляции. При каждом выполнении процедура, работающая с правами создателя, обращается к одному и тому же набору объектов (если, конечно, не используется динамическое формирование SQL-операторов). Работа с правами вызывающего позволяет создать процедуру, способную обращаться к аналогичным структурам в различных схемах, - в зависимости от того, кто ее вызвал.

Давайте рассмотрим ряд типичных случаев, когда используются процедуры с правами вызывающего.

Разработка универсальных утилит

Пусть создается хранимая процедура, использующая динамический SQL для выполнения запроса и вгдачи результатов в виде файла со значениями через запятую. Если не работать с правами вызывающего, эта процедура будет универсальной и полезной всем только при выполнении одного из следующих условий.

Создатель процедуры должен иметь возможность читать любой объект в базе дан-н1х. Например, обладать привилегией SELECT ANY TABLE. B противном случае при запуске этой процедуры для представления данных таблицы в виде текстового файла произойдет ошибка, потому что создатель не имеет необходимой привилегии SELECT для этой таблицы. Надо выполнять эту процедуру с правами вызывающего, а не создателя.

Каждый пользователь должен иметь исходный код и устанавливать его копию в своей схеме. Это нежелательно по очевидным причинам - сопровождение превратится в кошмар. Если будет обнаружена ошибка в исходном коде или вследствие обновления версии придется изменять код, обновлять придется десятки



1512

Глава 23

копий. Кроме того, эта скопированная процедура все равно не сможет обращаться к объектам, доступным пользователю через роль.

Обычно именно второй вариант чаще всего применяется для разработки универсального кода. Этот подход неидеален, но более безопасен с точки зрения защиты данных. Используя работу с правами вызывающего, можно создать процедуру один раз, предоставить права на ее выполнение многим пользователям, и они будут использовать ее со своим набором привилегий и с разрешением имен в своих схемах. Давайте рассмотрим небольшой пример. Мне часто приходится просматривать в среде SQL*Plus слишком Широкие таблицы, имеющие много столбцов. Если просто выполнить SELECT * T для такой таблицы, утилита SQL*Plus будет переносить данные на следующую строку по правому краю окна терминала. Например:

tkyte@DEV816> select * from dba tablespaces where rownum = 1;

TABLESPAGE NAME INITIAL EXTENT NEXT EXTENT MIN EXTENTS

MAX EXTENTS PGT INGREASE MIN EXTLEN STATUS GONTENTS LOGGING EXTENT MAN ALLOGATIO PLU

SYSTEM 163 84 163 84 1

5 05 5 0 0 ONLINE PERMANENT LOGGING

DIGTIONARY USER NO

Полученные данные читать очень неудобно. Вот если бы получать результаты в следующем виде:

tkyte@DEV816> exec print table(select * from dba tablespaces where

-> rownum = 1 ) ;

TABLESPAGE NAME

: SYSTEM

INITIAL EXTENT

: 16384

NEXT EXTENT

: 16384

MIN EXTENTS

: 1

MAX EXTENTS

: 505

PGT INGREASE

: 50

MIN EXTLEN

: 0

STATUS

: ONLINE

GONTENTS

: PERMANENT

LOGGING

: LOGGING

EXTENT MANAGEMENT

: DIGTIONARY

ALLOGATION TYPE

: USER

PLUGGED IN

: NO

PL/SQL procedure successfully completed.

Да, так гораздо лучше! Легко увидеть значение каждого столбца. Увидев резтат: использования моей процедуры PRINT TABLE, все хотят получить ее. Вместо того чтобы давать код, я предлагаю использовать мою, поскольку она создана с конструкцией AUTHID CURRENT USER. Мне не нужен доступ к чужим таблицам. Эта процедура сможет обращаться к ним (даже к тем, которые доступны через роль, - процедуры,



Права в1зывающего и создателя 1513

работающие с правами создателя, не могут этого делать в принципе). Давайте рассмотрим код и разберемся, как он устроен. Начнем с создания служебной учетной записи для хранения этого универсального кода, а также учетной записи, которую мы будем использовать для проверки зашиты:

tkyte@TKYTE816> grant connect to another user identified by another user;

Grant succeeded.

tkyte@TKYTE816> create user utils acct identified by utils acct; User created.

tkyte@TKYTE816> grant create session, create procedure to utils acct; Grant succeeded.

Я создал пользователя с очень ограниченными привилегиями. Их достаточно для того, чтобы зарегистрироваться и создать процедуру. Теперь я создам процедуру в этой схеме:

tkyte@TKYTE816> utils acct/utils acct

utils acct@TKYTE816> create or replace

2 procedure print table(p ery in varchar2)

3 AUTHID CURRENT USER

4 is

5 l theCursor integer default dbms sql.open cursor;

6 l columnValue varchar2(4000);

7 l status integer;

8 l descTbl dbms sql.desc tab;

9 l colCnt number;

10 begin

11 dbms sql.parse(l theCursor, p query, dbms sql.native);

12 dbms sql.describe columns(l theCursor, l colCnt, l descTbl);

14 for i in 1 .. l colCnt loop

15 dbms sql.define column(l theCursor, i, l columnValue, 4000);

16 end loop;

18 l status :=dbms sql.execute(l theCursor);

20 while (dbms sql.fetch rows(l theCursor) >0) loop

21 for i in 1 .. l colCnt loop

22 dbms sql.column value(l theCursor, i, l columnValue);

23 dbms output.put line(rpad(l descTbl(i).col name, 30)

25 l columnValue);

26 end loop;

27 dbms output.put line(- ) ;

28 end loop;

29 exception

30 when others then

31 dbms sql.dose cursor(l theCursor);

32 RAISE;

33 end;



1 ... 360 361 362 [ 363 ] 364 365 366 ... 469

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