Oracle для профессионалов

         

Выполнение команды ОС


Если бы я получал десятицентовую монету всякий раз, отвечая на вопрос о том, как выполнить команду ОС! До появления поддержки языка Java в СУБД, это действительно было сложно. Теперь же это почти тривиально. Есть, вероятно, сотни способов сделать это, но следующий фрагмент кода работает вполне удовлетворительно:

tkyte@TKYTE816> create or replace and compile 2 java source named "Util" 3 as 4 import java.io.*; 5 import java.lang.*; 6 7 public class Util extends Object 8 { 9 10 public static int RunThis(String[] args) 11 { 12 Runtime rt = Runtime.getRuntime(); 13 int rc = -1; 14 15 try 16 { 17 Process p = rt.exec(args[0]); 18 19 int bufSize = 4096; 20 BufferedInputStream bis = 21 new BufferedInputStream(p.getInputStream(), bufSize); 22 int len; 23 byte buffer[] = new byte[bufSize]; 24 25 // Выдаем то, что получено программой 26 while ((len = bis.read(buffer, 0, bufSize)) != -1) 27 System.out.write(buffer, 0, len); 28 29 rc = p.waitFor(); 30 } 31 catch (Exception e) 32 { 33 e.printStackTrace(); 34 rc = -1; 35 } 36 finally 37 { 38 return rc; 39 } 40 } 41 } 42 /

Java created.

Он позволяет выполнить любую программу и получить ее результаты либо в трассировочном файле на сервере, либо, при использовании средств пакета DBMS_JAVA, в буфере пакета DBMS_OUTPUT. Это, однако, весьма мощное средство — при наличии соответствующих привилегий с его помощью можно выполнять любую команду от имени пользователя-владельца ПО Oracle. В данном случае я хочу иметь возможность получить список процессов с помощью утилиты /usr/bin/ps в ОС UNIX и tlist.exe в Windows. Для этого мне необходимы две привилегии:

tkyte@TKYTE816> BEGIN 2 dbms_java.grant_permission 3 (USER, 4 'java.io.FilePermission', 5 -- '/usr/bin/ps', -- для UNIX 6 c:\bin\tlist.exe', -- для WINDOWS 7 'execute'); 8 9 dbms_java.grant_permission 10 (USER, 11 'java.lang.RuntimePermission', 12 '*', 13 'writeFileDescriptor'); 14 end; 15 /

PL/SQL procedure successfully completed.

В вашей системе может отсутствовать утилита tlist.exe. Она входит в состав набора инструментальных средств Windows Resource Toolkit и доступна не во всех Windows-системах. Этот пример просто показывает, что можно сделать, — отсутствие доступа к tlist.exe не помешает демонстрации. Этот метод можно использовать для выполнения любой программы. Учтите, однако, что нужно быть внимательным, предоставляя права на выполнение программ с помощью пакета DBMS_JAVA. Например, предоставление права на выполнение программы c:\winnt\system32\cmd.exe фактически означает разрешение выполнять ВСЕ программы, что очень опасно.


Первый вызов dbms_java.grant_permission позволяет запускать одну конкретную программу. При желании можно рискнуть и указать вместо имени программы символ *. Это позволит выполнять любые программы. Я не думаю, однако, что это разумно; явно перечисляйте полные имена программ, в надежности которых вы уверены. Вторая привилегия позволяет генерировать результаты во время выполнения. Здесь придется использовать метасимвол *, поскольку я не знаю точно, куда именно будут выдаваться результаты (в стандартный выходной поток, stdout, например, или куда-нибудь еще).

Теперь необходимо создать уровень связывания:

tkyte@TKYTE816> create or replace 2 function RUN_CMD(p_cmd in varchar2) return number 3 as 4 language java 5 name 'Util.RunThis(java.lang.String[]) return integer'; 6 /

Function created.

tkyte@TKYTE816> create or replace procedure rc( 2 as 3 x number; 4 begin 5 x := run_cmd(p_cmd); 6 if (x <> 0) 7 then 8 raise program_error; 9 end if; 10 end; 11 /

Procedure created.

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

tkyte@TKYTE816> set serveroutput on size 1000000 tkyte@TKYTE816> exec dbms_java.set_output(1000000)

PL/SQL procedure successfully completed.

tkyte@TKYTE816> exec rc('C:\WINNT\system32\cmd.exe /c dir') Volume in drive C has no label. Volume Serial Number is F455-B3C3 Directory of C:\oracle\DATABASE 05/07/2001 10:13a <DIR> . 05/07/2001 10:13a <DIR> .. 11/04/2000 06:28p <DIR> ARCHIVE 11/04/2000 06:37p 47 inittkyte816.ora 11/04/2000 06:28p 31,744 ORADBA.EXE 05/07/2001 09:07p 1,581 oradim.log 05/10/2001 07:47p 2,560 pwdtkyte816.ora 05/06/2001 08:43p 3,584 pwdtkyte816.ora.hold 01/26/2001 11:31a 3,584 pwdtkyte816.xxx 04/19/2001 09:34a 21,309 sqlnet.log 05/07/2001 10:13a 2,424 test.sql 01/30/2001 02:10p 348,444 xml.tar 9 File(s) 415,277 bytes 3 Dir(s) 13,600,501,760 bytes free

PL/SQL procedure successfully completed.

Мы получили список файлов каталога ОС.


Содержание раздела