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

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


1544 Глава 23

8 end loop;

9 end; 10 /

PL/SQL procedure successfully completed.

и в отчете TKPROF увидим:

OVERALL TOTALS FOR ALL REGURSIVE STATEMENTS

call

count

elapsed

disk.

query

current

rows

Parse

0.74

0.53

Execute

0.09

0.31

Fetch

0.08

0.04

total

1643

0.91

0.88

Misses in library cache during parse: 22

504 user SQL statements in session.

114 internal SQL statements in session.

618 SQL statements in session.

0 statements EXPLAINed in this session.

Разница огромна. Для анализа 500 уникальных операторов (эмулирующих поведение процедуры с правами вызывающего, которая обращается при каждом вызове к другой таблице) требуется 17,95 секунд процессорного времени. Для анализа же 500 одинаковых операторов (эмулирующих использование стандартной процедуры с правами создателя) понадобилось 0,74 секунды процессорного времени. В 24 раза меньше!

Конечно, это надо учитывать. Когда SQL-операторы не используются повторно, система может тратить больше времени на анализ запросов, чем на их фактическое выполнение. Причины этого б1ли рассмотрены в главе 10, посвященной стратегиям и средствам настройки производительности. Там я продемонстрировал необходимость использования связываемых переменных для повторного использования планов запросов.

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

Более надежный код для обработки ошибок

При создании хранимой процедуры со следующим кодом:

begin

for x in (select pk from t) loop

update y set c - c+0.5 where d = x.pk;

end loop;

end;

вполне можно быть уверенным, что при отсутствии синтаксических и семантических ошибок (компилируется успешно) она будет работать. При использовании процедур с



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

правами создателя это верно. Я точно знаю, что объекты (таблицы или представления) T и Y существуют, что T доступен для чтения, a Y можно изменять.

При использовании процедуры с правами вызывающего, ни в чем нельзя быть уверенным. Существует ли объект T, и если - да, то имеется ли в нем столбец с именем PK? И имею ли я для него привилегию SELECT? А если имею, то не через роль ли она получена? Ведь тогда при вызове процедуры из подпрограммы с правами создателя, она не сработает, хотя при непосредственном вызове будет работать прекрасно. Существует ли объект Y? И так далее. Другими словами, все условия, которые раньше можно было считать гарантированно выполненными, вызывают сомнению в процедурах с правами вызывающего. Так что, хотя процедуры с правами вызывающего и открывают новые возможности программирования, в некотором отношении они его усложняют.

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

объекта T нет;

объект T есть, но нет необходимых для доступа к нему привилегий;

объект T есть, но в нем нет столбца PK;

объект T существует и имеет столбец PK, но тип данных столбца отличается от использованного при компиляции;

все то же в отношении объекта Y.

Поскольку изменение объекта Y происходит только при получении определенных данных из T, мы можем многократно успешно выполнить эту процедуру, но однажды, когда в T будут помещены данные, процедура не сработает. Мы никогда не могли обратиться к объекту Y, но процедура не сработала потому, что мы впервые попытались . Ошибка во фрагменте кода произойдет только тогда, когда он выполнится.

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

create or replace procedure P

authid current user

no such table exception;

pragma exception init(no such table,-942); insufficient privs exception;

pragma exception init(insufficient privs,-1031); invalid column name exception;

pragma exception init(invalid column name,-904); inconsistent datatypes exception;

pragma exception init(inconsistent datatypes,-932); begin

for x in (select pk from t) loop

update y set c = c+0.5 where d = x.pk; end loop; exception

when NO SUCH TABLE then

dbms output.put line(Перехвачена ошибка: sqlerrm);



1546

Глава 23

when INSUFFIGIENT PRIVS then

dbms output.put line(Перехвaченa ошибка: sqlerrm);

When INVALID GOLUMN NAME then

dbms output.put line(Перехвaченa обка: sqlerrm);

when INGONSISTENT DATATYPES then

dbms output.put line(Перехвaченa ошибка: sqlerrm);

(дальше идет множество других обработчиков ошибок).. .

end;

Побочные эффекты использования SELECT *

Использование конструкции SELECT * в PL/SQL-процедуре с правами выз1ваю-щего, обращающейся к разным таблицам при вызове разными пользователями, может быть очень опасно. При этом данные могут быть получены поврежденными или в другом порядке. Причина в том, что запись, в которую выполняется выборка данных, настраивается при компиляции, а не при выполнении. Поэтому список столбцов для PL/SQL-объектов (записей) вместо * формируется при компиляции, а данные получаются при в1полнении запроса. Если в другой схеме имеется объект с тем же именем, но с другим порядком столбцов и к нему обращаются из процедуры с правами вызывающего с помощью оператора SELECT *, возникает именно такой побочный эффект:

tkyte@TKYTE816> create table t (msg varchar2(25), c1 int, c2 int); Table created.

tkyte@TKYTE816> insert into t

1 row created.

values (c1=l, c2=2, 1, 2);

tkyte@TKYTE816> create or replace procedure P

2 authid current user

3 as

4 begin

5 for x in (select * from t) loop

6 dbms output.put line(msg=

7 dbms output.put line(G1 =

8 dbms output.put line(G2 =

9 end loop;

10 end;

11 /

Procedure created.

tkyte@TKYTE816> exec p

msg= cl=l, c2=2 G1 = 1 G2 = 2

PL/SQL procedure successfully completed.

tkyte@TKYTE816> grant execute on P to u1;

Grant succeeded.

x.msg);

x.cl);

x.c2);



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

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