Skip to Main Content
  • Questions
  • Java procedure for host calls on Unix environment

Breadcrumb

Question and Answer

Connor McDonald

Thanks for the question, Henk-Jan.

Asked: October 24, 2000 - 11:10 am UTC

Last updated: January 30, 2020 - 9:02 am UTC

Version: 8.1.6

Viewed 50K+ times! This question is

You Asked

Steve,

I'm looking for a Java-procedure executing host calls on a Unix environment from the Oracle-server. I know the standard way of doing it by means of ProC (for Oracle versions before 8.1) but I do not have the ProC compiler available.

I do not know Java or ProC (nor do I currently have the time to learn them). I've found several examples of these scripts but the "Runtime Power" script on this site does not seem to do anything at all and the other script I've found in an Oracle newsgroup seems to miss some "#import" statements in order to compile correctly.

I would greatly appreciate your help on this one.
Henk-Jan

and Tom said...



Here is how to do this in java in 8.1.6. 8.1.6 added lots of new security features so this would be a little different in 8.1.5 but mostly the same.

We need to start by granting some privs. I'm going to grant as little as I have to get allow us to execute the program /usr/bin/ps. As SYS or some appropriately priveleged user, we will execute:

sys@DEV816> begin
2 dbms_java.grant_permission
3 ('RT_TEST',
4 'java.io.FilePermission',
5 '/usr/bin/ps',
6 'execute');
7
8 dbms_java.grant_permission
9 ('RT_TEST',
10 'java.lang.RuntimePermission',
11 '*',
12 'writeFileDescriptor' );
13 end;
14 /

PL/SQL procedure successfully completed.


That allows our user RT_TEST to successfully execute that program. We could have allowed it to execute /usr/bin/* or * or whatever -- I'm just letting it execute that one program.

Now, RT_TEST would create in its schema:


rt_test@DEV816> 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 // Echo back what the program spit out
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.

rt_test@DEV816> 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.


To make this callable as a procedure (ignoring the return code), we'll create a procedure:

rt_test@DEV816>
rt_test@DEV816> create or replace procedure RC(p_cmd in varchar2)
2 as
3 x number;
4 begin
5 x := run_cmd(p_cmd);
6 end;
7 /

Procedure created.

And now to run it:

rt_test@DEV816> set serveroutput on size 1000000
rt_test@DEV816> exec dbms_java.set_output(1000000)
PL/SQL procedure successfully completed.
rt_test@DEV816> exec rc('/usr/bin/ps -ef');
UID PID PPID C STIME TTY TIME CMD
root 0 0 0 Aug 17 ? 0:06 sched
root 1 0 0 Aug 17 ? 1:19 /etc/init -
root 2 0 0 Aug 17 ? 0:23 pageout
.....

PL/SQL procedure successfully completed.

rt_test@DEV816>


See

</code> http://java.sun.com/j2se/1.3/docs/api/java/lang/RuntimePermission.html http://java.sun.com/j2se/1.3/docs/api/java/security/SecurityPermission.html http://java.sun.com/j2se/1.3/docs/api/java/io/FilePermission.html

and 


http://docs.oracle.com/cd/A81042_01/DOC/java.816/a81353/perf.htm#1001971 <code>
From the “Java Developer’s Guide”, Part No. A81353-01, Chapter 5:

Table 5–1 Permission Types
n java.util.PropertyPermission
n java.io.SerializablePermission
n java.io.FilePermission
n java.net.NetPermission
n java.net.SocketPermission
n java.lang.RuntimePermission
n java.lang.reflect.ReflectPermission
n java.security.SecurityPermission
n oracle.aurora.rdbms.security.PolicyTablePermission
n oracle.aurora.security.JServerPermission



Rating

  (354 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Nagarajan, May 30, 2001 - 3:06 pm UTC

very useful material. Thanks for the same

Exactly what I needed to see

B.Wisniewski, June 04, 2001 - 8:22 am UTC

This is exactly what I needed to see in an example of interacting with the operating system. Trying to persuade the developers to use Java vs Perl and this is what I needed.

Thanks again.

Mark Penny, July 27, 2001 - 5:37 am UTC

I had never imagined that this could be done so easily. Thank you.

great answer

Sharon, October 03, 2001 - 10:51 am UTC

Great material , it's exactlly what I was looking for
10x you a lot

A reader, November 21, 2001 - 8:48 pm UTC

hi tom
your reply on extrnal procedure works
Thanks

I am also trying to run executable from java
i am getting this error

I am running Pesonal Oracle 8.1.7 on windows 98

SQL>  exec rc('c:\windows\command /c dir');
java.io.IOException
at oracle.aurora.java.lang.OracleProcess.create(OracleProcess.java)
at oracle.aurora.java.lang.OracleProcess.construct(OracleProcess.java)
at java.lang.Runtime.execInternal(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(Util:11)

PL/SQL procedure successfully completed. 

Tom Kyte
November 22, 2001 - 8:45 am UTC

Ok, is there a c:\windows\command.exe ?

do a dir c:\windows\command.*

show us the entire example from the dbms_java calls to the create or replace and compile java source to the call you are doing itself.

A reader, November 22, 2001 - 10:03 am UTC

hi tom

it was dir c:\windows\command.com

when i run
exec rc('c:\windows\command.com /c dir');

it never come back

i examined udump file it looks like

Dump file d:\oracle\admin\swami\udump\ORA10653.TRC
Thu Nov 22 09:34:37 2001
ORACLE V8.1.7.0.0 - Production vsnsta=0
vsnsql=e vsnxtr=3
Windows 95 V4.10, OS V192.0, CPU type 586
Oracle8i Personal Edition Release 8.1.7.0.0 - Production
JServer Release 8.1.7.0.0 - Production
Windows 95 V4.10, OS V192.0, CPU type 586
Instance name: swami

Redo thread mounted by this instance: 1

Oracle process number: 13

Windows thread id: -710243, image: ORACLE.EXE


*** 2001-11-22 09:34:37.720
*** SESSION ID:(17.10) 2001-11-22 09:34:37.610
Specified COMMAND search directory bad Microsoft(R) Windows 98
(C)Copyright Microsoft Corp 1981-1998. D:\Oracle\Ora81\DATABASE>

any idea.

Thanks




Tom Kyte
November 22, 2001 - 10:40 am UTC

Well, it looks like it just started up a command shell -- did not process the "/c dir" part of it (hence the apparent HANG -- it was waiting for someone to type "exit".


what happens if you just enter:

c:\windows\command.com /c dir


on the dos prompt itself. does that work?

what if you create a script:

do_dir.bat:

@echo off
dir


and run that instead?

but....

Connor, November 22, 2001 - 10:20 am UTC

who is Steve ?

:-)

Tom Kyte
November 22, 2001 - 10:41 am UTC

Thats a darn good question -- never noticed that Henk-Jan called me "steve" :)

A reader, November 22, 2001 - 10:58 am UTC

hi tom,

i ran

c:\windows\command.com /c dir

on dos prompt it works fine
and i also created do_dit.bat and it also works fine

thanks


Tom Kyte
November 22, 2001 - 11:06 am UTC

did you call the do_dir.bat from the java stored procedure -- if so, thats your solution. You see -- this is purely a "command.com" issue here -- we are getting a command.com error "search path invalid (sounds like a bad COMSPEC or something, been a really long time since I worked with dos stuff like that).

re: steve

Mark A. Williams, November 22, 2001 - 11:05 am UTC

I think 'Steve' is Tom's alter ego -- you know, the one who is answering questions and such on Thanksgiving! Thought you (Tom) were taking a break? OK, so I'm *reading* AskTom on Thanksgiving... but that's just because I haven't had the turkey yet.

A reader, November 22, 2001 - 11:27 am UTC

hi tom
Sorry for disturbance on thanks giving but my problem is critical i have to implement this on coming MONDAY

when i run
exec rc('c:\windows\command.com /c dir');

it never come back

THIS TIME I SET SQL_TRACE = TRUE

AND LOG FILE IS AS FOLLOWS

I KILLED SESSION FOR THREE TIMES AND CHECK LOG FILE EACH TIME. IT IS SIMILER EVERY TIME

Dump file d:\oracle\admin\swami\udump\ORA51445.TRC
Thu Nov 22 11:16:57 2001
ORACLE V8.1.7.0.0 - Production vsnsta=0
vsnsql=e vsnxtr=3
Windows 95 V4.10, OS V192.0, CPU type 586
Oracle8i Personal Edition Release 8.1.7.0.0 - Production
JServer Release 8.1.7.0.0 - Production
Windows 95 V4.10, OS V192.0, CPU type 586
Instance name: swami

Redo thread mounted by this instance: 1

Oracle process number: 10

Windows thread id: -341771, image: ORACLE.EXE


*** 2001-11-22 11:16:57.070
*** SESSION ID:(11.3) 2001-11-22 11:16:57.010
APPNAME mod='SQL*Plus' mh=3669949024 act='' ah=4029777240
=====================
PARSING IN CURSOR #1 len=35 dep=0 uid=18 oct=42 lid=18 tim=0 hv=2767092717 ad='4332a9c'
alter session set sql_trace = true
END OF STMT
EXEC #1:c=0,e=0,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=4,tim=0
=====================
PARSING IN CURSOR #1 len=87 dep=0 uid=18 oct=47 lid=18 tim=0 hv=3739629728 ad='433c588'
BEGIN RC('c:\windows\command.COM /c exp scott/tiger file=c:\xx.dmp tables=emp'); END;
END OF STMT
PARSE #1:c=0,e=0,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=4,tim=0
=====================
PARSING IN CURSOR #2 len=64 dep=1 uid=0 oct=2 lid=0 tim=0 hv=3686129482 ad='477a920'
insert into javasnm$(short, longname, longdbcs) values(:1,:2,:3)
END OF STMT
PARSE #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=0,tim=0
=====================
PARSING IN CURSOR #3 len=46 dep=1 uid=0 oct=3 lid=0 tim=0 hv=2044415509 ad='475d6b4'
select longname from javasnm$ where short = :1
END OF STMT
PARSE #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
=====================
PARSING IN CURSOR #4 len=57 dep=1 uid=0 oct=3 lid=0 tim=0 hv=467722929 ad='46be564'
SELECT max(version) FROM "SYS"."JAVA$POLICY$SHARED$TABLE"
END OF STMT
PARSE #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=1,cu=4,mis=0,r=1,dep=1,og=4,tim=0
STAT #4 id=1 cnt=1 pid=0 pos=0 obj=0 op='SORT AGGREGATE '
STAT #4 id=2 cnt=2 pid=1 pos=1 obj=16803 op='TABLE ACCESS FULL JAVA$POLICY$SHARED$TABLE '
=====================
PARSING IN CURSOR #4 len=57 dep=1 uid=0 oct=3 lid=0 tim=0 hv=467722929 ad='46be564'
SELECT max(version) FROM "SYS"."JAVA$POLICY$SHARED$TABLE"
END OF STMT
PARSE #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=1,cu=4,mis=0,r=1,dep=1,og=4,tim=0
STAT #4 id=1 cnt=1 pid=0 pos=0 obj=0 op='SORT AGGREGATE '
STAT #4 id=2 cnt=2 pid=1 pos=1 obj=16803 op='TABLE ACCESS FULL JAVA$POLICY$SHARED$TABLE '
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
=====================
PARSING IN CURSOR #4 len=147 dep=1 uid=0 oct=3 lid=0 tim=0 hv=3013728279 ad='468ad64'
select privilege#,level from sysauth$ connect by grantee#=prior privilege# and privilege#>0 start with (grantee#=:1 or grantee#=1) and privilege#>0
END OF STMT
PARSE #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=6,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=6,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=6,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=0,dep=1,og=4,tim=0
STAT #4 id=1 cnt=37 pid=0 pos=0 obj=0 op='CONNECT BY '
STAT #4 id=2 cnt=20 pid=1 pos=1 obj=0 op='CONCATENATION '
STAT #4 id=3 cnt=1 pid=2 pos=1 obj=102 op='INDEX RANGE SCAN '
STAT #4 id=4 cnt=20 pid=2 pos=2 obj=102 op='INDEX RANGE SCAN '
STAT #4 id=5 cnt=19 pid=1 pos=2 obj=83 op='TABLE ACCESS BY USER ROWID SYSAUTH$ '
STAT #4 id=6 cnt=55 pid=1 pos=3 obj=102 op='INDEX RANGE SCAN '
=====================
PARSING IN CURSOR #4 len=147 dep=1 uid=0 oct=3 lid=0 tim=0 hv=3013728279 ad='468ad64'
select privilege#,level from sysauth$ connect by grantee#=prior privilege# and privilege#>0 start with (grantee#=:1 or grantee#=1) and privilege#>0
END OF STMT
PARSE #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=6,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=6,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=6,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=0,dep=1,og=4,tim=0
STAT #4 id=1 cnt=37 pid=0 pos=0 obj=0 op='CONNECT BY '
STAT #4 id=2 cnt=20 pid=1 pos=1 obj=0 op='CONCATENATION '
STAT #4 id=3 cnt=1 pid=2 pos=1 obj=102 op='INDEX RANGE SCAN '
STAT #4 id=4 cnt=20 pid=2 pos=2 obj=102 op='INDEX RANGE SCAN '
STAT #4 id=5 cnt=19 pid=1 pos=2 obj=83 op='TABLE ACCESS BY USER ROWID SYSAUTH$ '
STAT #4 id=6 cnt=55 pid=1 pos=3 obj=102 op='INDEX RANGE SCAN '
=====================
PARSING IN CURSOR #4 len=147 dep=1 uid=0 oct=3 lid=0 tim=0 hv=3013728279 ad='468ad64'
select privilege#,level from sysauth$ connect by grantee#=prior privilege# and privilege#>0 start with (grantee#=:1 or grantee#=1) and privilege#>0
END OF STMT
PARSE #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=0,dep=1,og=4,tim=0
STAT #4 id=1 cnt=14 pid=0 pos=0 obj=0 op='CONNECT BY '
STAT #4 id=2 cnt=4 pid=1 pos=1 obj=0 op='CONCATENATION '
STAT #4 id=3 cnt=1 pid=2 pos=1 obj=102 op='INDEX RANGE SCAN '
STAT #4 id=4 cnt=4 pid=2 pos=2 obj=102 op='INDEX RANGE SCAN '
STAT #4 id=5 cnt=3 pid=1 pos=2 obj=83 op='TABLE ACCESS BY USER ROWID SYSAUTH$ '
STAT #4 id=6 cnt=25 pid=1 pos=3 obj=102 op='INDEX RANGE SCAN '
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #3:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
=====================
PARSING IN CURSOR #4 len=147 dep=1 uid=0 oct=3 lid=0 tim=0 hv=3013728279 ad='468ad64'
select privilege#,level from sysauth$ connect by grantee#=prior privilege# and privilege#>0 start with (grantee#=:1 or grantee#=1) and privilege#>0
END OF STMT
PARSE #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
EXEC #4:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=5,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=0
FETCH #4:c=0,e=0,p=0,cr=4,cu=0,mis=0,r=0,dep=1,og=4,tim=0
STAT #4 id=1 cnt=14 pid=0 pos=0 obj=0 op='CONNECT BY '
STAT #4 id=2 cnt=4 pid=1 pos=1 obj=0 op='CONCATENATION '
STAT #4 id=3 cnt=1 pid=2 pos=1 obj=102 op='INDEX RANGE SCAN '
STAT #4 id=4 cnt=4 pid=2 pos=2 obj=102 op='INDEX RANGE SCAN '
STAT #4 id=5 cnt=3 pid=1 pos=2 obj=83 op='TABLE ACCESS BY USER ROWID SYSAUTH$ '
STAT #4 id=6 cnt=25 pid=1 pos=3 obj=102 op='INDEX RANGE SCAN '

IT HANGS HERE EVERY TIME





Tom Kyte
November 23, 2001 - 9:44 am UTC

I already diagnosed this! It is NOT HANGNING IN ORACLE. You put up this dump file before:

i examined udump file it looks like


.....
Dump file d:\oracle\admin\swami\udump\ORA10653.TRC
Thu Nov 22 09:34:37 2001
ORACLE V8.1.7.0.0 - Production vsnsta=0
vsnsql=e vsnxtr=3
Windows 95 V4.10, OS V192.0, CPU type 586
Oracle8i Personal Edition Release 8.1.7.0.0 - Production
JServer Release 8.1.7.0.0 - Production
Windows 95 V4.10, OS V192.0, CPU type 586
Instance name: swami

Redo thread mounted by this instance: 1

Oracle process number: 13

Windows thread id: -710243, image: ORACLE.EXE


*** 2001-11-22 09:34:37.720
*** SESSION ID:(17.10) 2001-11-22 09:34:37.610
Specified COMMAND search directory bad Microsoft(R) Windows 98
(C)Copyright Microsoft Corp 1981-1998. D:\Oracle\Ora81\DATABASE>

any idea.

.......

When you are running "command /c dir" -- dos is messing up. You see the error message there "Specified COMMAND search directory bad" and a command prompt. That is your HANG.

command.com is running,
It is messing up.
It is dumping you at the command prompt -- waiting for you to type something in.

Unfortunately for you - this command prompt is in the background, you cannot see it, you cannot type into it. It will sit there forever.

This is NOT hanging in the database. This is hanging in DOS.


Did you try the .bat file as I suggested. If that works -- that is in fact your solution. If it doesn't, you'll have to find out what that error message is and how to fix it. I don't have windows98 to test with.

A reader, November 24, 2001 - 5:06 pm UTC

hi tom

finally i am able to run OS command from pl/sql.but from
Windws NT not Windows 98.

Now I can run os command using extrnal procedure
and Java stored procedure.

Thank you very much for your co-opration

Encountering some limitations

Andrew, November 29, 2001 - 3:59 pm UTC

Tom
Thanks for the great code, but I'm hitting limitations using '>', '|' and other metacharacters. Please could you explain why my attempts fail. I can only overcome the problem by writing the string I want to execute to a script (using utl_file, doing a chmod +x on that and then executing it). As you can see the use of '|' returns and error, the use of '>' is ignored.

1.) Granted the following privs from sys:
begin                                       
    dbms_java.grant_permission     
    ('SCOTT',                    
     'java.io.FilePermission',     
     '/tmp/*',                
     'execute');         
    dbms_java.grant_permission     
    ('SCOTT',                    
     'java.io.FilePermission',     
     '/usr/bin/*',                
     'execute');         
    dbms_java.grant_permission     
    ('SCOTT',                    
     'java.lang.RuntimePermission',
     '*',                          
     'writeFileDescriptor' );  
-- try to accomodate input redirection    
    dbms_java.grant_permission     
    ('SCOTT',                    
     'java.lang.RuntimePermission',
     '*',                          
     'readFileDescriptor' );      
-- try to accomodate input/output redirection    
    ('SCOTT',                    
     'java.io.FilePermission',     
     '/tmp/*',                
     'read,write'); 
-- commit;        
end;
/


2.) changed RC to output the return code:
CREATE OR REPLACE procedure RC(p_cmd in varchar2)
as
  x number;
begin
  x := run_cmd(p_cmd);
  DBMS_OUTPUT.PUT_LINE ( 'run_cmd returned : '||rpad(x, 3, ' ')||' for '|| p_cmd); 
end;
/


3.) the results
SQL> set serveroutput on
SQL> 
SQL> set serveroutput on
SQL> 
SQL> declare
  2    dummy varchar2(50);
  3  begin
  4    dbms_output.enable(1000000);
  5    dbms_java.set_output(1000000);
  6    
  7    -- the following work fine
  8    -- rc('/usr/bin/ps -ef');
  9    -- rc('/usr/bin/pwd');
 10    -- rc('/usr/bin/touch /tmp/t.txt');
 11    
 12    -- the following don't work 
 13    rc('/usr/bin/ps -ef | /usr/bin/grep oracle');
 14    rc('/usr/bin/pwd > /tmp/pwd.log');
 15    -- rc('/usr/bin/ksh -c "/usr/bin/pwd > /tmp/pwd.log"');
 16  end;
 17  /
run_cmd returned : 1   for /usr/bin/ps -ef | /usr/bin/grep oracle
/apps/oracle/product/8.1.7/dbs
run_cmd returned : 0   for /usr/bin/pwd > /tmp/pwd.log

PL/SQL procedure successfully completed.

4.) From Unix:
ls -ltr /tmp/pwd.log
/tmp/pwd.log: No such file or directory
 

Tom Kyte
November 30, 2001 - 8:27 am UTC

What I believe your issue is is that we wrote this tiny routine to run "A" program. You are not running "A" program -- you are running a shell specific command. This is like someone on windows trying to run "dir", "dir" is not a program -- its an internal command. similarly, ps -ef | grep oracle is not a command -- its an internal command to your shell that says "start ps, redirect its stdout, start grep, redirect its stdin".

you would need to run a SHELL that understands "|" and ">", something like:

sh -c 'ps -ef | grep oracle'

BUT -- then you would need execute on /bin/sh, with that you can run ANY command as the user "oracle" (or who ever starts the database). That would let you for example "sh -c rm -rf /*" and erase everything oracle is allowed to erase. So, my real suggestion would be to create a script that has the commands you want to execute and you run THAT script from the database. Give your self the permission to run that one command -- not /bin/sh



Tom, sorry for the mixup.

Henk-Jan Korpel, December 17, 2001 - 5:58 am UTC

He Tom,

Sorry, for the mixup with Steve (Feuerstein, that is) whose stuff I was studying at that time. I just saw it today, hope this clears it.

Regards
Henk-Jan

"Java procedure for host calls on Unix environment", version 8.1.6

Randy Bradley, January 16, 2002 - 6:58 pm UTC

Tom,
I found this information to be very helpful. The step-by-step instructions were easy to follow. I have a question about using the ftp command instead of the ps command. When I run the ps command everything work fine, but when I run the ftp command ("/usr/bin/ftp -vin < /public/parfile.txt"), the procedure just hangs.

What's seems to be causing this problem. I did assign execute permissions via the dbms_java package.

One more thing... I'm running 8.1.7 (64-bit) on HP-UX 11.00 (64-bit).

Tom Kyte
January 17, 2002 - 7:42 am UTC

ftp is waiting for the username and password to be entered and ftp refuses to read this from stdin as you are trying (i assume you have the username/password in the parfile.txt)

Do a man on netrc to see how to setup a .netrc (in the ORACLE account -- could be somewhat "dangerous").

A better approach might be to use some java classes that let you PROCEDURALLY do an ftp from java -- in that fashion, you can alleviate the inherit security issues with the .netrc file solution.

special characters >, >>, |, < etc.

A reader, January 17, 2002 - 12:33 pm UTC

I bet the above reader will need to do the FTP from a shell script if he wants to use '<'. I had a similar problem higher up in this thread.


Tom Kyte
January 17, 2002 - 1:59 pm UTC

Absolutely correct -- I didn't even read that far into the command -- that will be the next problem they hit.

Java procedure for host calls on Unix environment", version 8.1.6

Randy Bradley, January 17, 2002 - 12:43 pm UTC

Your information about using .netrc worked to some degree. I woks when I run the ftp command from the unix prompt, but it still hangs when I attempt to execute from SQL*PLUS. I hope you can help me resolve yet another issue.

Thanks!

Tom Kyte
January 17, 2002 - 2:00 pm UTC

See above...

Java procedure for host calls on Unix environment", version 8.1.6

Randy Bradley, January 17, 2002 - 4:56 pm UTC

I created shell script and I execute the shell script from with the procedure. Thanks for all the help.

Randy

Standard shell script...

A reader, January 17, 2002 - 6:05 pm UTC

In my comments higher up I referred to writing the command to a file, doing a chmod +x etc. Obviously that's only if you don't know the command you want to run. Creating a standard ftp shell script with predefined input parms is better. Maybe the way you implemented it?? From what I can remember the DBMS_PIPE solution (see this site) doesn't have the special character limitation. Java solution just seems neater.

9i ?

Connor, February 07, 2002 - 7:20 am UTC

Apologies for my total lack of java knowledge (I'm getting there...), but your example (which worked fine in 8i) appears to bomb out under my 9i version.  Could you post if the same code works under one of your 9i versions?

SQL> variable x number;
SQL> set serveroutput on
SQL> exec dbms_java.set_output(100000);
SQL> exec :x := RUN_CMD('/usr/bin/ls');
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util:14)

Cheers
Connor 

Tom Kyte
February 11, 2002 - 7:33 am UTC

I just removed the String array definition on the PL/SQL wrapper
function and the Java method. I've included all the code again (and an
example) below. I do not fully know why it worked in 8i.
My assumption is that the JVM-PL/SQL data type pickler may have
automatically promoted non-array types to arrays when required. Or 8i
was less exacting that in 9i.


ops$tkyte@ORA9I.WORLD> begin
  2    dbms_java.grant_permission
  3    ('RT_TEST',
  4     'java.io.FilePermission',
  5     '/usr/bin/ls',
  6     'execute');
  7  
  8    dbms_java.grant_permission
  9    ('RT_TEST',
 10     'java.lang.RuntimePermission',
 11     '*',
 12     'writeFileDescriptor' );
 13  end;
 14  /

PL/SQL procedure successfully completed.

ops$tkyte@ORA9I.WORLD> connect rt_test/rt_test
Connected.
ops$tkyte@ORA9I.WORLD> @login

rt_test@ORA9I.WORLD> 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    public static int RunThis(String args)
 10    {
 11    Runtime rt = Runtime.getRuntime();
 12    int        rc = -1;
 13  
 14    try
 15    {
 16       Process p = rt.exec(args);
 17  
 18       int bufSize = 4096;
 19       BufferedInputStream bis =
 20        new BufferedInputStream(p.getInputStream(), bufSize);
 21       int len;
 22       byte buffer[] = new byte[bufSize];
 23  
 24       // Echo back what the program spit out
 25       while ((len = bis.read(buffer, 0, bufSize)) != -1)
 26          System.out.write(buffer, 0, len);
 27  
 28       rc = p.waitFor();
 29    }
 30    catch (Exception e)
 31    {
 32       e.printStackTrace();
 33       rc = -1;
 34    }
 35    finally
 36    {
 37       return rc;
 38    }
 39    }
 40  }
 41  /

Java created.

rt_test@ORA9I.WORLD> 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.

rt_test@ORA9I.WORLD> create or replace procedure RC(p_cmd in varchar2)
  2  as
  3    x number;
  4  begin
  5    x := run_cmd(p_cmd);
  6  end;
  7  /

Procedure created.

rt_test@ORA9I.WORLD> variable x number;
rt_test@ORA9I.WORLD> set serveroutput on
rt_test@ORA9I.WORLD> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

rt_test@ORA9I.WORLD> exec :x := RUN_CMD('/usr/bin/ls /tmp');
10514.ksh
10565.sql
...
xxx.dat
xxx.dbf
zz

PL/SQL procedure successfully completed.

rt_test@ORA9I.WORLD> 

 

A reader, March 04, 2002 - 6:05 am UTC


Any workaround on 8.1.5

Senthil, April 29, 2002 - 4:37 pm UTC

Tom-

procedure dbms_java.grant_permission is available from 8.1.6. Is there any workaround available in 8.1.5 to achieve the same functionality. I am using 8.1.5 on windows NT. It throws the following error if i try to assign permission to any user...

PLS-00302: component 'GRANT_PERMISSION' must be declared

thanks,
senthil

Tom Kyte
April 29, 2002 - 9:05 pm UTC

There is JAVASYSPRIV (a role) you can grant but beware -- it is "all powerful". The granular privilege model added in 816 and up is far superior. Make sure to lock down this account so this role cannot be abused.

I think this what I need

Adam Hapworth, May 08, 2002 - 10:36 am UTC

I am looking at making a Java-procedure like the ones you have shown to run a program on our Unix server. The question I have is will I be able to have a user on a client machine run this java-procedure from a Form(4.5 now 6 coming) and get results back from the program on the server. I have seen a number of other news group posts regarding this with no answer and thought I would ask here where the experts are.

Tom Kyte
May 08, 2002 - 12:12 pm UTC

The answer is simply "YES".

The reason, all Java stored procedures are called through a wrapper, like this:

rt_test@DEV816> 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.



that maps the java types to SQL types. So, externally, it looks like PLSQL to the caller, but underneath, it is java.

Java procedure for host calls on Unix environment

Sandeep Lekhwani, June 06, 2002 - 2:02 pm UTC

Hi Tom,
Content proved to be very useful.
But, I am facing a problem.
The ksh I am calling from oracle using this utility, has some parameters. Now, some of the parameters contain the spaces. While running the ksh from unix we just put these parameters in double quotes. But, when calling from oracle, it identifies them as delimiters and hence treat as separate parameters. Is there a way that I can make it avoid the spaces which are inside double quotes. Or can I specify some other delim? Pls let me know. It's really urgent.

Tom Kyte
June 06, 2002 - 5:46 pm UTC

We are not parsing anything -- I don't understand what you mean? We are just executing a string -- passing it to the command interpreter.

There undoubtably exists a more sophisticated java api as well that lets you set an array of parameters instead of just string -- you could look that up as well.

help debugging, PLEASE :-)

George Liblick, June 19, 2002 - 2:26 pm UTC

Tom,

I cut and past your solution, then modified the procedure
names and changed the grant_permission to /usr/ucb/ps because that is what I found through the which command
on my box (/usr/bin/ps appears to be identical anyway.)
But when I execute the command, I am getting an error that
I don't know where to begin debugging... 

SQL> exec cmd( 'ps -f' );
java.lang.ArrayIndexOutOfBoundsException
at MyCommand.RunThis(MYCOMMAND:14)

PL/SQL procedure successfully completed.

.. it works the same for /usr/ucb/ps ..

You have been a great help in the past - thanks - and I
hope you will help one more time. 

Tom Kyte
June 19, 2002 - 9:48 pm UTC

search this question from the top for ArrayIndexOutOfBoundsException and you'll see the fix for 9i.

Thanks

George, June 20, 2002 - 12:06 pm UTC

I hate when the answer implies I didn't do my home work :-(
Both yesterday and today I searched for ArrayIndexOutOfBoundsException throughout the archives, but the search failed to return anything... I never thought the
answer would be right under my nose :-( I wonder why your site search failed to find this?

Anyway, it is working now and you have been most gracious - thanks.

Tom Kyte
June 20, 2002 - 12:15 pm UTC

partly my fault.

My index is on the q&a. Not the comments.

I have to code a function in this style:

</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:440419921146 <code>

in order to assemble the question, answer and all comments and responses into a clob and let intermedia index that! Just haven't done it yet, will do it soon (bothers me too)





that why i like oracle .. u can do almost anything

Nitin Gulati, August 21, 2002 - 9:49 pm UTC

Hi tom,
I am facing a problem of similar type.
I need to change permission in few files which are made from utl_file though oracle onli. I think this solution will help me. But when i scearch dbms_java in all objects i cannot find there. Is there anything wrong in my oracle installation. When i scearh for dbms_java in /$oracle_HOME/rdbms/admin i cant find there also so how to load this ?
But no doubt the explanation is really good
cheers,
nitin


Tom Kyte
August 22, 2002 - 8:59 am UTC

If you do not have java installed, your DBA can install it via initjvm.sql found in $ORACLE_HOME/javavm/install

great response, but...

craig, October 10, 2002 - 6:28 pm UTC

Tom -

Your examples work great, but I'm having some trouble running my particular command using your script.

I'm trying to use scp to move files from the database to another box. I can run this from the shell a-ok, but when run via your class, it returns a 1 (failure) every time. Indeed, the file does not exist in the new location when it is all said and done. Can you help me out?

Again, the following works from the shell on the db box:
/usr/bin/scp /u01/home/cnelson/flat_files/CSV2.txt cnelson@pspdwhp1:/u01/home/cnelson/CSV2.txt

Thanks again for your sage advice.

Tom Kyte
October 11, 2002 - 8:06 pm UTC

Well, you ran that script as YOU (cnelson) where as the java ran as ORACLE

different user
different environment
different everything


suggestion:

a) log in as Oracle and test this scp, make sure Oracle can run it (permissions)

b) start out with a script /tmp called "test.sh"

In there put in a call to

/usr/bin/env


and make sure the environment is OK (paths and everything else are totally differnet)

Then add the call to /usr/bin/scp in there (eg: incrementally add in things -- try to figure out where it is going awry)

Very Useful - How about returning output greater than 32K?

Greg DelVecchio, November 08, 2002 - 6:52 pm UTC

I managed to alter your example so that it returns the command line output as a varchar2. However, some of my commands output more than 32K of data. Is there a way to pass more than 32K of data from Java to PL/SQL? Could you pass the command line output as a CLOB or break it into a varray? Thanks for any suggestions you might have.

(NOTE: For others that may try this in 8.1.7. There is a bug (#1322857) that limits the string length that may be returned by a java stored function to 4K. If you write it as a java stored procedure you may pass a string up to 32K in length)

Tom Kyte
November 08, 2002 - 9:18 pm UTC

You'll have to use a CLOB - the caller could allocate a temporary clob and the java could write to it.

Problem when passing string parameters with lots of white spaces

Mahomed Suria, November 20, 2002 - 5:08 am UTC

I am running a unix script exec_cmd.sh using rc.exec as per your example. The script is simply
#!/bin/sh
$@
#finish

When a send several parameters including one that is a string with lots of white spaces , the string is being treated as several parameters rather than just one, even when I hav enclosed the string in double qoutes.

rc ('/usr/users/cdb_env/exe/exec_cmd.sh /usr/users/cdb_env/exe/
qsnd 1 triggr yrdman 1 "+000000001+000000001+000000001DC1 DL1 steve PC" ' )

When I list the parameters that exec_cmd.sh is receiving I get the following :
/usr/users/cdb_env/exe/qsnd
1
triggr
yrdman
1
"+000000001+000000001+000000001DC1
DL1
steve
PC"

It seems like the quoted string is being split into several parameters. I want the string to be a single parameter.

Can you help? I do not know what the problem is?




Tom Kyte
November 21, 2002 - 12:04 pm UTC

You'll have to read up on java -- the answer would lie there. You could use a lower level java api then the rather simple one i have here (no, I don't know the name or even if it exists)

As a workable workaround -- suggest you pass a single string for that parameter using an _ where you have whitespace and then using sed to remove it. EG:

$ cat /tmp/test.sh

#!/bin/sh

/usr/bin/echo '$1 = ' $1
X="`echo $1 | sed 's/_/ /g'`"
echo '$X = ' $X
/usr/bin/echo ---------------



and then:

rt_test@ORA817DEV.US.ORACLE.COM> exec rc('/tmp/test.sh a_b ' )
$1 = a_b
$X = a b
---------------
return code = 0 from /tmp/test.sh a_b


so, your script would use $X instead of $1 or you could just use

`echo $1 | sed s/_/ /g`

in your script where currently you just have $1


Calling OS command using Java procedure in PL/SQL generates NON-EXISTANT PROCESS on NT

Alain Labonte, December 19, 2002 - 11:48 am UTC

Hi, i use a java procedure mostly similar to this one, but when the command is terminated, a NON-EXISTANT PROCESS stays on the server (NT 4.0). Those processes seem to take some memory. So when i execute many jobs, they take a lot of memory and slow down my server. When i stop my database, they disapear, but i can't stop my database at anytime.

Do you have any idea of what might causes that?

Tom Kyte
December 19, 2002 - 12:59 pm UTC

I don't know what a "non existant process on nt" means.

need to run a script

tong siew pui, January 07, 2003 - 1:15 am UTC

The info is very useful. Many thanks.
I am able to follow the example and get the results as stated.

But what I needed is to run a unix script (with different unix commands), instead of a unix command.

I have a script 'tsp1.txt' in
    /u01/home/sinvb/tong

tsp1.txt
--------
ls -la


when I run
SQL> exec rc('/u01/home/sinvb/tong/tsp1.txt');
PL/SQL procedure successfully completed.

but the files are not listed.

when I run the command
'tsp1.txt' at '/u01/home/sinvb/tong'
the files get listed.

I tried different alternative
1) modified tsp1.txt to
    sh -c 'ls -la'
2) copy the file tsp1.txt to /usr/bin
   and 
    exec rc('/usr/bin/tsp1.txt');
both show the same result
PL/SQL procedure successfully completed.

pls adv what is the pbm and what must I do.
the ultimate aim is to prepare tsp1.txt as
a unix script which contains various unix command.

thanks for your help in advance.

i also noticed that if i run
exec rc('/usr/bin/ps')
nothing is displayed.

but i got results if i run
exec rc('/usr/bin/ps -ef');

but if i execute the command 'ps',
i get something displayed.
is there a reason why ???


 
 

Tom Kyte
January 07, 2003 - 6:24 am UTC

time for you to do a little debugging eh?

did you check the permissions? can ORACLE run your script? is the r-x flag on the entire path to this file? is ls in the rarified environment these scripts run in? what is the path? did you put some

/usr/bin/echo $PATH > /tmp/$$.debug

type statements in there?
is the script getting run at all?

did you read the "great response, but... " comment above and do what I suggested there?

.......

Stephan, January 09, 2003 - 5:53 am UTC

Try to execute the following:

exec rc('/usr/bin/sh /u01/home/sinvb/tong/tsp1.txt');

Note the sh command to open a shell and your script as 'parameter'. Be sure you have execute permissions for sh (with dbms_java.grant_permission).

This should output the desired result.


Tom Kyte
January 09, 2003 - 7:27 am UTC

as I said above however -- that would be a really bad idea.

you have to give privs on sh

exec rc( '/usr/bin/sh rm -rf /u01/apps/oracle/oradata/your_sid/*' )

is as easy to execute as tsp1.txt would be! caveat emptor.

Using Java

Abdal-Rahman Agha, January 16, 2003 - 12:41 am UTC

Hi Tom,
- Sorry, I am interesting to use Java in Oracle, can you advice on a book or any good place to learn about Oracle Java quickly?
- I have Win2k, Oracle9 R2: Please, explain this output:

SQL> exec rc('E:\WINNT\command.* /c dir');
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util.java:14)

PL/SQL procedure successfully completed. 

Tom Kyte
January 16, 2003 - 8:32 am UTC

that error just means you got really excited -- stopped reading the article and went to play with it! read on -- ctl-f for ArrayIndexOutOfBoundsException and you'll see the cause.

you might be interested in
</code> http://www.amazon.com/exec/obidos/ASIN/1861006020/ <code>



Is it possible to call os comand of another server

Reader, January 18, 2003 - 2:56 am UTC

Hi Tom

This is excellent piece of Code.

i have one clarification. Is it possible to call a particular command in other unix server.

Ie My oracle DB is in Unix server A
My ETL tool is running in Unix server B
I want to call the ETL Process as Commandline from Java procedure. Will it need to login into Server B. If so How to do it.

Tom Kyte
January 18, 2003 - 9:01 am UTC

if you can do it from sever A on the command line (outside of oracle), we can do it inside the database.

Solve that problem and we'll go from there. Oracle cannot bypass the OS and do magical things beyond what you've set up at the OS level.

We can use C based extprocs in 9i to do this as the extproc is allowed to run on another machine all together. but basically, you would need an agent on server b one way or another.

error on excuting java

Nikunj, February 03, 2003 - 12:20 am UTC

hi tom,

i have oracle ee 8.1.7 on windows nt 4.0 with service pack 6a. i want to execute host command from database.

so i follow ur steps as below.

SQL> CONNECT SYSTEM@BABUL
Enter password: *******
Connected.
SQL> begin
  2  dbms_java.grant_permission
  3  ('SCOTT',
  4  'java.io.FilePermission',
  5  'C:\WINNT',
  6  'execute');
  7  
  8  dbms_java.grant_permission
  9  ('SCOTT',
 10  'java.lang.RuntimePermission',
 11  '*',
 12  'writeFileDescriptor' );
 13  end;
 14  /

PL/SQL procedure successfully completed.

SQL> connect scott@babul
Enter password: *****
Connected.
SQL> 
SQL> create or replace and compile
  2  java source named "Util"
  3  as
  4  import java.io.*;
java source named "Util"
                  *
ERROR at line 2:
ORA-29536: badly formed source: Encountered "<EOF>" at line 1, column 17.

Was expecting:

";" ...

why i am geting this error.

thanks nikunj 

Tom Kyte
February 03, 2003 - 7:24 am UTC

what version of sqlplus do you have.

This:

ops$tkyte@ORA817DEV> create or replace and compile
  2  java source named "Util"
  3  as
  4  import java.io.*;
java source named "Util"
                  *
ERROR at line 2:
ORA-29536: badly formed source: Encountered "<EOF>" at line 1, column 17.
Was expecting:
";" ...



is what I get when I use 8.0 sqlplus which didn't understand "java source".  It just sucked the code upto the first ';' and submitted it (since sqlplus didn't know back then that java source 

a) existed
b) could contain ';' like plsql can


suggest you get your client software updated. 

Java Permisson

Steve, February 25, 2003 - 2:36 pm UTC

Hi Tom,

I just tried the answer here but I got the following messssage. What should I do? Thanks!  --steve

SQL> call testjava.run_cmd('ls') into :y;
java.security.AccessControlException: the Permission (java.io.FilePermission <<ALL FILES>> execute)
has not been granted by dbms_java.grant_permission to
SchemaProtectionDomain(SRS|PolicyTableProxy(SRS))
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java)
at java.lang.SecurityManager.checkExec(SecurityManager.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(Util:13)

Call completed.
 

Tom Kyte
February 25, 2003 - 8:28 pm UTC

did you use dbms_java grant permission to grant yourself the needed privs? like my example does?



Why it is not able to run java class

Umesh Nimbalkar, March 13, 2003 - 7:00 am UTC

Dear Tom,
I want to run class placed in one directory. For this i am giving permissions as follows

begin
dbms_java.grant_permission
('SALES',
'java.io.FilePermission',
'/usr/java130/jre/bin/java',
'execute');

dbms_java.grant_permission
('SALES',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;
/

now when i am trying to execute as below
exec rc('/usr/java130/jre/bin/java -version');

it is not giving any output. but if i run like
exec rc('/usr/java130/jre/bin/java');
it is iving output.
Pls let me know why it is not accepting parameters.

Tom Kyte
March 14, 2003 - 5:06 pm UTC

maybe the -version is writing to stderr. mine does:

$ java -version > xxx
java version "1.3.1_02"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.1_02-b02)
Java HotSpot(TM) Client VM (build 1.3.1_02-b02, mixed mode)


I only caught stdout.



Oracle Application Developer

Dawar, March 19, 2003 - 2:19 pm UTC

Is there a way to call unix command in oracle programs/ packages?


Dawar

Tom Kyte
March 19, 2003 - 3:43 pm UTC

umm, you mean like this:

rt_test@DEV816> exec rc('/usr/bin/ps -ef');
UID PID PPID C STIME TTY TIME CMD
root 0 0 0 Aug 17 ? 0:06 sched
root 1 0 0 Aug 17 ? 1:19 /etc/init -
root 2 0 0 Aug 17 ? 0:23 pageout
.....

PL/SQL procedure successfully completed.



which is the example from above???

Having small problem

Rob, April 24, 2003 - 12:39 pm UTC

I was able to run your example ps -ef with no problem.

I create a simple shell script on UNIX to copy a file rfk.scr:
cp /apps/actappl/rfk.test /apps/actappl/rfk.test2

I can run this with no problem using the Oracle account on UNIX.

When I try to run it using the Java callout nothing happens, no errors no copy.

DECLARE
t NUMBER(9);
BEGIN

t := act_dw_sys_events.run_cmd('/apps/actappl/rfk.scr');
END;

Any suggestions?

Thanks Rob

Tom Kyte
April 24, 2003 - 12:44 pm UTC

scripts can be tricky.

did you grant on it.
is is executable by the oracle software owner.
is the path to it traversable by the oracle software owner.
can the oracle software owner write to that directory.
can it read that file.
what was the return code.

look for (cnelson) on this page (had the same issue). ideas are there as well.

interesting response but do not answer to my problem

Rene Paradis, April 24, 2003 - 4:52 pm UTC

I want to execute a second perl script into the perl script called by the Java procedure like:
system("/path/perl_script.pl argv");
But
But the java grant permissions seem to allow only the first perl script to be executed and this one ends when the system command is called.
here is the granted permissions
begin
dbms_java.grant_permission
('SUPER_MAN',
'java.io.FilePermission',
'/path/first_script.pl',
'execute,read ,wrtie');

dbms_java.grant_permission
('SUPER_MAN',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;
/
begin
dbms_java.grant_permission
('SUPER_MAN',
'java.io.FilePermission',
'/path/second_script.pl',
'execute,read ,wrtie');

dbms_java.grant_permission
('SUPER_MAN',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;
/
if it is not possible to call a second perl script inside the first one, I planned to call it separatly:
declare
x number;
begin
x := run_cmd('/path/first_script.pl argv');
x := run_cmd('/path/second_script.pl argv');
end;
/

Tom Kyte
April 24, 2003 - 6:09 pm UTC

I missing your point?

if first_script.pl calls second_script.pl -- you need not grant on it (the Oracle JVM has *no clue* what first script might do, and it is allowed to do anything it wants really as far as running other commands go)


if first_script.pl doesn't call second_script.pl, but you want to -- you just need to grant on it.


So, I'm not understanding what you are saying here.

excellent

A reader, April 25, 2003 - 10:54 am UTC


did not solve my problem (first and second perl script)

Rene Paradis, April 25, 2003 - 11:48 am UTC

Hi again Tom,
here is my part of code inside the first perl script that calls the second perl script:
...
$fichier = shift @ARGV;
print("test1 tahaa/mascot/data/make_input_txt.pl $fichier\n");
#we build a txt file here
$x = system("/tahaa/mascot/data/make_input_txt.pl $fichier");
print("x value is $x\n");
...

the dbms.output would be:
test1 /seq/murin/proteo/make_input_txt.pl /tahaa/mascot/data/20030327/F006236.dat

PL/SQL procedure successfully completed.

The x value is not printed. but when I execute the command manually (/seq/murin/proteo/make_input_txt.pl /tahaa/mascot/data/20030327/F006236.dat), the script works. So it really seems that the first script cannot execute the system command, altough it does when it is executed manually. What should I do to make it work?
thank you very much for your help



Tom Kyte
April 25, 2003 - 3:37 pm UTC

this looks like a classic PERMISSION problem at the OS level.

put some debug in. remember -- as coded, this catches ONLY stdout -- you might want yet another wrapper -- a script that runs perl1 (which runs perl2) but redirects stderr to stdout so you can see it.

UNDOUBTABLY perl is pumping out an error to stderr and you just haven't seen it yet.



dk, May 07, 2003 - 6:32 pm UTC

Hi Tom,

I am a dveloper.
When I try to creat a java stored procedure in database, I met the following message, what happend ? What requirement I need
to ask DBA?

Thanks!

DLIV>create or replace and compile
2 java source named "Util"
3 as
4 import java.io.*;
java source named "Util"
*
ERROR at line 2:
ORA-29547: Java system class not available: oracle/aurora/rdbms/Compiler


Tom Kyte
May 08, 2003 - 9:33 am UTC

search for

ORA-29547

on this site

It almost works perfectly

Mark, May 15, 2003 - 10:51 am UTC

Tom,

I will appologize in advance because I think this might go a bit beyond the scope of the original question.

I modified your code to work on Windows and after some dumb mistakes on my part I can now execute commands at will from Oracle 9i stored procedures.

Thanks

There is one problem though that I have not been able to resolve yet. When I execute a batch file and that batch file then executes another program (not internal command) I get no output. It's like standard out has been redirected to the bit bucket. If I execute an internal command like 'dir' or 'set' I get the output in the stored procedure. I can also redirect that output to a file from within the batch file called from the stored procedure. But when I execute an external program, for example a "Hello World" java program or grep (windows version) to get some text, there is no output. The ERRORLEVEL indicates the program ran.

Any ideas what could be going on here?

Tom Kyte
May 15, 2003 - 5:51 pm UTC

windows isn't unix and concepts like stdin, stderr, stdout are so foriegn to it.

they do not all share the same "tty" if you will. don't know what to tell you other then use redirection and then "type" the output.

Can't get permissions to set up correctly..

Mahomed, May 16, 2003 - 1:04 pm UTC

Oracle9i Release 9.2.0.1.0 - Production
JServer Release 9.2.0.1.0 - Production

SQL> connect / as sysdba

begin

   dbms_java.grant_permission
      ('CDB_TRAIN',
      'java.io.FilePermission',
      '/data4/cdb_train/exe/exec_cmd',
      'execute');

   dbms_java.grant_permission
      ('CDB_TRAIN',
       'java.lang.RuntimePermission',
       '*',
       'writeFileDescriptor');
 end;
/
PL/SQL procedure successfully completed.

exec dbms_java.grant_permission( 'CDB_TRAIN','SYS:java.io.FilePermission','/usr/cdb_train/exe/exec_cmd', 'execute' );

PL/SQL procedure successfully completed.


exec :x := pkg_utils.sp_cmd('test',3,'/data4/cdb_train/exe/db_locks');
java.security.AccessControlException: the Permission (java.io.FilePermission
/usr/cdb_train/exe/exec_cmd execute) has not been granted to CDB_TRAIN. The
PL/SQL to grant this is dbms_java.grant_permission( 'CDB_TRAIN',
'SYS:java.io.FilePermission', '/usr/c
db_train/exe/exec_cmd', 'execute' )
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at
oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java
)
at java.lang.SecurityManager.checkExec(SecurityManager.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at MyCommand.RunThis(MyCommand.java:14)

PL/SQL procedure successfully completed. 

Tom Kyte
May 16, 2003 - 5:14 pm UTC

so show us a TRUE cut and paste, nothing doctored as above.

Another compile problem...

Jack Wells, May 18, 2003 - 2:17 pm UTC

Tom,
I'm getting the following error when I try to create the Util Java source:

SQL> sho err
Errors for JAVA SOURCE Util:

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0      Util:4: Superclass object of class Util not found.
0/0      Info: 1 errors
SQL> 

I get the same error on an 8.1.7.4 HP/UX instance, a Linux 9.2.0.3 instance and a 9.2.0.1 Windows instance.  Running the dbms_java.grant_permission, however, works fine on all three.  What is the "superclass object" of Util?  Is it one of the two imports just above the Util class declaration? 

Tom Kyte
May 18, 2003 - 2:52 pm UTC

hows about the entire example -- never saw that myself.

Another compile problem (full example)...

Jack Wells, May 18, 2003 - 4:26 pm UTC

Tom,
Here is the whole example:

SQL> connect sys@ncgd
Enter password: *****
Connected.
SQL> select version from v_$instance;

VERSION
-----------------
8.1.7.4.0

1 row selected.

SQL> 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        public static int runthis(string args)
 10       {
 11       runtime rt = runtime.getruntime();
 12       int        rc = -1;
 13     
 14       try
 15       {
 16          process p = rt.exec(args);
 17     
 18          int bufsize = 4096;
 19          bufferedinputstream bis =
 20           new bufferedinputstream(p.getinputstream(), bufsize);
 21          int len;
 22          byte buffer[] = new byte[bufsize];
 23     
 24          // echo back what the program spit out
 25          while ((len = bis.read(buffer, 0, bufsize)) != -1)
 26             system.out.write(buffer, 0, len);
 27     
 28          rc = p.waitfor();
 29       }
 30       catch (exception e)
 31       {
 32          e.printstacktrace();
 33          rc = -1;
 34       }
 35       finally
 36       {
 37          return rc;
 38       }
 39       }
 40     }
 41  /

Warning: Java created with compilation errors.

SQL> sho err
Errors for JAVA SOURCE Util:

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0      Util:4: Superclass object of class Util not found.
0/0      Info: 1 errors
SQL> 

 

Tom Kyte
May 18, 2003 - 6:27 pm UTC

object

should be

Object


initcap, java is case sensitive.


rt_test@DEV816> 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

Duh...

Jack Wells, May 19, 2003 - 1:31 am UTC

Oh.

After correcting that faux pax, there were a few other "spelling" mistakes I needed to correct... works like a charm now!

p.s. Note to self: don't use PL/Formatter on Java code!

Got an error

A reader, May 19, 2003 - 4:20 pm UTC

I copied the same code but got an error

SQL> exec rc('/usr/bin/ps -ef');
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(UTIL.java:14)

What is problem? 

What are the pre-requisites to run this?

Emelyn, June 10, 2003 - 3:05 pm UTC

In order to run your Java program, do I need to add entries to listener.ora and tnsnames.ora or any preparation or set-up to be done?
I'm running version 8.1.5.
Thanks in advance!

Tom Kyte
June 10, 2003 - 3:12 pm UTC

just have java installed in the database.

What are the pre-requisites to run this?

Emelyn, June 10, 2003 - 6:31 pm UTC

Here's what I got when I ran sql*plus:

SQL*Plus: Release 8.0.5.0.0 - Production on Tue Jun 10 14:52:27 2003

(c) Copyright 1998 Oracle Corporation. All rights reserved.


Connected to:
Oracle8i Enterprise Edition Release 8.1.5.0.0 - Production
With the Partitioning and Java options
PL/SQL Release 8.1.5.0.0 - Production

With the phrase: With the Partitioning and Java options
Does it mean, Java is installed?


Tom Kyte
June 10, 2003 - 8:08 pm UTC

yes.

you'll have problems creating java with the 805 sqlplus client however -- sqlplus "parses" statements before submitting them. it won't recognize 'create or replace java ....' and will most likely "barf"

Some points regarding to pass parameters to your shell

Erdal, June 11, 2003 - 12:58 pm UTC

I have been using the Java Stored Procedures a lot to replace the Pro*C Codes and all the other workarounds we did in the past to execute a command on the operating system (mostly UNIX).
There's a very good article here
</code> http://www.mountainstorm.com/publications/javazine.html <code>
It helped me a lot for passing parameters to UNIX Shell.
{"/bin/sh", "-c", "Your Command") format has no surprises when executing anything on UNIX.

Tom Kyte
June 11, 2003 - 7:13 pm UTC

unless of course, someone gives you

"rm -rf /usr/oracle/oradata"


to run. /bin/sh would not be something I would want "open" to run.

/bin/ps, sure
/bin/sh (run anything you like), not so sure I'd like that.

about username for dbms_java.grant_permission

Jianhui, June 18, 2003 - 5:06 pm UTC

The username must be uppercase or it will report user or role doesnt exist error. This may need to be improved since pl/sql is not case sensitive traditionally.

Issue with 9i

Steve, June 19, 2003 - 8:05 am UTC

Hi Tom

I've successfully run this in 8.1.7 and have put your amended code into 9.0.1.4 but get an error. Could you glance at it and tell me where I've gone wrong please?

ltop_owner@EU0084P> conn sys/eu0084psys@eu0084p as sysdba
Connected.
ltop_owner@EU0084P> ed
Wrote file afiedt.buf

1 begin
2 dbms_java.grant_permission
3 ('LTOP_OWNER',
4 'java.io.FilePermission',
5 'e:\orant_eu0084p\scripts\bandvisit.bat',
6 'execute');
7 dbms_java.grant_permission
8 ('LTOP_OWNER',
9 'java.lang.RuntimePermission',
10 '*',
11 'writeFileDescriptor' );
12* end;
ltop_owner@EU0084P> /

PL/SQL procedure successfully completed.

ltop_owner@EU0084P> conn ltop_owner/prodltop@eu0084p
Connected.
ltop_owner@EU0084P> ed
Wrote file afiedt.buf

1 create or replace and compile
2 java source named "Util"
3 as
4 import java.io.*;
5 import java.lang.*;
6 public class Util extends Object
7 {
8 public static int RunThis(String args)
9 {
10 Runtime rt = Runtime.getRuntime();
11 int rc = -1;
12 try
13 {
14 Process p = rt.exec(args);
15 int bufSize = 4096;
16 BufferedInputStream bis =
17 new BufferedInputStream(p.getInputStream(), bufSize);
18 int len;
19 byte buffer[] = new byte[bufSize];
20 // Echo back what the program spit out
21 while ((len = bis.read(buffer, 0, bufSize)) != -1)
22 System.out.write(buffer, 0, len);
23 rc = p.waitFor();
24 }
25 catch (Exception e)
26 {
27 e.printStackTrace();
28 rc = -1;
29 }
30 finally
31 {
32 return rc;
33 }
34 }
35* }
36 /

Java created.

ltop_owner@EU0084P> ed
Wrote file afiedt.buf

1 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';
ltop_owner@EU0084P> /

Function created.

ltop_owner@EU0084P> ed
Wrote file afiedt.buf

1 create or replace procedure RC(p_cmd in varchar2)
2 as
3 x number;
4 begin
5 x := run_cmd(p_cmd);
6* end;
7 /

Procedure created.

ltop_owner@EU0084P> conn ltop_owner/prodltop@eu0084p
Connected.
ltop_owner@EU0084P> variable x number
ltop_owner@EU0084P> set serveroutput on
ltop_owner@EU0084P> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

ltop_owner@EU0084P> exec :x := RUN_CMD('/usr/bin/ls /tmp');
java.io.IOException: The handle is invalid.
at oracle.aurora.java.lang.OracleProcess.create(OracleProcess.java)
at oracle.aurora.java.lang.OracleProcess.construct(OracleProcess.java)
at java.lang.Runtime.execInternal(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(Util:11)

PL/SQL procedure successfully completed.

ltop_owner@EU0084P>

Tom Kyte
June 19, 2003 - 8:07 am UTC

you seem to be on windows (e:\ ...)

but you seem to be trying to use the power of unix (/usr/bin/ls...) ???



Oops....just checking you were awake!!

steve, June 19, 2003 - 8:21 am UTC

Hide my shame!!!! I'll just wait for the ground to open up and swallow me!

Yes the server is on Windoze and if I run the correct command it runs as it should. The power of cut 'n paste!!!

"The DBA formerly known as Steve."

OS Output

Jack Wells, June 21, 2003 - 2:09 am UTC

Tom,

I'm having trouble passing the OS output back in a parameter to the calling PL/SQL binding function. I'd like to do this rather than rely on the dbms_output approach. I've added the following to the function call (per your instruction in your book):

public static int RunOsCmd(java.lang.String OsCmdLine,
java.lang.String[] CmdOutput)

Now I need to get the routine to stuff its output in the "CmdOutput" parameter. How would I do this?

Tom Kyte
June 21, 2003 - 10:33 am UTC

you'll have to write a little java to concatenate the output instead of using system.out to write it "on screen" and then assign that to CmdOutput[0] before you return.

How to concatenate output

Jack Wells, June 21, 2003 - 6:26 pm UTC

Tom,

Here is my PL/SQL binding code and Java code and output from running the program. I can't seem to get the output in the return variable. As I'm not a Java dude, I suspect I'm not concatenating correctly or not handling the "buffer" variable correctly. What is the problem?

FUNCTION run_command_java (
fv_command IN VARCHAR2,
fv_output OUT VARCHAR2
)
RETURN NUMBER
AS
LANGUAGE JAVA
NAME 'NcgOSj.runOsCmd( java.lang.String,
java.lang.String[] ) return integer';

PROCEDURE run_command_java (
fv_command IN VARCHAR2,
fv_output OUT VARCHAR2
)
IS
ln_return_code NUMBER;
BEGIN
ln_return_code := run_command_java (fv_command, fv_output);
END run_command_java;

CREATE OR REPLACE AND COMPILE
JAVA SOURCE NAMED "NcgOSj"
AS
import java.io.*;
import java.lang.*;

public class NcgOSj extends Object
{
public static int runOsCmd(String OsCmdLine,
String[] CmdOutput)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;
String coutput = "";

if (OsCmdLine.length() < 1) {
System.out.println("USAGE: java NcgOSj.runOsCmd \'cmd\' OutputStringVariable");
System.exit(1);
}
try
{
// The exec() method in java.lang.Runtime is overloaded and
// can be called in different forms. The following use illustrates
// the simplest form of exec() which takes a string as a parameter.
//
// Execute the command using the Runtime object variable 'rt' and
// get the process 'p' which controls this command
Process p = rt.exec(OsCmdLine);

int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];

// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1) {
System.out.write(buffer, 0, len);
coutput = coutput + buffer;
}
// Wait for the process 'p' to finish and get the return code
// from the process
rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
CmdOutput[0] = coutput;
return rc;
}
}
}
/

VARIABLE outpt VARCHAR2(2000)
SET serveroutput on
EXEC dbms_java.set_output(100000);
EXEC run_command_java ('/bin/ls /', :outpt);
bin
boot
dev
etc
home
initrd
lib
lost+found
misc
mnt
ncg01
ncg02
ncg03
ncg04
ncglx01
ncglx01_cp.log
ncglx01_cp.sh
ncglx01_mount.sh
nohup.out
opt
proc
root
sbin
tmp
tmpdir
usr
var

PL/SQL procedure successfully completed.

PRINT outpt

OUTPT
-----------------------------------------------------------
[B@e8955a6a



Tom Kyte
June 21, 2003 - 6:57 pm UTC

we will have to hope a java dude comes along.

Convert...

Kamal Kishore, June 22, 2003 - 1:29 pm UTC

The byte array needs to be converted to a String before assigning to the OUT variable.
The while (read...) loop needs to be changed to the following:

// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1) {
System.out.write(buffer, 0, len);
ot = new String(buffer, 0, len) ;
coutput = coutput + ot ;
}

Where "ot" is a String variable declared in the program above like this:


Runtime rt = Runtime.getRuntime();
int rc = -1;
String coutput = " ";
String ot = " " ;


This seems to work when run on my system.


Tom Kyte
June 22, 2003 - 4:25 pm UTC

Thanks, appreciate that...

Works like a charm!

Jack Wells, June 22, 2003 - 4:48 pm UTC

Thanks Kamal! Made those changes and it works just as expected.

Tell me, do you know how I could just convert the byte array variable "buffer" to a string inline instead of declaring the new variable "ot"? Something like:

// capture the output in a string variable
while ((len = bis.read(buffer, 0, bufSize)) != -1) {
coutput = coutput + toString (buffer, 0, len);
}

Wouldn't this use up less memory than allocating "new" memory for each iteration for the "ot" variable?

Hangs on sendmail

Jack Wells, June 23, 2003 - 8:44 pm UTC

Tom,

Do you have any idea why the program above would hang on a call to sendmail? As long as I have done the dbms_java.grant_permission, the program works fine for /bin/ls, /bin/rm, etc., but when I issue the following command from SQL*Plus, it just hangs:

EXEC run_command_java (/usr/sbin/sendmail jwells@nichegroup.com < /home/oracle/smtest.txt', :outpt);

The server is on Red Hat Linux AS 2.1 and 9.2 of the database. Issuing the command line as oracle at the Unix prompt works fine. Does it work on your Linux box?

Tom Kyte
June 24, 2003 - 7:41 am UTC

sendmail must be waiting for you to type something in. If you goto the OS and kill it, and it returns, that is what is happening.

write a script, call the script perhaps.

(or heck, just use UTL_SMTP eh?)

------------------------------------------------

Oh I see it, search for

you would need to run a SHELL that understands...

on this page. you sent a SHELL command (redirect). you are thinking "oh, anything that runs in shell, runs here", but it doesn't. redirection is a "shell thing"


Yong, June 24, 2003 - 4:39 pm UTC

Jack,

You cannot pass more than one parameters in this case. As tom suggested: write a script and run the script. You can use pl/sql to write a script and change run mode and call the script.

BTW, why not use pl/sql send mail with attachemet?

You were right

Jack Wells, July 07, 2003 - 12:31 pm UTC

Tom,
You were right, it was the "<" redirection... a shell thing. In my zeal to ensure only granular permissions were issued, I had avoided giving execute permission on /usr/sh. When I did, though, it worked fine. Now, the only thing that bothers me is this execute priv on /usr/sh...

Tom Kyte
July 07, 2003 - 1:25 pm UTC

so -- write a SCRIPT that you invoke that does the redirection.



"Java procedure for host calls on Unix environment"

Raja, August 11, 2003 - 12:58 pm UTC

Hi Tom,
We are looking to call a unix shell script from Oracle after an update/insert/delete happens on a table in the database. The above solution looks kind of neat, however, just wondering whether the procedure RC above could be called from a database trigger and made to execute a shell script (lets say test.sh) OR do you have any other suggestions which might help? We are using Oracle version 8.1.7

Thanks in advance!

Raja

Tom Kyte
August 11, 2003 - 2:11 pm UTC

lets back up a second.

what exactly would this shell script do? this sounds like a fairly "bad idea" for many reasons. Once I know what the script does, I'll give you a "for example"

"Java procedure for host calls on Unix environment"

Raja, August 11, 2003 - 5:14 pm UTC

Hi Tom,
In simple words, what we are trying to do here is just notify the java webserver that for example an update has occured, based on which it will initiate other necessary actions on its side on the webserver.

Actually, I do not code java. Our java developers just gave me an idea of what they want (for example to be able to execute host calls - shell scripts from Oracle which will notify the webserver for either executing something on the webserver with respect to the database update event on a table or maybe run shell script which could FTP some files or other information for each updated)

Let me know if this is enough or need more details.

Regards,
Raja

Tom Kyte
August 11, 2003 - 6:54 pm UTC

well, the update hasn't really happened -- NOT until you commit anyhow.

what about this:


update t set x = 5; -- update 1,000,000 records
ROLLBACK;


whoops -- so sorry, I just ran 1,000,000 sh scripts to notify someone about

a) an even they cannot see (since I did not commit, they can never have seen the updated data)

b) that didn't really happen.


Another interesting on -- read this article:
</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:11504247549852 <code>

to see an update that updates 4 rows BUT fires the row trigger 6 times! what about that?



You want to read about AQ (advanced queues) I believe and they want to use JMS to be notified about events.

It is nice and transactional. they'll only get notified of REAL ACTUAL committed events.



"Java procedure for host calls on Unix environment"

Raja, August 12, 2003 - 11:44 am UTC

Hi Tom,
Thanks a lot for a prompt reply. This is certainly helping. Actually, just wanted to know if JMS supported in Oralce 8.1.7 as, I just happened to go to metalink (let me know if I am looking at the right article).....

</code> http://metalink.oracle.com/metalink/plsql/ml2_documents.showDocument?p_database_id=NOT&p_id=232301.1 <code>

and it mentions.....
The following requirements need to be satisfied when using JMS-AQ:

OC4J 9.0.3.0.0
Supported RDBMS version
Oracle9i Database 9.0.1.4 (Patch: 2517300)
Oracle9i Database 9.2.0.2 (Patch: 2632931)
For further information, see:

Note:230372.1

Send JMS Messages to OJMS Queue Fails with PLS-00306

You,ve been very helpful!
Regards,
Raja

is there any security issue

please help, August 26, 2003 - 1:41 pm UTC

Hi Tom,

Thanks for this nice solution, currently I am using it to call sqlldr to load a file into a table from plsql, since it will run sqlldr as user oracle, my boss worrys about any possible security hole here, please give me some your comments

Thanks


Tom Kyte
August 27, 2003 - 7:45 am UTC

what is your boss worried about exactly?

using java with very very specific grants like this (eg: this user is allowed to run /home/oracle/bin/sqlldr and nothing else) is much more secure then the other methods of:

o using an extproc. that can run any code the user running the extproc listener can run

o using "java_sys_priv" or some other broad ranging privs.


if you have a specific concern, we can address that.

Trigger again

Warren, September 16, 2003 - 2:30 pm UTC

Tom,

I noticed that you had put the person off who asked about using triggers, but I have a similar question. OK, I have a third party app that is inserting or updating into a table, tableA. I would like to set up a trigger on these actions such that it will call a batch file (say devtest.bat, sorry I had to use Windows for these guys). Can I use your method to pass a column name (call it Project_Name) from tableA to the devtest.bat file?

The insert/update is automatically committed by the application when the click on the OK button. No rollback opportunity, and no other ad-hoc application (i.e. sqlplus) access to the database.

I have your method working calling the devtest.bat file directly, but can't get a trigger working for this.

Thanks!

Tom Kyte
September 16, 2003 - 6:11 pm UTC

tell you want -- read this:

</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:11504247549852 <code>

and see if you REALLY want to call a bat file from a trigger. pretend where I use a sequence - you called your bat file. think about the ramifications....


you want to use a stored procedure, invoked by dbms_job, AFTER the transaction commits. It is the only transactional method that works.

yes, you can pass a parameter to a script.
but I don't have a windows machine anywhere to play with to test for you.
you might have to invoke "cmd /c ....." in order to get it to go.
but that means you need to be able to run "cmd.exe" which means you can run ANYTHING. (not good)

Works nicely

Mike, December 02, 2003 - 12:42 pm UTC

Tom's code works well. Question: is it possible to expand the solution to also populate the DIR_LIST table with file attributes such as size and last-mod date? If so, any code snippets to share?

Return value into a variable

Highlander, January 07, 2004 - 1:27 pm UTC

Tom,
Can you post an axample of the "Util" java that will return the output to a variable or lob instead of dbms_output.

Thank you.

Tom Kyte
January 07, 2004 - 6:31 pm UTC

on the road, in a car right now (not conducive to massive coding :)

ask some other time when I'm taking questions (or search the site for java examples that show how to return strings and other such things -- they are out there, I had them all in my book "Expert one on one Oracle" as well)

AUTHID CURRENT_USER - privileges problem

Andriy Terletskyy, January 08, 2004 - 10:20 am UTC

Hi Tom,

I have two Questions:

1. I defined the java source and wrapper function RUN_CMD with invoker-rights AUTHID CURRENT_USER in SCHEMA1 (GLOBAL) and granted the execute right on RUN_CMD to SCHEMA2 (WP).

After that I granted the execute and writeFileDescriptor permission with DBMS_JAVA.GRANT_PERMISSION to user WP (SCHEMA2).

If I trying to execute this functiom with user WP (SCHEMA2) :

...
GLOBAL.run_cmd('/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh')
...


FEHLER in Zeile 1:
ORA-29532: Java call terminated by uncaught Java exception:
java.security.AccessControlException: the Permission (java.io.FilePermission
/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh execute) has not been
granted to GLOBAL. The PL/SQL to grant this is dbms_java.grant_permission(
'GLOBAL', 'SYS:java.io.FilePermission',
'/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh', 'execute' )
ORA-06512: at "GLOBAL.RUN_CMD", line 0
ORA-06512: at line 5

What's wrong?

2. How I can write the wrapper function based on Java-class another user?

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

Warnung: Funktion wurde mit Kompilierungsfehlern erstellt.

WP@BBSE> show error
Fehler bei FUNCTION RUN_CMD:

LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
4/3 PLS-00311: the declaration of
"GLOBAL:Util.RunThis(java.lang.String[]) return integer" is
incomplete or malformed


Thanks

Tom Kyte
January 08, 2004 - 3:18 pm UTC

1) worked for me.  See full example below (shows that the invoker OPS$TKYTE needs the priv, not the owner RT_TEST)



2) this works:

ops$tkyte@ORA920PC> create synonym "Util" for rt_test."Util"
  2  /
 
Synonym created.
 
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> 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.


And in this case -- OPS$TKYTE is the true invoker and OPS$TKYTE would need execute on ls (not RT_TEST)

ops$tkyte@ORA920PC> begin
  2    dbms_java.grant_permission
  3    ('RT_TEST',
  4     'java.io.FilePermission',
  5     '/bin/ls',
  6     'execute');
  7
  8    dbms_java.grant_permission
  9    ('RT_TEST',
 10     'java.lang.RuntimePermission',
 11     '*',
 12     'writeFileDescriptor' );
 13  end;
 14  /
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> @connect rt_test/rt_test
ops$tkyte@ORA920PC> set termout off
rt_test@ORA920PC> REM GET afiedt.buf NOLIST
rt_test@ORA920PC> set termout on
rt_test@ORA920PC>
rt_test@ORA920PC> 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    public static int RunThis(String args)
 10    {
 11    Runtime rt = Runtime.getRuntime();
 12    int        rc = -1;
 13
 14    try
 15    {
 16       Process p = rt.exec(args);
 17
 18       int bufSize = 4096;
 19       BufferedInputStream bis =
 20        new BufferedInputStream(p.getInputStream(), bufSize);
 21       int len;
 22       byte buffer[] = new byte[bufSize];
 23
 24       // Echo back what the program spit out
 25       while ((len = bis.read(buffer, 0, bufSize)) != -1)
 26          System.out.write(buffer, 0, len);
 27
 28       rc = p.waitFor();
 29    }
 30    catch (Exception e)
 31    {
 32       e.printStackTrace();
 33       rc = -1;
 34    }
 35    finally
 36    {
 37       return rc;
 38    }
 39    }
 40  }
 41  /
 
Java created.
 
rt_test@ORA920PC> grant execute on "Util" to public
  2  /
 
Grant succeeded.
 
rt_test@ORA920PC>
rt_test@ORA920PC> create or replace
  2  function RUN_CMD(p_cmd in varchar2) return number
  3  authid current_user
  4  as
  5  language java
  6  name 'Util.RunThis(java.lang.String) return integer';
  7  /
 
Function created.

rt_test@ORA920PC> show errors
No errors.
rt_test@ORA920PC>
rt_test@ORA920PC> create or replace procedure RC(p_cmd in varchar2)
  2  authid current_user
  3  as
  4    x number;
  5  begin
  6    x := run_cmd(p_cmd);
  7  end;
  8  /
 
Procedure created.
 
rt_test@ORA920PC> grant execute on rc to public
  2  /
 
Grant succeeded.
 
rt_test@ORA920PC>
rt_test@ORA920PC> variable x number;
rt_test@ORA920PC> set serveroutput on
rt_test@ORA920PC> exec dbms_java.set_output(100000);
 
PL/SQL procedure successfully completed.
 
rt_test@ORA920PC>
rt_test@ORA920PC>
rt_test@ORA920PC> exec :x := RUN_CMD('/bin/ls /tmp');
afiedt.buf
BEQ2113
DCE2113
DEC2113
foo.dat
hostname.txt
ISPX2113
ITCP2113
kde-tkyte
ksocket-tkyte
log
LU622113
net2113
NMP2113
nscopy.tmp
nsmail-1.tmp
nsmail-2.tmp
nsmail-3.tmp
nsmail-4.tmp
nsmail-5.tmp
nsmail.eml
nsmail.html
nsmail.tmp
orbit-tkyte
RAW2113
SPX2113
ssh-XXDMz0hl
TCP2113
TCPS2113
US2113
VI2113
 
PL/SQL procedure successfully completed.
 
rt_test@ORA920PC>
rt_test@ORA920PC> @connect /
rt_test@ORA920PC> set termout off
ops$tkyte@ORA920PC> REM GET afiedt.buf NOLIST
ops$tkyte@ORA920PC> set termout on
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> create synonym "Util" for rt_test."Util"
  2  /
 
Synonym created.
 
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> 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.
 
ops$tkyte@ORA920PC> show errors
No errors.
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> create or replace procedure RC(p_cmd in varchar2)
  2  as
  3    x number;
  4  begin
  5    x := run_cmd(p_cmd);
  6  end;
  7  /
 
Procedure created.
 
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> variable x number;
ops$tkyte@ORA920PC> set serveroutput on
ops$tkyte@ORA920PC> exec dbms_java.set_output(100000);
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> exec :x := RUN_CMD('/bin/ls /tmp');
java.security.AccessControlException: the Permission (java.io.FilePermission /bin/ls execute) has not been granted to OPS$TKYTE.
The PL/SQL to grant this is dbms_java.grant_permission( 'OPS$TKYTE', 'SYS:java.io.FilePermission', '/bin/ls', 'execute' )
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:283)
at java.security.AccessController.checkPermission(AccessController.java:399)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:545)
at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java:267)
at java.lang.SecurityManager.checkExec(SecurityManager.java:800)
at java.lang.Runtime.exec(Runtime.java:548)
at java.lang.Runtime.exec(Runtime.java:418)
at java.lang.Runtime.exec(Runtime.java:361)
at java.lang.Runtime.exec(Runtime.java:325)
at Util.RunThis(Util.java:13)
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA920PC> exec :x := rt_test.RUN_CMD('/bin/ls /tmp');
java.security.AccessControlException: the Permission (java.io.FilePermission /bin/ls execute) has not been granted to OPS$TKYTE.
The PL/SQL to grant this is dbms_java.grant_permission( 'OPS$TKYTE', 'SYS:java.io.FilePermission', '/bin/ls', 'execute' )
at java.security.AccessControlContext.checkPermission(AccessControlContext.java:283)
at java.security.AccessController.checkPermission(AccessController.java:399)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:545)
at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java:267)
at java.lang.SecurityManager.checkExec(SecurityManager.java:800)
at java.lang.Runtime.exec(Runtime.java:548)
at java.lang.Runtime.exec(Runtime.java:418)
at java.lang.Runtime.exec(Runtime.java:361)
at java.lang.Runtime.exec(Runtime.java:325)
at Util.RunThis(Util.java:13)
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC>




 

Thanks for the question regarding "Java procedure for host calls on Unix environment", version 8.1.6

fakhri, January 08, 2004 - 11:36 am UTC

hi tom,

i applied this script and i have error message :

SQL> ed
Wrote file afiedt.buf

  1  begin
  2        dbms_java.grant_permission
  3        ('scott',
  4         'java.io.FilePermission',
  5         '/usr/bin/ps',
  6         'execute');
  7       dbms_java.grant_permission
  8        ('scott',
  9         'java.lang.RuntimePermission',
 10         '*',
 11         'writeFileDescriptor' );
 12*   end;
SQL> /
begin
*
ERROR at line 1:
ORA-29532: appel Java arrêté par une exception Java non interceptée :
oracle.aurora.vm.IdNotFoundException: scott is not a user or role
ORA-06512: à "SYS.DBMS_JAVA", ligne 0
ORA-06512: à ligne 2


can you help me 

thanks
 

Tom Kyte
January 08, 2004 - 3:18 pm UTC

'scott' isn't a user

'SCOTT' probably is.

AUTHID CURRENT_USER - privileges problem

Andriy Terletskyy, January 09, 2004 - 7:12 am UTC

Hi Tom,

my two Guestions in not answered:

1. It is well that I can see the invoker need the priv. But if I give the priv to invoker and revoke that from owner - i see that:
ORA-29532: Java call terminated by uncaught Java exception:
java.security.AccessControlException: the Permission (java.io.FilePermission
/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh execute) has not been
granted to GLOBAL.


The Permission of this script must be granted to the OWNER too? That is wrong.

2. Wrapper function based on Java-class another user.
That work, if java class is not in package, but need also owner execute privs(see 1.)

But, if I put the class in package, that dosn't work:

WP@BBSE> @conn global@bbse
Kennwort eingeben: *****
GLOBAL@BBSE> create or replace and compile java source named util as
2 package de.berenbergbank.global.tools;
3
4 import java.io.BufferedReader;
5 import java.io.BufferedInputStream;
6 import java.io.InputStream;
7 import java.io.InputStreamReader;
8 import java.io.IOException;
9
10 import java.util.Collections;
11 import java.util.LinkedList;
12 import java.util.List;
13
14
15 /**
16 * Created by IntelliJ IDEA.
17 * User: Terletskyy
18 * Date: 06.01.2004
19 * Time: 13:26:35
20 * To change this template use Options | File Templates.
21 */
22 public class Util {
23
24 public static String run_cmd(String command) throws Exception
25 {
26 StringBuffer myBuffer = new StringBuffer();
27 Process p = Runtime.getRuntime().exec(command);
28 int out;
29
30 int bufSize = 4096;
31 BufferedInputStream bis = new BufferedInputStream(p.getInputStream(), bufSize);
32 byte buffer[] = new byte[bufSize];
33 int len;
34
35 // Echo back what the program spit out
36 while ( (len = bis.read(buffer, 0, bufSize)) != -1) {
37 myBuffer.append(new String(buffer, 0, len));
38 }
39
40 if ((out=p.waitFor()) != 0 ){
41 throw new Exception("Error: "+out);
42 }
43
44 return myBuffer.toString();
45 }
46
47 }
48 /

Java wurde erstellt.

GLOBAL@BBSE> GRANT EXECUTE ON GLOBAL."de/berenbergbank/global/tools/Util" TO PUBLIC;

Benutzerzugriff (Grant) wurde erteilt.


WP@BBSE> create synonym "de/berenbergbank/global/tools/Util" for GLOBAL."de/berenbergbank/global/tools/Util"
2 /

Synonym wurde angelegt.

WP@BBSE> CREATE OR REPLACE FUNCTION RUN_CMD (in_command IN VARCHAR2) RETURN VARCHAR2
2 AS LANGUAGE JAVA NAME 'de.berenbergbank.global.tools.Util.run(java.lang.String) return java.lang.String';
3 /

Funktion wurde erstellt.

WP@BBSE> variable x Varchar2(4000);
WP@BBSE> set serveroutput on
WP@BBSE> exec dbms_java.set_output(100000);

PL/SQL-Prozedur wurde erfolgreich abgeschlossen.

WP@BBSE> exec :x := RUN_CMD ('/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh');
java.lang.NoSuchMethodException: No applicable method found
at
oracle.aurora.util.JRIExtensions.getMaximallySpecificMethod(JRIExtensions.java)
at
oracle.aurora.util.JRIExtensions.getMaximallySpecificMethod(JRIExtensions.java)
BEGIN :x := RUN_CMD ('/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh'); END;

*
FEHLER in Zeile 1:
ORA-29531: no method run in class de/berenbergbank/global/tools/Util
ORA-06512: at "WP.RUN_CMD", line 0
ORA-06512: at line 1


Thanks,
Andriy

AUTHID CURRENT_USER - privileges problem

Andriy Terlerskyy, January 09, 2004 - 7:32 am UTC

Sorry it must be

WP@BBSE> CREATE OR REPLACE FUNCTION RUN_CMD (in_command IN VARCHAR2) RETURN VARCHAR2
2 AS LANGUAGE JAVA NAME 'de.berenbergbank.global.tools.Util.run_cmd(java.lang.String) return java.lang.String';
3 /

Funktion wurde erstellt.

WP@BBSE> show error
Keine Fehler.
WP@BBSE> variable x Varchar2(4000);
WP@BBSE> set serveroutput on
WP@BBSE> exec dbms_java.set_output(100000);

PL/SQL-Prozedur wurde erfolgreich abgeschlossen.

WP@BBSE> exec :x := RUN_CMD('/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh');
java.security.AccessControlException: the Permission (java.io.FilePermission
/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh execute) has not been granted
to GLOBAL. The PL/SQL to grant this is dbms_java.grant_permission( 'GLOBAL',
'SYS:java.io.FilePer
mission', '/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh', 'execute' )
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at
oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java
:267)
at java.lang.SecurityManager.checkExec(SecurityManager.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at de.berenbergbank.global.tools.Util.run_cmd(UTIL.java:26)
BEGIN :x := RUN_CMD('/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh'); END;

*
FEHLER in Zeile 1:
ORA-29532: Java call terminated by uncaught Java exception:
java.security.AccessControlException: the Permission (java.io.FilePermission
/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh execute) has not been
granted to GLOBAL. The PL/SQL to grant this is dbms_java.grant_permission(
'GLOBAL', 'SYS:java.io.FilePermission',
'/oracle/u01/app/oracle/admin/BBSE/appscripts/ls.sh', 'execute' )
ORA-06512: at "WP.RUN_CMD", line 0
ORA-06512: at line 1


Tom Kyte
January 09, 2004 - 8:42 am UTC

yes, it appears that both need the grant -- if you feel this is "a bug", please open a tar with support -- I cannot change the code.

Java procedure for host calls on Unix environment

fakhri, January 09, 2004 - 9:15 am UTC

hi tom,

thanks for your help, all the procedures are succefull, but when I execute :

SQL>  exec rc('/usr/bin/ps -ef');
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util.java:11)

PL/SQL procedure successfully completed.

I have Oracle 9i database.

thx for you help.
fakhri 

Tom Kyte
January 09, 2004 - 9:24 am UTC

and read the entire page........ ctl-f for arrayindexoutofbounds

win-2003

RR, January 09, 2004 - 10:33 am UTC

In redhat linux AS 2.1  with oracle 9i-2 your code worked fine.But while I am trying the following in win-2003 with oracle 9i-2 its giving the following error. Please help.
SQL> begin
  2   dbms_java.grant_permission
  3       ('DEVEL',
  4        'java.io.FilePermission',
  5        'c:\oracle\backup\abc.bat,
  6        'execute');
  7  end;
  8  /
begin
*
ERROR at line 1:
ORA-04021: timeout occurred while waiting to lock object
SYS.JAVA$POLICY$SHARED$0000001d
ORA-06512: at "SYS.DBMS_JAVA", line 0
ORA-06512: at line 2


 

Tom Kyte
January 09, 2004 - 1:47 pm UTC

well, it is not "my code", it is just a standard API call.

read through:

</code> http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:292016138754#14645479504811 <code>

where we just worked through how to find out who is blocking you when you get that 4021.

RE: Win 2003

Mark A. Williams, January 09, 2004 - 10:54 am UTC

'c:\oracle\backup\abc.bat

Is missing the closing tick - is that correct? Just an observation...

- Mark

rr, January 09, 2004 - 11:05 am UTC

file is present.It just hangs & giving the following error.
Same thing is happening with '*' too.

SQL> begin
  2   dbms_java.grant_permission
  3       ('DEVEL',
  4        'java.io.FilePermission',
  5        'c:\oracle\backup\*,
  6        'execute');
  7  end;
  8  /
begin
*
ERROR at line 1:
ORA-04021: timeout occurred while waiting to lock object
SYS.JAVA$POLICY$SHARED$0000001d
ORA-06512: at "SYS.DBMS_JAVA", line 0
ORA-06512: at line 2
 

rr, January 09, 2004 - 11:09 am UTC

closing tick ' is present in the actual code. I just made a typo after pasting it here.thanks!

Line 5

Mark A. Williams, January 09, 2004 - 11:13 am UTC

Is line 5 correct?

'c:\oracle\backup\abc.bat,

It looks like it is missing the closing tick:
i.e., 'c:\oracle\backup\abc.bat',

Or is it just getting dropped in the copy and paste?

- Mark

A reader, January 09, 2004 - 11:37 am UTC

AS its my test database , I just shutdown & restarted the database & everything seems to be normal now. Thanks!

A reader, January 09, 2004 - 12:13 pm UTC

The Beauty of Windows shutdown and restart, everything works fine.

:-))))))




Only as 'oracle' o/s user?

Robert, January 21, 2004 - 3:10 pm UTC

Tom,

Is there any way to run this so that the o/s command is run as another user besides the 'oracle' user?

We want to implement this to run users' application scripts, but would like to limit potential security risks of users' scripts running as 'oracle'.

Thanks,

Robert.

Tom Kyte
January 21, 2004 - 3:30 pm UTC

using a C based external procedure and a listener running "as that other user", yes.

Using Java -- no.

UnsatisfiedLinkError

Janick Reynders, January 27, 2004 - 10:17 am UTC

Hi Tom,

A few months ago I tried to run a program from within Oracle using the procedure you described here,
(Actually it was a shell script) and it worked great! But just recently I tried to do the same thing on another machine, and now I get an exception:

java.lang.UnsatisfiedLinkError
at oracle.aurora.java.lang.OracleProcess.create(OracleProcess.java)
at oracle.aurora.java.lang.OracleProcess.construct(OracleProcess.java)
at java.lang.Runtime.execInternal(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at UsBblLoadingWrapper.load(UsBblLoadingWrapper:13)

Until now I have not been able to find the problem. Any ideas what could be going wrong?

Thanks,
Janick


this is the setup:
------------------
 Oracle9i

- The permissions:
    dbms_java.grant_permission('AMICUS', 'java.io.FilePermission', '/home/ami35/bin/loading_script.sh', 'execute');
    dbms_java.grant_permission('AMICUS', 'java.lang.RuntimePermission', '*', 'writeFileDescriptor');

- The class:

create or replace and compile
java source named "UsBblLoadingWrapper"
as
import java.io.*;
import java.lang.*;


public class UsBblLoadingWrapper extends Object {

    public static int load() {
        Runtime rt = Runtime.getRuntime();
        int rc = -1;
        System.out.println("\n\n ---START--- \n\n");
    
        try {
            Process p = rt.exec("/home/ami35/bin/loading_script.sh");
            
            int bufSize = 4096;
            BufferedInputStream bis = new BufferedInputStream(p.getInputStream(), bufSize);
            
            
            int len;
            byte buffer[] = new byte[bufSize];
            System.out.println("\n\n--stdout--\n");
            
            // Echo back what the program spit out
            while ((len = bis.read(buffer, 0, bufSize)) != -1) {
                System.out.write(buffer, 0, len);
            }
            
            BufferedInputStream errbis = new BufferedInputStream(p.getErrorStream(), bufSize);
            
            System.out.println("\n\n--stderr--\n");
            while ((len = errbis.read(buffer, 0, bufSize)) != -1) {
                System.out.write(buffer, 0, len);
            }
                        
            rc = p.waitFor();
        }
        catch (Throwable e) {
               e.printStackTrace();
               rc = -1;
        }
        finally    {
               return rc;
        }
    }
}
/


- the function:

create or replace
function TEST_EXTERNAL_PROGRAM return number
as
language java
name 'UsBblLoadingWrapper.load() return integer';
/


- the script:

#!/bin/sh
echo "test"


- the call:

SQL> set serveroutput on size 1000000
exec dbms_java.set_output(1000000)
DECLARE
           rc NUMBER;
BEGIN
         rc := TEST_EXTERNAL_PROGRAM();
         DBMS_OUTPUT.PUT_LINE('function returncode ' || rc);
END;
/SQL>
PL/SQL procedure successfully completed.

SQL>   2    3    4    5    6    7
---START---
java.lang.UnsatisfiedLinkError
at oracle.aurora.java.lang.OracleProcess.create(OracleProcess.java)
at oracle.aurora.java.lang.OracleProcess.construct(OracleProcess.java)
at java.lang.Runtime.execInternal(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at UsBblLoadingWrapper.load(UsBblLoadingWrapper:13)
function returncode -1

PL/SQL procedure successfully completed.

SQL> 

Tom Kyte
January 27, 2004 - 10:43 am UTC

if you are on version 9013 or 9014, contact support and ask them to peek at bug 2598380

Sarada Priya, February 16, 2004 - 6:44 am UTC

Hi Tom,

I found this very useful, but I have a question to ask. I have a requirement wherein the Database Server, 9iAS server & Reports Server(We put all the reports output files in this after the nightly batch jobs) all in a networked environment and the Client system is web-enabled Forms9i forms. We need to build an interface wherein the user needs to see all the files available under a designated folder in the Reports Server and should be allowed to print the same. We are perplexed how to get the List of files from the Reports server. The above problem(for which you have answered) deals with the DB server itself, but this one???? Any idea? Please send in.
Thanks and Regards
Sarada Priya

Tom Kyte
February 16, 2004 - 7:44 am UTC

sorry, I don't work with reports but it seems to me that "mount" is the answer? just attach a network drive and go at it -- whatever client you have would read the directory.

How can we diagnose problems?

Ben, February 19, 2004 - 12:14 am UTC

Tom,
We've successfully implemented this on one database, and now I'm trying to implement it on a new one, but it seems the thing doesn't work. Is there an error log somewhere that would show me what went wrong?
Here's the code for the procedure that I implemented:
create or replace and compile java source named "Util" as
  import java.io.*;
  import java.lang.*;
  
  public class Util extends Object  {
   public static int RunThis(String[] args)    {
    Runtime rt = Runtime.getRuntime();
    int        rc = -1;
  
    try    {
       Process p = rt.exec(args[0]);
  
       int bufSize = 4096;
       BufferedInputStream bis =
        new BufferedInputStream(p.getInputStream(), bufSize);
       int len;
       byte buffer[] = new byte[bufSize];
  
       // Echo back what the program spit out
       while ((len = bis.read(buffer, 0, bufSize)) != -1)
          System.out.write(buffer, 0, len);
  
       rc = p.waitFor();
    }
    catch (Exception e)    {
       e.printStackTrace();
       rc = -1;
    }
    finally    {
       return rc;
    }
   }
  }
  /

create or replace
  function RUN_CMD( p_cmd  in varchar2) return number
  as
  language java
  name 'Util.RunThis(java.lang.String[]) return integer';
  /


As the SYS user, I granted the following privileges:
begin
      dbms_java.grant_permission
      ('ROCQ',
       'java.io.FilePermission',
       '/tahiti/bin/test.pl',
       'execute');
  
      dbms_java.grant_permission
      ('ROCQ',
       'java.lang.RuntimePermission',
       '*',
       'writeFileDescriptor' );
  end;
  /

The procedure that executes the system call:
CREATE OR REPLACE PROCEDURE rocq.test_runcmd IS

    resultat_rp        NUMBER;

BEGIN

    dbms_output.put_line('Beginning.');
    resultat_rp := RUN_CMD('perl /tahiti/bin/test.pl');
    dbms_output.put_line(resultat_rp);
    dbms_output.put_line('Ending.');

END;
/
show errors;

And the script that is called:
#!/usr/bin/perl -w

system "echo allo >allo";

Finally, the execution:
SQL> @ test_runcmd.pls

Procedure created.

No errors.
SQL> exec test_runcmd
Beginning.
-1
Ending.

PL/SQL procedure successfully completed.

Any ideas?
Thanks for your help! 

Tom Kyte
February 19, 2004 - 10:31 am UTC

you granted execute on the script.


you cannot run "perl", no grant on "perl"


if you do this:

set serveroutput on size 1000000
exec dbms_java.set_output(1000000)

you should see the java output "on screen"

Ben, February 19, 2004 - 11:04 am UTC

Just tried these grants:
begin
      dbms_java.grant_permission
      ('ROCQ',
       'java.io.FilePermission',
       'perl',
       'execute');

       dbms_java.grant_permission
      ('ROCQ',
       'java.io.FilePermission',
       '/usr/bin/perl',
       'execute');
 
      dbms_java.grant_permission
      ('ROCQ',
       'java.lang.RuntimePermission',
       '*',
       'writeFileDescriptor' );
  end;
  /

But the host call still doesn't work:

SQL> set serveroutput on size 1000000
exec dbms_java.set_output(1000000)
SQL> 
PL/SQL procedure successfully completed.

SQL> exec test_runcmd
Beginning.
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util:8)
-1
Ending.

PL/SQL procedure successfully completed.


 

Permissions

Ben, February 19, 2004 - 12:21 pm UTC

Just did as you suggested, but now I'm running into a classic Permissions problem. 
SQL> begin
  2    dbms_java.grant_permission
  ('ROCQ',
   'SYS:java.io.FilePermission',
   'perl',
   'execute');

  dbms_java.grant_permission
  ('ROCQ',
   'SYS:java.io.FilePermission',
   '/usr/bin/perl',
   'execute');

  dbms_java.grant_permission
  ('ROCQ',
   'SYS:java.io.FilePermission',
  3    4    5    6    7     '/tahiti/bin/test.pl',
   'execute');

  dbms_java.grant_permission
  ('ROCQ',
   'SYS:java.lang.RuntimePermission',
   '*',
   'writeFileDescriptor' );
end;
/

PL/SQL procedure successfully completed.

SQL> 
SQL> exec test_runcmd
Beginning.
java.security.AccessControlException: the Permission (java.io.FilePermission
<<ALL FILES>> execute) has not been granted to ROCQ. The PL/SQL to grant this is
dbms_java.grant_permission( 'ROCQ', 'SYS:java.io.FilePermission', '<<ALL
FILES>>', 'execute' )
at
java.security.AccessControlContext.checkPermission(AccessControlContext.java:207
)
at java.security.AccessController.checkPermission(AccessController.java:403)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:549)
at
oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java
:267)
at java.lang.SecurityManager.checkExec(SecurityManager.java:788)
at java.lang.Runtime.exec(Runtime.java:270)
at java.lang.Runtime.exec(Runtime.java:195)
at java.lang.Runtime.exec(Runtime.java:152)
at Util.RunThis(Util:10)
-1
Ending.

PL/SQL procedure successfully completed.
 

Tom Kyte
February 19, 2004 - 12:31 pm UTC

sorry -- i cannot reproduce on 9ir2 myself (did you log out and back in after granting?)


ops$tkyte@ORA920PC> grant dba to rt_test identified by rt_test;
 
Grant succeeded.
 
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> begin
  2    dbms_java.grant_permission
  3    ('RT_TEST',
  4     'java.io.FilePermission',
  5     '/usr/bin/perl',
  6     'execute');
  7
  8    dbms_java.grant_permission
  9    ('RT_TEST',
 10     'java.lang.RuntimePermission',
 11     '*',
 12     'writeFileDescriptor' );
 13  end;
 14  /
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC>
ops$tkyte@ORA920PC> @connect rt_test/rt_test
ops$tkyte@ORA920PC> set termout off
rt_test@ORA920PC> REM GET afiedt.buf NOLIST
rt_test@ORA920PC> set termout on
rt_test@ORA920PC>
rt_test@ORA920PC> 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    public static int RunThis(String args)
 10    {
 11    Runtime rt = Runtime.getRuntime();
 12    int        rc = -1;
 13
 14    try
 15    {
 16       Process p = rt.exec(args);
 17
 18       int bufSize = 4096;
 19       BufferedInputStream bis =
 20        new BufferedInputStream(p.getInputStream(), bufSize);
 21       int len;
 22       byte buffer[] = new byte[bufSize];
 23
 24       // Echo back what the program spit out
 25       while ((len = bis.read(buffer, 0, bufSize)) != -1)
 26          System.out.write(buffer, 0, len);
 27
 28       rc = p.waitFor();
 29    }
 30    catch (Exception e)
 31    {
 32       e.printStackTrace();
 33       rc = -1;
 34    }
 35    finally
 36    {
 37       return rc;
 38    }
 39    }
 40  }
 41  /
 
Java created.
 
rt_test@ORA920PC>
rt_test@ORA920PC>
rt_test@ORA920PC> 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.
 
rt_test@ORA920PC>
rt_test@ORA920PC>
rt_test@ORA920PC> create or replace procedure RC(p_cmd in varchar2)
  2  as
  3    x number;
  4  begin
  5    x := run_cmd(p_cmd);
  6  end;
  7  /
 
Procedure created.
 
rt_test@ORA920PC>
rt_test@ORA920PC>
rt_test@ORA920PC> variable x number;
rt_test@ORA920PC> set serveroutput on
rt_test@ORA920PC> exec dbms_java.set_output(100000);
 
PL/SQL procedure successfully completed.
 
rt_test@ORA920PC>
rt_test@ORA920PC>
rt_test@ORA920PC> exec :x := RUN_CMD('/usr/bin/perl /home/tkyte/test.pl' );
Hello World
 
PL/SQL procedure successfully completed.
 
 

Ben, February 19, 2004 - 1:39 pm UTC

Yes - actually, the grant was in one terminal window as the SYS user, and the script execution was in another terminal, as a regular user. I just tried to disconnect/reconnect, and it still fails, but now I've lost the error messages:

@tahiti/export/home/hebben01>sqlplus

SQL*Plus: Release 9.0.1.4.0 - Production on Thu Feb 19 13:25:34 2004

(c) Copyright 2001 Oracle Corporation.  All rights reserved.

Enter user-name: rocq     
Enter password: 

Connected to:
Oracle9i Enterprise Edition Release 9.0.1.4.0 - Production
JServer Release 9.0.1.4.0 - Production

SQL> set serveroutput on size 1000000
exec dbms_java.set_output(1000000)
SQL> 
PL/SQL procedure successfully completed.

SQL> exec test_runcmd
Beginning.
-1
Ending.

PL/SQL procedure successfully completed.

 

Tom Kyte
February 19, 2004 - 2:37 pm UTC

put some System.out.println( "hello world" ) messages in your java.

I think you have gotten around your "permission issue" (else we'd see that) and it is now failing 'for some other reason'

Ben, February 19, 2004 - 2:53 pm UTC

This is what I tried:

create or replace and compile java source named "Util" as
  import java.io.*;
  import java.lang.*;
  
  public class Util extends Object {
    public static int RunThis(String args) {
    Runtime rt = Runtime.getRuntime();
    int        rc = -1;
    try    {
        System.out.println("Hello world 1");
       Process p = rt.exec(args);
  
       int bufSize = 4096;
       BufferedInputStream bis =
        new BufferedInputStream(p.getInputStream(), bufSize);
       int len;
       byte buffer[] = new byte[bufSize];
        System.out.println("Hello world 2");
  
       // Echo back what the program spit out
       while ((len = bis.read(buffer, 0, bufSize)) != -1)
          System.out.write(buffer, 0, len);
        System.out.println("Hello world 3");
  
       rc = p.waitFor();
    }
    catch (Exception e)  {
        System.out.println("Hello world 4");
       e.printStackTrace();
       rc = -1;
    }
    finally {
       return rc;
    }
   }
  }
/

Re-granted privileges as the sys user:
SQL> begin
      dbms_java.grant_permission
      ('ROCQ',
       'SYS:java.io.FilePermission',
       '/usr/bin/perl',
       'execute');
 
     dbms_java.grant_permission
      ('ROCQ',
       'SYS:java.lang.RuntimePermission',
       '*',
       'writeFileDescriptor' );
  end;
/

PL/SQL procedure successfully completed.

Checked permissions at the OS level to make sure Oracle had the required privileges to execute the script.
But I'm still getting the same result:
SQL> exec test_runcmd
Beginning.
-1
Ending.

I'm not seeing the "hello world" messages. 

Tom Kyte
February 19, 2004 - 3:01 pm UTC

are you sure you made the call to dbms_java to enable output (else it gets written to a trace file on the database server).

Until you get "output", nothing is working -- get it to get output on your screen first. Just write a hello world java snippet if you have to.

Ben, February 19, 2004 - 3:01 pm UTC

Disregard my last posting. I had neglected to logout/login again.
The new Java:
create or replace and compile java source named "Util" as
  import java.io.*;
  import java.lang.*;
  
  public class Util extends Object {
    public static int RunThis(String args) {
    Runtime rt = Runtime.getRuntime();
    int        rc = -1;
    try    {
        System.out.println("Hello world 1");
       Process p = rt.exec(args);
        System.out.println("Hello world A");
  
       int bufSize = 4096;
       BufferedInputStream bis =
        new BufferedInputStream(p.getInputStream(), bufSize);
       int len;
       byte buffer[] = new byte[bufSize];
        System.out.println("Hello world 2");
  
       // Echo back what the program spit out
       while ((len = bis.read(buffer, 0, bufSize)) != -1)
          System.out.write(buffer, 0, len);
        System.out.println("Hello world 3");
  
       rc = p.waitFor();
    }
    catch (Exception e)  {
        System.out.println("Hello world 4");
       e.printStackTrace();
       rc = -1;
    }
    finally {
       return rc;
    }
   }
  }
/


Here is what I'm seeing:
SQL> exec test_runcmd
Beginning.
Hello world 1
-1
Ending.

PL/SQL procedure successfully completed.
 

Tom Kyte
February 19, 2004 - 3:04 pm UTC

put something in the finally block -- it is not making sense yet. If the rt.exec was failing -- it would jump to the catch block -- but apparently - it is not.

Ben, February 19, 2004 - 3:11 pm UTC

    finally {
         System.out.println("Goodbye cruel world");
      return rc;
   }


SQL> exec test_runcmd
Beginning.
Hello world 1
Goodbye cruel world
-1
Ending.
 

Tom Kyte
February 19, 2004 - 3:23 pm UTC

don't know -- sorry, i'll have to refer you to support. we know the rt.exec was working at some point (you got the permissions thing) but now is not.

Maybe try "ls" like I did to remove perl and scripting from the equation first tho

Ben, February 19, 2004 - 3:26 pm UTC

ok
Thanks for all your help, Tom.

how to send message?

Sikandar Hayat, March 09, 2004 - 6:34 am UTC

Hi,
I want to send message to different users when any insert in the table. I am using Oracle 9i r2 on Windows 2003 env. Please guide me as I am trying to use

net send sikandar A record inserted....

But unable to use net send command in the trigger.

Tom Kyte
March 09, 2004 - 12:16 pm UTC

did you install the above code that lets you run host commands?

3x for help!!!

dibo, March 21, 2004 - 10:53 pm UTC

so good.
haho.

Can PL/SQL submit a nohup job in unix shell

Stephen, April 02, 2004 - 1:43 am UTC

I try to submit a nohup shell script from pl/sql, but the session still wait unit the script end. How can I submit a nohup jobs in pl/sql?

Please advise!

Tom Kyte
April 02, 2004 - 10:06 am UTC

the script you run would call the script you want to run in the background

instead of you running:


rc( 'some_script' );

you would run

rc( 'some_other_script' );

and some_other_script would be

#!/bin/sh
some_script &



Can PL/SQL submit a nohup job in unix shell

Stephen, April 02, 2004 - 8:29 pm UTC

Hi,

I had tried the following method already in the some_other_script:

1)
#!/bin/sh
some_script &

2)
#!/bin/sh
nohup some_script &

But the session in PL/SQL still wait until the last nohup job completed.

Should you have any idea? Please advise.


Thanks,
Stephen



Tom Kyte
April 03, 2004 - 8:53 am UTC

maybe its the waitFor() call in the Process class.

in fact, google'ing waitfor process confirms.

your choices

o learn more java to find the exact solution you want
o remove the p.waitfor call so as to not block and hope that is the solution you want.

why I hate windoz #101

robert, April 13, 2004 - 2:39 pm UTC

tom, 
The code below worked fine under *nix (9i) where instead of
"c:/winnt/system32/cmd", I had "/bin/sh".
But under 8i/W2K, it's not carrying out my commands:
Can you spot whats wrong, thanks

CREATE OR REPLACE AND COMPILE
JAVA SOURCE NAMED "Util"
AS
import java.io.*;
import java.lang.*;

public class Util extends Object
{
public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;

try
{
String[] cmd = {"c:/winnt/system32/cmd", "/c", args};
Process p = Runtime.getRuntime().exec(cmd);
rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}

/

CREATE OR REPLACE
FUNCTION run_host_cmd(p_cmd IN VARCHAR2) RETURN NUMBER
AS
LANGUAGE JAVA
NAME 'Util.RunThis(java.lang.String) return integer';
/

CREATE OR REPLACE PROCEDURE RC(p_cmd IN VARCHAR2)
AS
x NUMBER;
BEGIN
x := run_host_cmd(p_cmd);
END;
/

SQL> exec rc('del C:\temp\foo.pdf');

PL/SQL procedure successfully completed



----  BUT C:\temp\foo.pdf' is NOT deleted

GRANTED:
dbms_java.grant_permission('MANDA','java.io.FilePermission','c:\winnt\system32\cmd.exe','execute');
dbms_java.grant_permission('MANDA', 'java.io.FilePermission','C:/temp/*', 'read,write'); 
dbms_java.grant_permission('MANDA',  'java.lang.RuntimePermission','C:/temp/*',   'writeFileDescriptor' ); 

 

Tom Kyte
April 13, 2004 - 6:36 pm UTC

look in the server for a trace file -- the prints from exceptions are going there.

Disregard Prev Post - bug found

robert, April 13, 2004 - 5:26 pm UTC

tom pls disregard my prev posting.
found out what was wrong...shoulda have a space
before the parameter...duh
Thanks

SQL> exec rc(' del C:\temp\foo.pdf'); 

Does Oracle waits ?

Robert, April 14, 2004 - 9:28 am UTC


Tom, does Oracle, in PL/SQL processing, wait for the host call via Java SP to end then continue ?

Thanks

Tom Kyte
April 14, 2004 - 10:49 am UTC

as coded, yes --

26 while ((len = bis.read(buffer, 0, bufSize)) != -1)
27 System.out.write(buffer, 0, len);
28
29 rc = p.waitFor();

30 }

Just what we needed

Jack Boyle, April 28, 2004 - 7:46 am UTC

We have implemented a solution for executing processes outside of the database that includes Oracle Queues, detached processes, etc. This solution looks like a much cleaner, more straightforward approach.

Need to run sqlldr command from within the procedure

Anurag Mehrotra, April 29, 2004 - 7:15 pm UTC

I have already implemented the solution mentioned here to run OS commands successfully. However in spite of my best efforts I have been unable to invoke sql loader command using this method.

my exec command is:
exec :x := RUN_CMD('/export/home/oracle/test-sqlldr/load-data-test.sh mytestctl.ctl mydatafile.dat')

load-data-test.sh looks something like:

USAGE="load-data-test.sh ctlfilename.ctl datafilename.dat"
if [ $# -lt 2 ] ; then
echo "$USAGE"
exit 1 fi
ORACLE_SID=dbtest ORACLE_HOME=/usr/app/oracle/product/8.1.7 export ORACLE_SID
export ORACLE_HOME

$ORACLE_HOME/bin/sqlldr username/pwd $1 data=$2

I have also assigned the following privilege to the user:

dbms_java.grant_permission
('USERNAME',
'java.io.FilePermission',
'/usr/bin/ls',
'execute');

dbms_java.grant_permission
('USERNAME',
'java.io.FilePermission',
'/export/home/oracle/test-sqlldr/load-data-test.sh',
'execute');

dbms_java.grant_permission
('USERNAME',
'SYS:java.io.FilePermission',
'/export/home/oracle/test-sqlldr/*',
'read,write,execute');

dbms_java.grant_permission
('USERNAME',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );

end;
/

Somehow it does not seem to create the log file or the bad file in the directory I am expecting it to create (/export/home/oracle/test-sqlldr). The response I get after executing the RUN_CMD is: "PL/SQL procedure successfully completed."

Could there be some permission that I am missing on the directory?



Tom Kyte
April 30, 2004 - 7:00 am UTC

well, I see no explicit "cd" anywhere -- do you have any idea what directory might be the "current working one"?

I would add a bit of "debug" to the script. redirect its output to /tmp/something, put cd's in there to be exactly where you think you should be and so on.

and don't forget, it'll run "as oracle", not as "you" so yes, permissions play into this big time.

It worked

Anurag Mehrotra, April 30, 2004 - 9:59 am UTC

'cd' did the trick.
You can write all the complex code in the world, but can forget simplest of all things, that can cause undesirable results.

Your help is greatly appreciated.


to call a Pro*C executables

Pushparaj A, May 19, 2004 - 10:50 am UTC

Tom,

Can I use this Java approach to call a Pro*C executables
from the stored procedures. Since Pro*C needs to connect back to the database, I am not sure if this is the best way.
Currently we don't have JVM installed in our database and if calling a Pro*C executable from stored procedure is feasible by this way then I can ask the manager to have the
JVM installed in the database.

We currently using,
Oracle9i Enterprise Edition Release 9.2.0.5.0 - 64bit Production
With the Partitioning option
JServer Release 9.2.0.5.0 - Production

Thanks
Pushparaj


Tom Kyte
May 19, 2004 - 11:10 am UTC

you can use this approach to call "any executable"

but if I had pro*c code I needed to invoke -- i would be looking at EXTERNAL PROCEDURES and just call the c code as a subroutine instead, it'll use the same connection, it'll use the same transaction.

Background execution

andrew, May 25, 2004 - 7:55 pm UTC

In relpy to Stephen's posting above, I've successfully used this for background execution:

#!/usr/bin/ksh
# Script: at_now.ksh
/usr/bin/echo "$1 $2 $3 $4 $5 $6 $7 $8 $9" | /usr/bin/at now

begin
RC('/full_path/at_now.ksh /usr/bin/sleep 10');
end;
/


Java procedure for host calls

RameshG, May 26, 2004 - 10:36 am UTC

I'm getting the following error when i run it:

SQL> exec rc('/usr/bin/ps -ef');
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util.java:11)

DBA's have granted the permissions that you have specified.

Could explain me if anything else needs to be done.

Thanks
RameshG
 

Tom Kyte
May 26, 2004 - 12:47 pm UTC

ctl-f and enter ArrayIndexOutOfBoundsException into the text field...

Java procedure for host calls on Unix environment

Jose Luis Sanchez, May 27, 2004 - 1:19 pm UTC

hi tom.

I don´t know anything about java or unix and i would like to know if i could use this procedures whit sqlldr on windows xp and Oracle 9i. I´m not DBA an i would like to know if is obligatory anyone grant me permission with dbms_java.grant_permission.

thank you very much for your help



Tom Kyte
May 27, 2004 - 8:32 pm UTC

works on windows.

you need the grant permission on any OS

Works but Sqlloader is hanging and bringing the Databse down

Rajesh Chundi, June 08, 2004 - 2:36 pm UTC

Hi Tom ,
I am using the procedure RC to call sqlloader in a loop in anothe rstored proc for each input file.
if the input file is small it works

even for multiple files, but its hanging and bringing the database down whne the number of records is increased to 6000 of 1column or type number.

what am I missing please help
here is the stroed proc iam Using .

CREATE OR REPLACE PROCEDURE "TKMSYS"."LG2" AS
l_file UTL_FILE.file_type;
l_location VARCHAR2(100) := 'GRADESDIR';
l_filename VARCHAR2(100) := 'fileList.txt';
l_exists BOOLEAN;
l_file_length NUMBER;
l_blocksize NUMBER;
l_text VARCHAR2(32767);
cmdStr varchar2(4000);
procId varchar2(100);
fileSeq number(10);
retVal number(10);

BEGIN
-- Open file.
l_file := UTL_FILE.fopen(l_location, l_filename, 'r', 32767);

select 'LG' ||to_char(sysdate,'mmddyyyyhhmiss') into procId from dual;


-- Read and output first line.
UTL_FILE.get_line(l_file, l_text, 32767);
DBMS_OUTPUT.put_line('First Line: |' || l_text || '|');

-- Read through the file until we reach the last line.
BEGIN
fileSeq:= 1 ;
retVal := RUN_CMD('mkdir c:\UPHS\'||procId);
LOOP
retVal := -99;
UTL_FILE.get_line(l_file, l_text, 32767);

cmdStr := ' sqlldr TKMSYS/do1od3le5@rchundi data=c:\UPHS\' ||l_text ||
' control=c:\UPHS\test.ctl log=c:\UPHS\'||procId ||'\'||replace(l_text,'.txt','.log')||
' bad=c:\UPHS\'||procId ||'\'||replace(l_text,'.txt','.bad') ||
' discard=c:\UPHS\'||procId ||'\'||replace(l_text,'.txt','.dis') ;
-- if(fileSeq =1) then
-- RC('echo ' || cmdStr || '> c:\UPHS\'||procId ||'\loadRaw.bat');
-- else
-- RC('echo ' || cmdStr || ' >> c:\UPHS\'||procId ||'\loadRaw.bat');
-- end if;
DBMS_OUTPUT.put_line( cmdStr );
retVal:= RUN_CMD(cmdStr);
--Rc('exit');
-- DBMS_OUTPUT.put_line( l_text );
fileSeq := fileSeq + 1;
END LOOP;


EXCEPTION
WHEN NO_DATA_FOUND THEN
null;
END;
-- Rc('echo CHR(10)');
-- Output the last line.
DBMS_OUTPUT.put_line('Last Line : |' || l_text || '|');
DBMS_OUTPUT.put_line( 'c:\UPHS\'||procId ||'\loadRaw.bat' );

--RC('c:\UPHS\'||procId ||'\loadRaw.bat CHR(10)');



-- Close the file.
UTL_FILE.fclose(l_file);
END;
/


Tom Kyte
June 08, 2004 - 3:41 pm UTC

sqlldr will not "hang" or "bring down" your database.


run sqlldr from the command line (remove pieces). what happens then?

spurious OutOfMemoryException

A reader, June 16, 2004 - 3:30 pm UTC

Hi Tom,

I'm running the code practically identical to yours, and it gets called several times in succession. And sometimes I'm getting OutOfMemoryException, which gets thrown from

Process p = Runtime.getRuntime().exec(cmd);

Once I catch the first OutOfMemoryException, all the next attempts also fail, until I logout/re-login again.
Do you have any idea what could be causing it?

The command itself is a shell script that calls chmod.

The oracle version is 9.2 and it's running under AIX.

Any ideas would be much appreciated.

thanks,
ilya

Tom Kyte
June 16, 2004 - 4:02 pm UTC

"practically identical"

care to share? does it always reproduce? (eg: if you go into a hard loop and just call it over and over and ask it to run "uptime" or something innocent -- does it eventually bomb?)

spurious OutOfMemoryException

Ilya, June 16, 2004 - 4:51 pm UTC

OK, here's the java code:

public static void executeCommand(String cmd)
throws IOException, java.sql.SQLException {
Process p = Runtime.getRuntime().exec(cmd);
int res;

int bufSize = 4096;
int len;
byte[] buffer = new byte[bufSize];

try {

BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);

//Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1) {
System.out.write(buffer, 0, len);
}

res = p.waitFor();
p = null;
bis.close();
bis = null;
} catch (InterruptedException ex) {
throw new RuntimeException(
"exception while waiting for the process to complete: "
+ ex.getMessage());
}

}


and here's pl/sql test code:

begin
dbms_java.set_output(1000000);
dbms_output.enable(1000000);

for i in 1 .. 100
loop
fileutils_pkg.executecommand('/homedev/ilyam/giftsedd/chmod_edd.sh');
end loop;
end;

and there's also a package fileutils_pkg with
PROCEDURE executecommand(
cmd IN VARCHAR2
)
AS
LANGUAGE JAVA
NAME 'gifts.edd.FileUtils.executeCommand(java.lang.String)';

This runs fine the first time (calling the program 100 times in succession), but usually bombs the second time with this error:

ORA-04030: out of process memory when trying to allocate 4032 bytes (ioc_make_sub2,ioc_allocate_pal)
and the printstack is
java.lang.OutOfMemoryError
at java.lang.Thread.start(Thread.java)
at oracle.aurora.java.lang.OracleProcess.newOutputStream(OracleProcess.java)
at oracle.aurora.java.lang.OracleProcess.construct(OracleProcess.java)
at java.lang.Runtime.execInternal(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at gifts.edd.FileUtils.executeCommand(FileUtils.java:241)

where line 241 is

Process p = Runtime.getRuntime().exec(cmd);

I also tried commenting out all the BufferedInputStream stuff, so that it's simply
public static void executeCommand(String cmd)
throws IOException, java.sql.SQLException {
Process p = Runtime.getRuntime().exec(cmd);
int res;

//int bufSize = 4096;
//int len;
//byte[] buffer = new byte[bufSize];

try {
/*
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);

//Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1) {
System.out.write(buffer, 0, len);
}
*/
res = p.waitFor();
p = null;
//bis.close();
//bis = null;
} catch (InterruptedException ex) {
throw new RuntimeException(
"exception while waiting for the process to complete: "
+ ex.getMessage());
}

}


but the result is exactly the same: succeeds on the first run, fails with OutOfMemoryException the second time.

thanks,
ilya



Tom Kyte
June 16, 2004 - 4:58 pm UTC

how is your java pool size?

spurious OutOfMemoryException

Ilya, June 16, 2004 - 5:12 pm UTC

sorry, I don't know much about java pool size. What do I need to check?



Tom Kyte
June 16, 2004 - 6:09 pm UTC

SQL> show parameter java 

spurious OutOfMemoryException

Ilya, June 16, 2004 - 8:15 pm UTC

NAME TYPE VALUE
------------------------------------ ----------- ----------
java_max_sessionspace_size integer 0
java_pool_size big integer 218103808
java_soft_sessionspace_limit integer 0

Tom Kyte
June 17, 2004 - 7:59 am UTC

I'll have to request you file a tar with support. possible memory leak.

spurious OutOfMemoryException

A reader, June 17, 2004 - 10:53 am UTC

while in the process of creating a tar, I found a similar report of memory leak problem with oracle's JVM, reproducible in 9.2.0.2; it was fixed in 10.0.0

ArrayIndexOutOfBounds

Chris Fischer, June 17, 2004 - 5:18 pm UTC

I've read all the suggestions of going back and doing a ctrl-f to find the comment about this exception.

Here's my problem though. The documented construct for passing an array of strings to a java method in a pl/sql wrapper is to have it declared like this:

public class EchoInput {
public static void main (String[] args) {
for (int i = 0; i < args.length; i++)
System.out.println(args[i]);
}
}


To publish method main, you might write the following call spec:

CREATE OR REPLACE PROCEDURE echo_input (
s1 VARCHAR2,
s2 VARCHAR2,
s3 VARCHAR2)
AS LANGUAGE JAVA
NAME 'EchoInput.main(java.lang.String[])';

This is taken directly from the 9iR2 Java Stored Procedure Developers Guide.

In addition, I have an 8i app that I'm trying to upgrade to 9i, and all my calls to methods similarly fail with ArrayIndexOutOfBounds. I can't believe that Oracle would make a change to the callspec in such a way as to BREAK everyone's app? Oh, I guess everyone being the 5 foolish people to actually USE java in the database.

Tom Kyte
June 17, 2004 - 6:42 pm UTC

in my case, i had a bug in the code (i did it wrong). I was not passing an array of strings.

I'm not sure what you are trying to say?

can you give me a complete test case in the fashion I give to you? with the create or replace java, etc etc etc.

Memory leak

John Dunn, July 14, 2004 - 9:00 am UTC

I am using the following code to run unix commands. I have minimised the memory issues by including a call to the garbage collector, but occasionally it is returning a rc of 3. However I do not know how to output details of the exception. I would like to output the error details to a file. Can anyone help with that?

CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "function_os_command" AS

import java.io.*;

import java.util.*;

public class function_os_command

{

public static int Run(String Command)

{

int rc = 0;

try

{

Runtime rt = Runtime.getRuntime();

Process p = rt.exec(Command);

try {

rc = p.waitFor();

} catch (InterruptedException intexc) { rc = 2; }

rt.gc();

} catch (Throwable t) { rc = 3; }

return(rc);

}

}

/



This Example is Not working On Oracle 9i R2 on Windows

Harshad Savot, July 14, 2004 - 11:04 am UTC

I have tried this example on Oracle 9i R2 Windows.

java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util:14).

What Should change in code so It can works on Windows Platform. Please give any example .
Thanks

Harshad

Tom Kyte
July 14, 2004 - 12:04 pm UTC

ctl-f for arrayindexoutofbounds on this page......... search for that word -- asked and answered.

Having an issue calling a sqlplus shell...

Kelly Taylor, July 23, 2004 - 9:02 pm UTC

Tom,

I'm having a problem using run_cmd in my package for starting dynamic SQL*Plus sessions; I want to pass a connection string and PL/SQL block to a shell script for execution. Everything works fine when calling exp or others, which I've included below. I think it's a quoting problem but I can't seem to find a solution other than completely reformatting the SQL and using sed. If you would provide any insight or advice, I'd seriously appreciate it. :)  RDBMS/OS --> 9.2.0.4/Solaris 8

My code:
--
-- TEST TABLE
--
create table exp_test(id number(22));

--
-- THIS PROC WORKS SHOWING JAVA AND PERMS ARE CORRECT,
-- I USED YOUR LATEST CODE.
--
create or replace procedure run_exp(
    p_exp_conn     in  varchar2,                          -- USERID= 
    p_table_name   in  varchar2,                          -- TABLES= 
    p_dmp_file     in  varchar2,                          -- FILE= 
    p_log_file     in  varchar2 )                         -- LOG= 
is
--
-- Example call: 
--     exec run_exp('user/pass@sid',
--                  'exp_test',
--                  '/tmp/exp_test.dmp',
--                  '/tmp/exp_test.log');  
--
    l_exp_cmd      varchar2(2000) := '/tmp/run_exp.sh';
    l_return       number         := 0;
    
begin
    l_exp_cmd := l_exp_cmd ||'  "'|| p_exp_conn
                           ||'" "'|| p_table_name
                           ||'" "'|| p_dmp_file
                           ||'" "'|| p_log_file
                           ||'"'; 

    l_return := run_cmd(l_exp_cmd);
     
    if l_return = 0 then
        dbms_output.put_line('Exp session succeeded.');
    else
        dbms_output.put_line('Exp session failed.');
    end if;

exception
when others then
    raise;
end run_exp;
/
--
-- THIS IS THE PROBLEM PROC OR QUOTING PROBLEM
--
create or replace procedure run_sqlplus(
    p_sqlplus_conn     in  varchar2,
    p_sqlplus_qry      in  varchar2,
    p_spool_file       in  varchar2 )
is
--
-- Sample call: 
--     exec run_sqlplus('user/pass@sid',
--                      'begin dbms_output.put_line(''Hello''); end;',   
--                      '/tmp/run_sqlplus.log');  
--
    l_sqlplus_cmd      varchar2(2000) := '/tmp/run_sqlplus.sh';
    l_return           number         := 0;
    
begin
    l_sqlplus_cmd := l_sqlplus_cmd ||'   '|| p_sqlplus_conn
                                   ||'  "'|| p_sqlplus_qry
                                   ||'" "'|| p_spool_file
                                   ||'"';
                                   
    dbms_output.put_line(l_sqlplus_cmd);
                  
    l_return := run_cmd(l_sqlplus_cmd);
     
    if l_return = 0 then
        dbms_output.put_line('SQL*Plus session succeeded.');
    else
        dbms_output.put_line('SQL*Plus session failed.');
    end if;

exception
when others then
    raise;
end run_sqlplus;
/

--
-- SAMPLE SHELL SCRIPTS
--
#!/bin/sh
#
# run_exp.sh
# -------------------------
# 
echo userid = $1
echo tables = $2
echo file = $3
echo log = $4

exp userid=$1 tables=$2 file=$3 log=$4 statistics="none" direct="yes"

#!/bin/sh
#
# run_sqlplus.sh
# -------------------------
#
echo conn = $1
echo query = $2
echo spoolfile = $3

sqlplus -s /NOLOG << EOF
connect $1
set serverout on
spool $3
set timing on
begin
    $2
end;
/
spool off
exit
EOF

--
-- TEST sh SCRIPTS
--
$ /tmp/run_exp.sh "user/pass@sid" "exp_test" "/tmp/exp_test.dmp" "/tmp/exp_test.log"

result:
-------
. . exporting table                       EXP_TEST          0 rows exported
Export terminated successfully without warnings.

$ /tmp/run_sqlplus.sh "user/pass@sid" "begin dbms_output.put_line('Hello'); end;" "/tmp/run_sqlplus.log"

result:
-------
conn = user/pass@sid
query = begin dbms_output.put_line('Hello'); end;
spoolfile = /tmp/run_sqlplus.log
Connected.

Hello

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.16

--
-- TEST PROCS
--
set serveroutput on size 1000000
exec dbms_java.set_output(1000000);

SQL> exec run_exp('user/pass@sid', 'exp_test', '/tmp/exp_test.dmp', '/tmp/exp_test.log');

PL/SQL procedure successfully completed. (new dmp file and log were created)

SQL> exec run_sqlplus('user/pass@sid','begin dbms_output.put_line(''Hello''); end;','/tmp/run_sqlplus.log');
/tmp/run_sqlplus.sh   user/pass@sid  "begin dbms_output.put_line('Hello'); end;" "/tmp/run_sqlplus.log"
conn = user/pass@sid
query = "begin
spoolfile = dbms_output.put_line('Hello');
Connected.
ERROR:
ORA-01740: missing double quote in identifier
Elapsed: 00:00:00.00
SQL*Plus session succeeded.

PL/SQL procedure successfully completed. 

Tom Kyte
July 24, 2004 - 11:13 am UTC

whitespace will kill you everytime when you have sh's calling shells and so on.

easiest to just "avoid the issue"

user/pass@connect should never have whitespace
we'll make the reasonable assumption that your spool file name won't either

but the query will....

so arg1 and arg2 are "one word"
arg3 is the rest.  

we change the script to be:

#!/bin/sh
#
# run_sqlplus.sh
                                                                                                   
conn=$1
shift
spoolfile=$1
shift
query=$*
                                                                                                   
echo conn = $conn
echo query = $query
echo spool = $spoolfile
                                                                                                   
sqlplus -s /NOLOG << EOF
connect $conn
set serverout on
spool $spoolfile
set timing on
begin
    $query
end;
/
spool off
exit
EOF


and the plsql to be:

ops$tkyte@ORA9IR2> create or replace procedure run_sqlplus(
  2      p_sqlplus_conn     in  varchar2,
  3      p_sqlplus_qry      in  varchar2,
  4      p_spool_file       in  varchar2 )
  5  is
  6  --
  7  -- Sample call:
  8  --     exec run_sqlplus('user/pass@sid',
  9  --                      'begin dbms_output.put_line(''Hello''); end;',
 10  --                      '/tmp/run_sqlplus.log');
 11  --
 12      l_sqlplus_cmd      varchar2(2000) := '/tmp/run_sqlplus.sh';
 13      l_return           number         := 0;
 14
 15  begin<b>
 16      l_sqlplus_cmd := l_sqlplus_cmd ||' '|| p_sqlplus_conn
 17                                     ||' '|| p_spool_file
 18                                     ||' '|| p_sqlplus_qry;
 19</b>
 20      dbms_output.put_line(l_sqlplus_cmd);
 21
 22      l_return := run_cmd(l_sqlplus_cmd);
 23
 24      if l_return = 0 then
 25          dbms_output.put_line('SQL*Plus session succeeded.');
 26      else
 27          dbms_output.put_line('SQL*Plus session failed.');
 28      end if;
 29
 30  exception
 31  when others then
 32      raise;
 33  end run_sqlplus;
 34  /
 
Procedure created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> set serveroutput on
ops$tkyte@ORA9IR2> exec dbms_java.set_output(100000);
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA9IR2> exec run_sqlplus('/', 'begin dbms_output.put_line(''Hello''); end;', '/tmp/run_sqlplus.log' );
/tmp/run_sqlplus.sh / /tmp/run_sqlplus.log begin dbms_output.put_line('Hello');
end;
conn = /
query = begin dbms_output.put_line('Hello'); end;
spool = /tmp/run_sqlplus.log
Connected.
Hello
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.00
SQL*Plus session succeeded.
 
PL/SQL procedure successfully completed.
 





 

More permissions problems

Mike, July 26, 2004 - 11:58 am UTC

Tom, this is great stuff. As usual. However, I've read all the various permissions solutions in the article so far, but am still having problems.

Calling ls, ps, etc all works great. However, I cannot get any user scripts to run. I created a test script in the Oracle users home directory, owned by Oracle (who also owns and started the database) and checked the execute permissions. Script runs fine at the command line as Oracle, but I get nothing in SQL*Plus and nothing in my debug.txt file when I run it via pl/sql. I granted permissions on /usr/bin/whoami just to verify that Oracle is the user executing these scripts and it is.

Here's my test script:
ls
echo "This is a test..."
date > debug.txt

Any additional thoughts? I'm stumped.

Tom Kyte
July 26, 2004 - 1:24 pm UTC

put a #!/bin/sh at the top, and echo $PATH and other things, check out the environment.

Thanks!

Mike, July 26, 2004 - 1:36 pm UTC

#!/bin/sh solves the problem. Obviously didn't even think of that one. Sorry to bug you with something so simple.

run remotely

fz, October 18, 2004 - 3:30 am UTC

It runs fine locally, but the result does not show up when running remotely through a db_link.  did I miss sth?

LOCAL:
SQL> exec rc('/bin/sar -u 3 3');
....
23:54:34    %usr    %sys    %wio   %idle
23:54:37       0       2       2      96
23:54:40       0       0       2      98
23:54:43       0       0       1      99
Average        0       1       1      98
PL/SQL procedure successfully completed.

REMOTE:
SQL> set serveroutput on size 1000000
SQL> exec dbms_java.set_output(1000000)
PL/SQL procedure successfully completed.
SQL> exec rc@xxx('/bin/sar -u 3 3');
PL/SQL procedure successfully completed.
SQL>

 

Tom Kyte
October 18, 2004 - 8:20 am UTC

when you run the remote procedure -- its "dbms_output" stuff (java output stuff) goes to the REMOTE dbms_output package too.

sqlplus runs dbms_output.get_lines() after each statement to see if there is anything to print -- there isn't anything "local". It doesn't know to look at dbms_output@xxx to get the output.

You'd have to do that yourself -- call dbms_output@xxx to get the lines and use the "local" dbms_output to print them.

Is calling Unix shell from Java sp a reliable way in prod?

Mark Gokman, October 18, 2004 - 2:49 pm UTC

In reference to the original question and examples in this thread. Is this a safe and reliable way of communicating with the OS? I'm not that familiar with JVM in general and the way Oracle runs it, but if JVM is a part of Oracle kernel, then allowing the application to talk almost directly to the OS seems to be strange. For example, what if i call a shell script that changes the structure of the database, or something else that can affects the entire instance? Is there any protection against such operations?


Tom Kyte
October 19, 2004 - 7:40 am UTC

what if you call a stored procedure that alters the structure of the database??
what if you call a stored procedure that affects the entire instance??


not sure what you are concerned about -- YOU write the script, YOU own the script. the script does what you told it to do. This is no less safe than running a pro*c application as Oracle on the database server (well, wait, it is probably lots more safe)

Why is it more secure?

mark Gokman, October 19, 2004 - 1:32 pm UTC

Could you please explain why running os calls from Java sp is more secure and safe than running pro*c on the server as Oracle?

Tom Kyte
October 19, 2004 - 1:52 pm UTC

Pro*c running on the server as Oracle can issue:

system( "rm -rf /home/oracle/" );


Java stored procedures can only run RM if the DBA has said "ok, you can run rm", you have the ability to grant execute on individual OS programs to java stored procedures.

A C program can run anything it wants.

Heck, the C program running as Oracle could attache the SGA if it felt like it (fun stuff maybe...)


you have very very granual access control over the java stored procedure, making it more securable (as long as you don't grant access to "*" or something.

How can pass the parameters ?

raman, October 20, 2004 - 5:51 pm UTC

Hello Tom,

This topic has given me an idea how I can execute host calls from PL/SQL in Oracle server. Finally, I am using like this:

SET SERVEROUTPUT ON SIZE 1000000
CALL DBMS_JAVA.SET_OUTPUT(1000000);
BEGIN
Host_Command (p_command => 'sdelayer -o delete -l TRM_RP_GEOMETRICS_MV,GEOMETRY -i esri_sde9i -s jj00WB316 -u gisteam -p gisteam -N -q');
END;
/

It does SDE registration in Oracle Spatial database.

Table name: TRM_RP_GEOMETRICS_MV
Column Name: Geometry
Username:GISTEAM
Pwd:GISTEAM
Database: JJ00WB316

It is executed successfully. I have to execute such Host_Command procedure 12 times in part of a PL/SQL script for different purposes.

Like that, I have 40 PL/SQL scripts with different table name,column name etc...

Now, I would like to create a procedure which will accept the parameters like tablename,columnname etc....pass them to HOST_COMMAND procedure to execute the DOS command. So, that I don't need to maintain in those 40 scripts.

So, how can I make the HOST_COMMAND procedure accept these parameters??

Example:
CREATE OR REPLACE PROCEDURE A (TABLENAME,COLUMNNAME)
AS
BEGIN

Host_Command (p_command => 'sdelayer -o delete -l <TABLENAME>,<COLUMNNAME> -i esri_sde9i -s jj00WB316 -u gisteam -p gisteam -N -q');


Host_Command (...);
Host_Command (...);
..
..
End;



It would be very helpful to me, if you could give me a solution.

regards,
-raman

Tom Kyte
October 20, 2004 - 8:56 pm UTC

... p_command => 'sdelayer -o delete -l ' || l_table_name || ',' || l_column_name || ' -i ....


just concatenate them into the string.

raman, October 25, 2004 - 11:01 am UTC

Thankyou verymuch ...

but what about this....

Roel, November 25, 2004 - 9:09 am UTC

I created a java program and wrapped it in PL/SQL. I would like to use it to unzip a certain file:

In SQLPLUS >
exec host.run('/bin/unzip -L /app/dphrmo/pvc/f0016741.113 -d /app/dphrmo/pvc/');

Archive: /app/dphrmo/pvc/f0016741.113

PL/SQL-procedure succesfully completed.

But no extraction is made. When I execute the complete command at the Unix prompt the unzip is succesful. When I try to unzip a file - in PLSQL - that already exists, the program 'hangs' logically, because it's waiting to enter a Yes/No/Cancel action for overwriting.

But why is the unzip-action not succesfull?

Tom Kyte
November 25, 2004 - 10:21 am UTC

umm, hows about the entire example. for all i know you are catching and hiding all errors in your java program.

Roel, November 26, 2004 - 3:04 am UTC

The entire (java) program is:

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "Host" AS
import java.io.*;
import java.sql.*;
import java.util.*;

public class Host
{
public static void Dir(String directory)
throws SQLException
{
File path = new File( directory );
String[] list = path.list();
String element;

for(int i = 0; i < list.length; i++)
{
element = list[i];
#sql { INSERT INTO DIR_LIST (FILENAME)
VALUES (:element) };
}
}

public static int Run(String Command)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;
try
{
Process p = rt.exec(Command);

int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream( p.getInputStream(), bufSize );
int len;
byte buffer[] = new byte[ bufSize ];
// Echo back what the program spit out
while (( len = bis.read(buffer, 0, bufSize)) != -1 )
System.out.write(buffer, 0, len);
rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}
/


So (IMHO) the errors are catched but not hided...
Before running the PL/SQL command I also ran:
>exec dbms_java.set_output(1000000)

So what can be wrong?


Tom Kyte
November 26, 2004 - 9:26 am UTC

add debug -- lots of System.out.println's and make sure you can see them.

did you set serveroutput on as well?

Solved!

Roel, November 26, 2004 - 10:47 am UTC

I moved the p.waitFor() direct after the exec(Command) and read out the ErrorStream. Apparently the user (Oracle?) was not allowed to write in the specified directory....

Now it works! Thanx a lot!


Run Java program at Unix file system using Java Stored Procedure using same example.

Mayank, December 08, 2004 - 6:26 pm UTC

I tried the same steps mention by you and grant permissions to all the files.

I am able to run a shell script which contains unix commands, but I am not able to run a small HelloWorld Java program from the shell script.

I want to run a java program from the shell script and call that shell script from the stored procedure in question.





Tom Kyte
December 09, 2004 - 12:51 pm UTC

then you need to figure out why?

your environment is most likely NOT AT ALL what you think it is. Your path is going to be Oracle's path, your environment is going to be Oracle's environment.


read the followup above that can be found by ctl-f'ing for

ran as ORACLE

on this page.

Mayank, December 08, 2004 - 6:38 pm UTC

SQL> exec rc('/usr/bin/sh /home/dhscrp/pass.sh');
run_cmd returned : 1   for /usr/bin/sh /home/dhscrp/pass.sh

PL/SQL procedure successfully completed.
------------------------------------------------
create or replace procedure RC(p_cmd in varchar2)
as
x number;
begin
    x := run_cmd(p_cmd);
    --execute immediate('set serveroutput on size 1000000');
    --dbms_java.set_output(1000000);
    DBMS_OUTPUT.PUT_LINE ( 'run_cmd returned : '||rpad(x, 3, ' ')||' for '||p_cmd);
end;
/

----------------------------------------------------
SQL> create or replace function RUN_CMD( p_cmd  in varchar2) return number
  2  AUTHID CURRENT_USER as  language java
  3  name 'OSUtil.RunThis(java.lang.String) return integer';
  4  /


-------------------------------------------------------

create or replace and compile java source named "OSUtil" as
  import java.io.*;
  import java.lang.*;
  public class OSUtil extends Object
  {
    public static int RunThis(String args)
    {
         Runtime rt = Runtime.getRuntime();
         int        rc = -1;
         try
         {
            Process p = rt.exec(args);
            int bufSize = 4096;
            BufferedInputStream bis =
            new BufferedInputStream(p.getInputStream(), bufSize);
            int len;
             byte buffer[] = new byte[bufSize];
           // Echo back what the program spit out
            while ((len = bis.read(buffer, 0, bufSize)) != -1)
           System.out.write(buffer, 0, len);
              rc = p.waitFor();
      }
      catch (Exception e)
      {
        e.printStackTrace();
        rc = -1;
      }
      finally
      {
         return rc;
      }
     }
   }
/
-------------
I used the same to call a shell script contains java commands to run one java class from Unix OS. It is not doing any thing though it is working for the shell script which contains unix commands only.
 

Tom Kyte
December 09, 2004 - 12:59 pm UTC

see above

Tom you are the best!!!, December 16, 2004 - 1:18 pm UTC

Tom,
Host command via java stored procedures works fine for us.But each time it generates a .trc (trace files) in user dump destination like show below.How we can stop generating this sort of trace files?

dump file c:\oracle\admin\reds\udump\reds_ora_11844.trc
Thu Dec 16 13:10:56 2004
ORACLE V9.2.0.5.0 - Production vsnsta=0
vsnsql=12 vsnxtr=3
Windows 2000 Version 5.2 , CPU type 586
Oracle9i Enterprise Edition Release 9.2.0.5.0 - Production
With the OLAP and Oracle Data Mining options
JServer Release 9.2.0.5.0 - Production
Windows 2000 Version 5.2 , CPU type 586
Instance name: reds

Redo thread mounted by this instance: 1

Oracle process number: 33

Windows thread id: 11844, image: ORACLE.EXE


*** 2004-12-16 13:10:56.590
*** SESSION ID:(35.2353) 2004-12-16 13:10:56.497


C:\oracle\ora92\DATABASE>cmd /k "c:\reds_lims_labels\print_commands\warehouse_medium.cmd C:\reds_lims_labels\13105656CHENNK.lbl > c:\reds_lims_labels\warehouse_medium.log"



Tom Kyte
December 16, 2004 - 1:36 pm UTC

you didn't open up cmd did you???


keys, kingdom come to mind -- you didn't dbms_java and give permissions on cmd?

as usual you are the best tom

you are the best tom, December 16, 2004 - 2:58 pm UTC

.cmd file is working via this java procedure.Can we turn off the trace file generations?

Tom Kyte
December 16, 2004 - 3:39 pm UTC

i'm talking about

...> cmd /k ...


are you using cmd????!? that would be "the keys to the kingdom".

A reader, December 16, 2004 - 3:56 pm UTC

Thanks! We didn't give permission on cmd /k .
We only gave execute permission on the following file.
c:\reds_lims_labels\print_commands\warehouse_medium.cmd .





Tom Kyte
December 16, 2004 - 5:08 pm UTC

why do i see cmd /k in there then?

C:\oracle\ora92\DATABASE>cmd /k
"c:\reds_lims_labels\print_commands\warehouse_medium.cmd
C:\reds_lims_labels\13105656CHENNK.lbl >
c:\reds_lims_labels\warehouse_medium.log"

?

but all you are seeing is the system.out. stuff -- meaning, you didn't call the dbms_java.setoutput to redirect stdout to the dbms_output buffer.

if you run the example "as is" from sqlplus - do you get the trace file then?

A reader, December 16, 2004 - 4:09 pm UTC

Let me explain again.Sorry I din't make it clear.

We didn't give direct permission to cmd /k .

We gave permission to execute the following file

c:\reds_lims_labels\print_commands\submit_warehouse_medium.cmd

submit_warehouse_medium.cmd has the following lines :

cmd /k "c:\reds_lims_labels\print_commands\warehouse_medium.cmd %1 > c:\reds_lims_labels\warehouse_medium.log"

Thanks Tom! Do we have anyway to turn off these trace file generations.

Tom Kyte
December 16, 2004 - 5:10 pm UTC

ok, do you have the stdout redirection going -- do you see this if you run the example as is from sqlplus with all of the commands I've got there.

A reader, December 17, 2004 - 2:11 pm UTC

SQL> execute dbms_java.set_output(99999);

PL/SQL procedure successfully completed.

SQL> set serverout on;
SQL> variable a number;

SQL> execute :a := java_mail_stuff.run_cmd('c:\reds_lims_labels\print_commands\call_ware
.cmd c:\reds_lims_labels\13032121AGARWALAR.lbl');
C:\oracle\ora92\DATABASE>cmd /k
"c:\reds_lims_labels\print_commands\warehouse_medium.cmd
c:\reds_lims_labels\13032121AGARWALAR.lbl >
c:\reds_lims_labels\warehouse_medium.log"

PL/SQL procedure successfully completed.


It didn't generate the trace file when I execute it from the sqlplus. Thanks! 

Tom Kyte
December 17, 2004 - 3:14 pm UTC

you needed to redirect system.out ...

A reader, December 17, 2004 - 4:30 pm UTC

Did you mean that if we do "2>>&1 " like shown below then it would not generate the trace files?

cmd /k "c:\reds_lims_labels\print_commands\warehouse_medium.cmd %1 > c:\reds_lims_labels\warehouse_medium.log" 2>>&1


Tom Kyte
December 18, 2004 - 8:38 am UTC

no, i mean the dbms_java setoutput command redirected the system.out stuff to "dbms_output", by default, that stuff goes to the tracefile.

did you see how in sqlplus you saw on the screen what you normally see in the trace file?

Is it a good idea starting backup script using this technique

A reader, December 18, 2004 - 7:24 pm UTC

I have writen a Java SP to run a host script as mentioned above, and this scripts starts my backup script (since SP waits for the first script to end I wrote an intermadiate script). I have scheduled the SP to start my backup script using DBMS_JOB. All works fine.
Before going to distribute it to 2046 Oracle sites, I want to ask that, is this a good idea for starting backup using this technique?

Tom Kyte
December 19, 2004 - 10:35 am UTC

People typically use scripts outside of the database (eg: via rman or someother backup utility) to do this. It would be unusual to initial the backup from inside the database.


Not having reviewed you code (not saying that we want youy to post it all here!) I cannot say if this is a good idea (tm) or not. If you have tested this 100% and have a backout plan in place, sure.

A reader, December 20, 2004 - 8:09 pm UTC

Thank you for your response.

We have more than 2000 oracle remote sites. Operators of these sites even don't know (and dont care) if they have a DB. We have to perform backups on behalf of the site users.
The users' creativity on destruction made the simple backup script to a backup and one click recovery program.

Most of the sites have only one computer, so rman cannot be used. Using third party backup tools is not feasable for small sites.

Therefore we have to use the backup scripts. The problem comes out managing start time of backup (If we dont start backups, clients never take a backup). Scheduling backup using OS tools (eg. at command) needs administrator password that users dont know, even if they know it is hard to force them to schedule. But scheduling using Oracle job is as simple as running a sql script.

I know scheduling backup using oracle jobs is unusual, that is why I am asking if it is a good idea.

I don't know if here is the right place for the story. Any way here is the code that I use.

------------------------------------------------------------
the java code
------------------------------------------------------------
import java.io.*;

public class Dba {
public Dba() {
}

public static void main(String[] args) {
Dba dba = new Dba();
String arg="";
System.out.println(args[0]);
if (args.length>0) arg=args[0];
runDba(arg);
}

public static void runProcess (String program){
Process proc;
Runtime rt;

rt = Runtime.getRuntime();
try {
proc = rt.exec(program);
Thread.sleep(1000);
}
catch (Exception ex) {
ex.printStackTrace();
}

}

public static void runDba(String param){
runProcess(param);
}

}
------------------------------------------------------------
load java -user <username>/<password> Dba.class
------------------------------------------------------------

create or replace procedure jrun(param varchar2)
as language java
name 'Dba.runDba(java.lang.String)';
/

------------------------------------------------------------
startbackup.bat
------------------------------------------------------------
c:
cd c:\
start %1 %2 %3 (%2 & %3 are optional parameters)
exit
------------------------------------------------------------
backup.bat
------------------------------------------------------------

c:
cd c:\
@setlocal
set CommonProgramFiles=C:\Program Files\Common Files
set COMPUTERNAME=IBRAHIM
set HOMEDRIVE=C:
set HOMEPATH=\Documents and Settings\iozturk
set LOGONSERVER=\\IBRAHIM
set OS=Windows_NT
set Os2LibPath=C:\WINNT\system32\os2\dll;
set Path=C:\Program Files\Java\jdk1.5.0\bin;D:\oracle\product\10.1.0\db\bin;D:\oracle\product\10.1.0\db\jre\1.4.2\bin\client;D:\oracle\product\10.1.0\db\jre\1.4.2\bin;C:\jdk1.5.0\jre\bin;C:\j2sdk1.4.2_05\jre\bin;D:\JBuilderX\jdk1.4\bin;C:\WINNT\system32;C:\WINNT;C:\WINNT\System32\Wbem;C:\Program Files\Symantec\pcAnywhere\;D:\JBuilderX\jdk1.4\bin;D:\Program Files\Adabas\bin;D:\Program Files\Adabas\pgm; D:\Program Files\StarOffice7\program;
set PATHEXT=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH
set ProgramFiles=C:\Program Files
set SystemDrive=C:
set SystemRoot=C:\WINNT
set TEMP=C:\DOCUME~1\iozturk\LOCALS~1\Temp
set TMP=C:\DOCUME~1\iozturk\LOCALS~1\Temp
set USERDOMAIN=IBRAHIM
set USERNAME=iozturk
set USERPROFILE=C:\Documents and Settings\iozturk
C:\j2sdk1.4.2_05\bin\java -cp "%HOMEPATH%\dba_scripts\bin;%HOMEPATH%\dba_scripts\bin\lib\jbcl.jar;%HOMEPATH%\dba_scripts\bin\lib\classes12.jar;%HOMEPATH%\dba_scripts\bin\lib\jdom.jar" dbaController.DbaController backup
REM C:\j2sdk1.4.2_05\bin\java -cp C:\dba_scripts\bin;c:\dba_scripts\bin\lib\jbcl.jar;C:\dba_scripts\bin\lib\classes12.jar;c:\dba_scripts\bin\lib\jdom.jar dbaController.DbaController backup
@endlocal
exit

------------------------------------------------------------

finally schedule it to every friday at 19 PM

VARIABLE jobno NUMBER
BEGIN
DBMS_JOB.SUBMIT(:jobno,
'jrun(''c:\startbackup.bat c:\backup.bat OraLisener stop'');',
SYSDATE, 'NEXT_DAY(TRUNC(SYSDATE), ''CUMA'') + 19/24');
COMMIT;
END;
/
------------------------------------------------------------





Tom Kyte
December 20, 2004 - 8:28 pm UTC

<quote>
I know scheduling backup using oracle jobs is unusual, that is why I am asking
if it is a good idea.
</quote>


the definition of catch-22 here....

It is unusual, therefore I have no real experience with it, hence I cannot commit to saying "good thing" or "bad thing".

I'd probably rather (especially with 2000 of these things) rather have a program that is a little more "in tune with what is happening". How can you tell if this worked or not?


So, using dbms_job -- probably OK

but using a bat file? probably not ok, i'd want something more sophisticated. Maybe your actual backup program is, but I cannot see that here. I'd want a log reported into a central repository or something.

partly successful, but running into a problem

Anurag Mehrotra, February 05, 2005 - 11:32 am UTC

In the past I have successfully implemented the solution mentioned here, now I am trying to take it to the next level.

I am trying to generate Sql loader control file and shell script (on Unix platform) based on parameters passed to a sp and then call the solution mentioned here to launch the shell script.

At first I was running into the following problem:
java.security.AccessControlException: the Permission (java.io.FilePermission <<ALL FILES>> execute has not been granted.

I resolved this by granting the following permision:
dbms_java.grant_permission
('IMPORTUSER',
'SYS:java.io.FilePermission',
'<<ALL FILES>>',
'read,write,execute')

In order to execute the generated shell script, I need to assign the 'x' privilege at the os level, so I granted the following privilege:

dbms_java.grant_permission
('IMPORTUSER',
'java.io.FilePermission',
'/usr/bin/chmod',
'execute');

In spite of all this when I issue the chmod command, and try to launch the shell script, it does nothing:

cmd_return_code := osCommandRun('chmod 744 ' || v_FileDirectory || '/' || v_ShFileName );

cmd_return_code := osCommandRun(v_FileDirectory || '/' || v_ShFileName || ' ' ||
v_CtlFileName || ' ' || a_Data_File_Name );

Sqlplus simply reports "PL/SQL procedure successfully completed", but the permission is neither changed nor the shell script is executed.

Am I missing something here?



Tom Kyte
February 05, 2005 - 11:40 am UTC

why aren't you just using the much easier external table capability???


lauching shell scripts -- and not having them work -- always means "your environment isn't at all what you anticipated"

remember, it is NOT your environment
it is NOT your shell.
it is not alot of things


but --tell me, why no external tables?

followup about shell script

Anurag Mehrotra, February 05, 2005 - 11:58 am UTC

I would have loved to use external tables, but using external tables is not an options.

Damn Corporate security standards. External tables are not on the approved list.

In the meantime I added some debugging statements right as follows:

cmd_return_code := osCommandRun('chmod 744 ' || v_FileDirectory || '/' || v_ShFileName );


DBMS_OUTPUT.PUT_LINE('chMod Command= ' || to_char(cmd_return_code));

cmd_return_code := osCommandRun(v_FileDirectory || '/' || v_ShFileName || ' ' ||
v_CtlFileName || ' ' || a_Data_File_Name );

DBMS_OUTPUT.PUT_LINE('SqlLoader Launch Command= ' || to_char(cmd_return_code));


both return the code of 255.


Tom Kyte
February 06, 2005 - 3:06 am UTC

it is always an option.


would you mind pointing out to the security dudes that external tables are somewhat SAFER then permitting you to run a script as "oracle", on the OS, able to do anything "oracle" is allowed to do, including rm -rf $ORACLE_HOME

your script is not running due to differences in the environment, could be as simple as "i don't know what shell to run" - eg: a missing #!/bin/sh for exmaple.... to the environment is not really setup right.


start small, just try to get:

#!/bin/sh
env


to run or something.

problem somewhat isolated

Anurag Mehrotra, February 06, 2005 - 9:47 am UTC

I will again try to convince the security team about external tables.

I can successfully execute any shell script from within a PL/Sql procedure as mentioned here as long as it has the ‘x’ (execute) privilege set for oracle.

My problem is that I have to create shell script and the control file on the fly (within the stored procedure), I need to first make it ‘x’ executable to be able to run it.

In spite of granting exclusive ‘x’ privilege on ‘chmod’ it does not change the permission and hence cannot execute the shell script. I get a return code of 255 as opposed to 0.

cmd_return_code := osCommandRun('chmod 744 ' || v_FileDirectory || '/' || v_ShFileName );

If I change the permission to 744 for the same file manually at the os level, and re-run the stored procedure, asking for the same file name to be generated, it preserves the execute permission and the successfully executes the shell script to launch the sql loader.

This makes me believe that I am having some trouble running ‘chmod’ command due to some file permissions.

Any ideas?


figured my problem

Anurag Mehrotra, February 06, 2005 - 1:37 pm UTC

I finally figured out my problem:

I had granted the following java permission:

dbms_java.grant_permission
('IMPORTUSER',
'java.io.FilePermission',
'/usr/bin/chmod',
'execute');

but the command to change the permission would not work.

cmd_return_code := osCommandRun('chmod 744 ' || v_FileDirectory || '/' || v_ShFileName );

so I changed the command to:

cmd_return_code := osCommandRun('/usr/bin/chmod 744 ' || v_FileDirectory || '/' || v_ShFileName );

All I did was to prefix chmod with /usr/bin/ and it started working. Even though 'oracle' path was setup correctly with /usr/bin:/usr/ccs/bin:/usl/local/bin: and so on.

I am thinking that when an OS command is executed from within PL/Sql Procedure, it runs in it's own shell and does not inherit any environment/path variables of the parent (in this case 'oracle' user).

Please correct me if I am wrong here.





Tom Kyte
February 07, 2005 - 3:59 am UTC

/usr/bin/chmod <> chmod

that was the cause. if you granted yourself chmod, chmod would work. you granted /usr/bin/chmod, not chmod, so only /usr/bin/chmod will work (if you are specific in one place, you must be so in others)


it makes me laugh in a sad way that your "security" team lets you create any arbitrary shell script and execute it as Oracle - but you cannot use external tables.


How sad and misguided is that. There is zero percent chance I would let anyone create a shell script on the fly like that in real life. How dangerous is that? How insecure is that? How totally POWERFUL is that ability. You can do pretty much anything you want (on purpose by by accident!!!!!)

Trying to exeute a batch file that calls windows scheduler 'AT'

Steve Montgomerie, February 07, 2005 - 10:10 am UTC

Tom,
I am using your procedure here with some success.
I have tested with a simple batch file that does time /t>> c:\temp\test.log. That works fine. 

What I want to do is to schedule a job to run on another server 
through windows AT. For this my batch file contents looks like 'at \\AAAAAAAA 10:34 C:\TEMP\STOP_APP_SERVER.BAT'. I can run this through the command line and also double click the batch file to schedule the job. When Oracle however executes the batch file it does not get scheduled - the procedure completes to success but no joy on the scheduling. 

I execute it through Oracle like so


SQL> variable x number;
SQL> set serveroutput on
SQL> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

SQL> exec :x := RUN_CMD('C:\TEMP\SCHEDULE_APP_SERVER_SHUT.BAT');
D:\oracle\ora92\DATABASE>at \\orlq1aza 14:26 C:\TEMP\STOP_APP_SERVER.BAT

PL/SQL procedure successfully completed.

SQL> commit; 

Tom Kyte
February 07, 2005 - 11:03 am UTC

on windows -- the oracle process is executing as a very "low privileged" user. Not as "you", not as "admin" - as a very low privileged user.

Ask your windows experts onsite how a service running as a low privileged user can get access to remote services

( i would suggest you don't get too carried away with this, this is not looking like a "robust" implementation, there are lots of real job scheduling tools out there -- enterprise manager for example, with error handling and so on)

mapping a network drive on windows within a procedure

Justin, February 10, 2005 - 4:30 pm UTC

Tom,

I am trying to map a network drive from within a stored proc.

Here is what I have done and what I get at the end:

1) Run these as sys

exec dbms_java.grant_permission('PHAME','java.io.FilePermission','C:\WINDOWS\system32\net.exe','execute');

exec dbms_java.grant_permission('PHAME','java.lang.RuntimePermission','*','writeFileDescriptor' );

2) run this as our schema owner

create or replace and compile
java source named "Util"
as
import java.io.*;
import java.lang.*;

public class Util extends Object
{
public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;

try
{
Process p = rt.exec(args);

int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];

// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer, 0, len);

rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}
/

3) run this as our schema owner
create or replace procedure call_net_use(p_cmd in varchar2)
as
x number;
begin
x := NET_USE(p_cmd);
end;
/

4) run this as our schema owner
exec call_net_use('net use j: \\servername\d$ password /user:domain\username');

( The net use command works at the command line of the database server (I have changed the parms to be generic))

I get:

java.security.AccessControlException: the Permission (java.io.FilePermission <<ALL FILES>> execute) has not been granted to PHAME. The PL/SQL to grant this is dbms_java.grant_permission( 'PHAME',
'SYS:java.io.FilePermission', '<<ALL FILES>>', 'execute' )

Do you see the problem?

Thanks very much!

Tom Kyte
February 11, 2005 - 7:44 pm UTC

sorry -- not even going to try to touch this one. network shares and stuff like that under windows is just plain "magic, especially when you involve an underprivileged service like the Oracle service"

services make everything a little different.


that command line test -- totally unrelated to the security/privilege environment the database is running as.


I'm thinking "you don't want to do this" -- really.

ok.. thanks for the input

Justin, February 14, 2005 - 9:58 am UTC


Works like a charm!!!

Deepak Haldiya, March 08, 2005 - 6:29 pm UTC

Hi Tom,

I have been using the code from this thread. It works great!!!

We have a tmp folder from which we want to delete all the files after certain operation.

When I use

exec :x := RUN_CMD('/usr/bin/rm /tmp/xyz.txt') ;

if works fine.

But what I really like to run is
exec :x := RUN_CMD('/usr/bin/rm /tmp/*.txt') ;

to delete all the files from the tmp foler. This does not work.

Any suggestions!!!

Tom Kyte
March 08, 2005 - 7:24 pm UTC

define "does not work"

Deepak Haldiya, March 09, 2005 - 10:49 am UTC

when I meant by "does not work" is that '/usr/bin/rm *.txt' passed as an argument to RUN_CMD does not delete a single file from /tmp folder. Although the procedure successfully completes and i do not get anything in DBMS JAVA OUTPUT.

If I pass the '/usr/bin/rm xyz.txt' then the procedure deletes the file from xyz.txt from the tmp folder.

Thanks



Tom Kyte
March 09, 2005 - 12:57 pm UTC

so, sounds like the * isn't getting expanded because it isn't going through a "shell" and the shell expands * and ?.


it tried to delete a file named "*.txt"


the safest solution is to not use * or ? -- for to fix this, we might have to use a shell script and that gets nasty (security wise)

See Erdal's link above

andrew, March 09, 2005 - 1:22 pm UTC

This link from Erdal (above) might help Deepak: </code> http://www.mountainstorm.com/publications/javazine.html <code>

Tom Kyte
March 09, 2005 - 1:58 pm UTC

please -- consider the ramifications of /bin/sh access!!!!!

think about it, that is why I specifically say "safe" above.


(you want to give an Oracle shell to everyone? think of what can happen)

OS from Jave store procedure

Laxman Kondal, March 22, 2005 - 2:11 pm UTC

Hi Tom

I read you book and this page and wanted to create Java OS command to do export and landed up in many errors.

This one is the one I can not figure out and need your help.
Oracel 9R2 on Redhat Server2.1 and client from where I ran this Windows XP.

I search this page for dbms_java.grant_permission and unable to figure out my own mistake.


scott@TUNE> connect sys/xxxx@TUNE as sysdba;
Connected.
scott@TUNE> begin
2 dbms_java.revoke_permission
3 ('SCOTT',
4 'java.io.FilePermission',
5 '/opt/oracle/9.2.0.1.0/bin/exp',
6 'execute');
7
8 dbms_java.revoke_permission
9 ('SCOTT',
10 'java.lang.RuntimePermission',
11 '*',
12 'writeFileDescriptor' );
13 end;
14 /

PL/SQL procedure successfully completed.

scott@TUNE> rem show err
scott@TUNE> show err
No errors.
scott@TUNE> begin
2 dbms_java.grant_permission
3 ('SCOTT',
4 'java.io.FilePermission',
5 '/opt/oracle/9.2.0.1.0/bin/exp',
6 'execute');
7
8 dbms_java.grant_permission
9 ('SCOTT',
10 'java.lang.RuntimePermission',
11 '*',
12 'writeFileDescriptor' );
13 end;
14 /

PL/SQL procedure successfully completed.

scott@TUNE> show err
No errors.
scott@TUNE> connect scott/tiger@TUNE
Connected.
scott@TUNE> 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 public static int RunThis(String args)
10 {
11 Runtime rt = Runtime.getRuntime();
12 int rc = -1;
13
14 try
15 {
16 Process p = rt.exec(args);
17
18 int bufSize = 4096;
19 BufferedInputStream bis =
20 new BufferedInputStream(p.getInputStream(), bufSize);
21 int len;
22 byte buffer[] = new byte[bufSize];
23
24 // Echo back what the program spit out
25 while ((len = bis.read(buffer, 0, bufSize)) != -1)
26 System.out.write(buffer, 0, len);
27
28 rc = p.waitFor();
29 }
30 catch (Exception e)
31 {
32 e.printStackTrace();
33 rc = -1;
34 }
35 finally
36 {
37 return rc;
38 }
39 }
40 }
41 /

Java created.

scott@TUNE> show err
No errors.
scott@TUNE> 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.

scott@TUNE> show err
No errors.
scott@TUNE> create or replace procedure RC(p_cmd in varchar2)
2 as
3 x number;
4 begin
5 x := run_cmd(p_cmd);
6 end;
7 /

Procedure created.

scott@TUNE> show err
No errors.
scott@TUNE> create or replace procedure run_exp(p_exp_cmd varchar2)
2 is
3
4 l_exp_cmd varchar2(500);
5 l_return number := 0;
6
7 begin
8 --
9 l_return := run_cmd(p_exp_cmd);
10 --
11 if l_return = 0 then
12 dbms_output.put_line('Export session succeeded.');
13 else
14 dbms_output.put_line('Export session failed.');
15 end if;
16
17 exception
18 when others then
19 raise;
20 end run_exp;
21 /

Procedure created.

scott@TUNE> show err
No errors.
scott@TUNE> set serveroutput on size 1000000
scott@TUNE> exec dbms_java.set_output(1000000)

PL/SQL procedure successfully completed.

scott@TUNE>
scott@TUNE> exec run_exp('exp scott/tiger@TUNE, TABLES=(emp, dept), FILE=/tmp/exp_test.dmp, LOG=/tmp/exp_test.log');
java.security.AccessControlException: the Permission (java.io.FilePermission <<ALL FILES>> execute) has not been granted
to SCOTT. The PL/SQL to grant this is dbms_java.grant_permission( 'SCOTT', 'SYS:java.io.FilePermission', '<<ALL FILES>>', 'execute' )
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java)
at java.lang.SecurityManager.checkExec(SecurityManager.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(Util.java:13)
Export session failed.

PL/SQL procedure successfully completed.

scott@TUNE> show user
USER is "SCOTT"
scott@TUNE> begin
2 dbms_java.grant_permission
3 ('SCOTT',
4 'java.io.FilePermission',
5 '/opt/oracle/9.2.0.1.0/bin/exp',
6 'execute');
7
8 dbms_java.grant_permission
9 ('SCOTT',
10 'java.lang.RuntimePermission',
11 '*',
12 'writeFileDescriptor' );
13 end;
14 /

PL/SQL procedure successfully completed.

scott@TUNE> show err
No errors.
scott@TUNE> connect scott/tiger@tune
Connected.
scott@TUNE> set serveroutput on size 1000000
scott@TUNE> exec dbms_java.set_output(1000000)

PL/SQL procedure successfully completed.

scott@TUNE> exec run_exp('exp scott/tiger@TUNE, TABLES=(emp, dept), FILE=/tmp/exp_test.dmp, LOG=/tmp/exp_test.log');
java.security.AccessControlException: the Permission (java.io.FilePermission <<ALL FILES>> execute) has not been granted
to SCOTT. The PL/SQL to grant this is dbms_java.grant_permission( 'SCOTT', 'SYS:java.io.FilePermission', '<<ALL FILES>>', 'execute' )
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java)
at java.lang.SecurityManager.checkExec(SecurityManager.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(Util.java:13)
Export session failed.

PL/SQL procedure successfully completed.
scott@TUNE> select * from dba_java_policy where grantee = 'SCOTT';

KIND GRANT TYPE_SCHEM TYPE_NAME NAME ACTION ENABLED SEQ
-------- ----- ---------- ---------------------- ------------------------- --------------- -------- ---
GRANT SCOTT SYS java.io.FilePermission /opt/oracle/9.2.0.1.0/bin execute ENABLED 75
/exp

GRANT SCOTT SYS java.io.FilePermission /usr/bin/exp execute ENABLED 77
GRANT SCOTT SYS java.lang.RuntimePermi * writeFileDescri ENABLED 76
ssion ptor
GRANT SCOTT SYS java.lang.RuntimePermi /tmp/ writeFileDescri ENABLED 79
ssion ptor


4 rows selected.

scott@TUNE>

What I am doing wrong is obviously I can not find.
Thanks for all the help.

Regards.

Tom Kyte
March 22, 2005 - 6:05 pm UTC

you gave privs to run

/x/y/z

and ran

z

/z/y/z <> z

OS Command from Java Pl Sql

Laxman Kondal, March 22, 2005 - 2:52 pm UTC

Hi Tom

This was my first Java program and one mistakle I found was that path was not correct and then reconnected and worked fine.

begin
dbms_java.grant_permission
('SCOTT',
'java.io.FilePermission',
'/opt/oracle/product/9.2.0.1.0/bin/exp',
'execute');

dbms_java.grant_permission
('SCOTT',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;

I orginally missed /product/ in path.

I will appriciate if you could help me to make it better or your any suggestion.

Thanks

Regards.



Tom Kyte
March 22, 2005 - 6:07 pm UTC

well, it was mostly the orginal code from above, so I think I like it...

OS Command from Pl Sql

Laxman Kondal, March 22, 2005 - 9:04 pm UTC

Hi Tom

Thanks for reply. I have few ....

In one of your follow-up you said

"did you use dbms_java grant permission to grant yourself the needed privs? like my example does?"

If sys as sysdba has granted 'java.lang.RuntimePermission', and execute permission then why do I need to grant it to me again?

Is it required for all users to grant permission to ownself?

After granting privs what’s the reason for reconnecting again to execute? Java cannot see those grant/prives?

Once JAVA SOURCE NAMED "Util" is compiled where can I find compiled code in oracle?

I could not find dbms_java.grant_permission on any document, where is it?

Thanks for you help and wonderful source of knowledge.

Regards.




Tom Kyte
March 23, 2005 - 1:13 am UTC

I asked if you did, i never said "you have to do it twice???"

</code> http://otn.oracle.com/pls/db92/db92.drilldown?remark=&word=dbms_java&book=&preference= <code>

accessing xml file in OS filesystem

A Reader, March 31, 2005 - 6:28 am UTC

I am trying to use a java stored procedure in solaris environment. The java code is accessing a xml file and inserts the data within it into a table in oracle. I am using java.io.File class to create the file object. I am not able to create the file object using following code.

InputSource input = new InputSource(new FileReader(new File("/export/home/stniitd1/interface/inbound/a55progsched/a55_episode_sample.xml")));

when I used System.getProperty("user.dir"), I got following string
/nas/orasoft/baracuda/product/9.2.0/


Tom Kyte
March 31, 2005 - 8:06 am UTC

why aren't you able to create the file object (i have as much information as you would if I said to you "my car won't start, why")

Java Source

Stefan Knecht, April 07, 2005 - 8:59 am UTC

Hello Tom,

i implemented the java code you've shown above, and it works great.

however, when i tried to modify it slightly to this:

CREATE OR REPLACE AND COMPILE JAVA SOURCE named "Util_zip"
as
import java.io.*;
import java.lang.*;

public class Util_zip extends Object
{

public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;

try
{
Process p = rt.exec(args);

int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];


// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer,0,len);

#sql {
CALL scanning.insert_file (:buffer) };

rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}
/
show errors;

oracle throws 01461, 00000, "can bind a LONG value only for insert into a LONG column".
as the byte[] apparently maps to a LONG RAW (?). What i am trying to do is insert the data that the unix command spits back out into a table for later processing.

The procedure being called is very straight forward:

PROCEDURE insert_file (p_file IN VARCHAR2)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO ziplist (file_name) VALUES (p_file);
COMMIT;
END;

i use autonomous_transaction pragma, because this whole thing is being called inside a function. the data integrity should be fine, though as there's no concurrent accesses to this table at all.

The operating system command being called is also working fine, it's a simple shell script that does:
#!/bin/sh
/usr/local/bin/unzip -l $1 | /bin/awk '{ print $4 }' | /bin/grep '\.'

i tried to "fix" the above java to convert this to a datatype oracle would understand, but after 2h of failures (i know enough java to read the source and java.sun.com, but that's not enough anymore here :| ) ... i am hoping you might be able to tell me how to adjust the source to accomplish this task. or maybe you even see a much easier way to do the same trick.

looking forward to your reply, and thanks in advance

Stefan


Tom Kyte
April 07, 2005 - 10:46 am UTC

why wouldn't you use a blob/clob and just stream it right in there in the java?

Error

Andy, April 07, 2005 - 1:09 pm UTC

Hi Tom, I try use this example but when i execute the procedure rc, failure
SQL> exec rc('ls')
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(UTIL.java:15) 

I see the other questions about the error java.lang.ArrayIndexOutOfBoundsException, but all have UTIL.java:14 and for me show UTIL.java.15 (change the number)

It's the same error!?

Thank's 

Tom Kyte
April 07, 2005 - 1:33 pm UTC

yes

Excellent Example

Charlie, April 07, 2005 - 2:50 pm UTC

Out of all the examples of java calling a host command - this one has to be the best. I needed to use logic like this and it works great.

Permission Error

Andy, April 07, 2005 - 6:17 pm UTC

hi Tom again

When i try execute the RUN_CMD function, show me the next error:

B@db9i> exec :x := RUN_CMD('/usr/lib ls')
java.security.AccessControlException: the Permission (java.io.FilePermission /usr/lib execute) has
not been granted to HT. The PL/SQL to grant this is dbms_java.grant_permission( 'HT',
'SYS:java.io.FilePermission', '/usr/lib', 'execute' )
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java)
at java.lang.SecurityManager.checkExec(SecurityManager.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(UTIL.java:13)

I saw the solution for this error: use 2 users, User A give the grants to user B and user B create all the programns (Util,RUN_CMD, RC).

But show me the same error!!! please help me!!

I tryed use SYS user for give grants too

Tom Kyte
April 07, 2005 - 7:06 pm UTC

did you read the error message? it actually shows you the permission you need.


but....

/usr/lib ls

what is that?

In that context, /usr/lib would be a program (but it isn't) and ls would be a parameter to it.

perhaps you meant to try and run something else?

Permission Error - Ok

Andy, April 07, 2005 - 6:52 pm UTC

forgets the previous question, already arrange it...


thanks

But what is the called script able to DO?

Tom Best, April 18, 2005 - 10:03 am UTC

Tom:

This is great for us - we need to call a script from pl/sql, and the external proc thing was giving us trouble. This is cleaner.

One question though - I can get a script to run, such as:

echo Hello world.

But... if the script does something to a file - or creates a directory or anything - I see the echo output, but the file operation does not actually happen.

E.G.

echo Hello World
mv /home/oracle/this /home/oracle/that

I see Hello World (so I know it ran) but file "this" does not become "that".

Is this a permissions thing? Do I need a DIRECTORY object created and have perms on it or something?

Thanks.

Tom Kyte
April 18, 2005 - 10:23 am UTC

mv is a command, might not be in your path. echo might have been.

but can surely be a permission issue, the script is running as the dedicated server userid in the OS. It can only do what that user can do.


Try this,

/bin/touch /tmp/testing


and make sure that /tmp/testing doesn't exist first, if it creates a file, it'll show you "who" you are.

It was the path

Tom Best, April 18, 2005 - 2:00 pm UTC

That fixed it. It was the path. The user was indeed oracle, but the path was not setup in the script.

Thanks again.

Execute command at client side(Windows XP)

Morg, April 27, 2005 - 3:03 pm UTC

Dear Tom,
I want from client side (Windows XP,Plus80w) to execute a dos command like (Copy file) using PL/SQL and kindly note that client connect to database 9i on unix server.

Tom Kyte
April 27, 2005 - 3:23 pm UTC

not going to happen.

PLSQL runs on the server, not on the client (unless you are running forms but even then it is running in the middle tier).

sqlplus can run a host command on the client. but plsql cannot.

Calling exp/imp from java

Laxman Kondal, May 19, 2005 - 5:54 pm UTC

Hi Tom

I need your help to solve this export/import from java class which I got from this site. It works fine and its realy great and when I wanted to test it with wrong username/password hangs, waitng for username/password.

Since I am calling from pl/sql there is no way I can kill this.

Could you please help me to figure out how to fix this.

Thanks


Tom Kyte
May 20, 2005 - 7:07 am UTC

kill it at the OS level (and then understand what a mistake this could be -- calling a program that tries to interact with a user....)

Calling exp/imp from java

Laxman Kondal, May 20, 2005 - 7:12 am UTC

Hi Tom
Thanks for reply.

We did kill it from OS but I was trying to find if any way java code can be alterd to cater for this eventually.

Anoter alternate was to hard code username/pwd which may not be desirable.

Thanks and regards.

Tom Kyte
May 20, 2005 - 8:08 am UTC

only host out to things that will NEVER interact with the end user.

off topic ...

Paul, May 20, 2005 - 10:41 am UTC

Tom - what's going on today? The 'last updated'for 20 May 2005 8am appears on one line for questions 1 to 10, and straddles 2 lines for questions 11 to 20?



Tom Kyte
May 20, 2005 - 6:26 pm UTC

changed nothing, window width perhaps on your screen?

print to file

rye, May 20, 2005 - 12:27 pm UTC

hi tom,
execellent stuff. what i'm trying to do is execute a .bat file that calls a vbscript that prints a ms word doc to pdf. everything works great from the commandline. when i try and run it using your proc, the word doc opens and gets sent to the pdf writer, but hangs there. in other tests, i have been able to sucessfully print to a regular printer using the proc. any ideas on what could be preventing me from printing using the pdf writer?


Tom Kyte
May 20, 2005 - 6:36 pm UTC

windows...
the database is running in a different environment -- it doesn't have your "printers", "shares" etc - it has IT'S set up --

it is running as a service, you'll need to find a windows guy to help you get a service to know about other stuff like that.

Any addvice on remote progam calls?

Rene, May 30, 2005 - 5:39 am UTC

The initial solution is very cool! But what would I do, if I have to call a binary on a different server, that is not running an Oracle database? (Otherwise I could call a procedure on the remote oracle server, which then calls the program locally....)

The company's policy is to not allow anything else on the Oracle server (which is okay with me).

The environment is Oracle 9i (9.2.0.6.0) on Windows 2000 Server.
The "remote" program is on a different Windows 2000 Server.

So, how can I call a program that is on a different server in this environment?

Do you have any ideas or hints (it seems to be a windows specific problem) how do I do a "remote call" from the Oracle database to the other server?

Sincerly, Rene

Tom Kyte
May 30, 2005 - 9:05 am UTC

You'll have to ask your system and security folk (remote program execution can be very "virus like").

Say the remote machine has an application server, you could invoke it via a URL (utl_http).

Say the remote machine has no security, you could use some windows command line to to a remote program execution.


But this is something you need to solve "outside" of Oracle first. Just make it so this database server can run that remote program. Once you figure that out given you OS's, your security, your setup , we can proceed from there.

host call fails on Linux 10.1.0.3/10.1.0.4

Pete, June 07, 2005 - 10:20 pm UTC

Tom,

I've used the Util class since ver 817 ->10.1.0.2 with no issue at all.
When running same code after the upgrade I'm getting
ERROR:
ORA-03114: not connected to ORACLE

BEGIN rc('/bin/ps -ef'); END;

*
ERROR at line 1:
ORA-03113: end-of-file on communication channel

No trace files to find in udump/bdump. I also tried putting dbms_output and java system.out.. but the connection aborts and never finishes and I'm not getting any debug info at all.
In addition to the specific grants I've also granted javauserpriv, javasyspriv but no different result.
Is anyone aware of anything that has changed in the ojvm that makes this non backward compatible ?

exec dbms_java.grant_permission('IRIS', 'java.io.FilePermission', '/bin/ps','execute');
exec dbms_java.grant_permission('IRIS', 'java.io.FilePermission', '*','read,write');


create or replace and compile
java source named "Util"
as
import java.io.*;
import java.lang.*;

public class Util extends Object
{
public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;

try
{
Process p = rt.exec(args);

int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];

// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer, 0, len);

rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}
/
create or replace
function RUN_CMD( p_cmd in varchar2) return number
as
language java
name 'Util.RunThis(java.lang.String) return integer';
/
create or replace procedure RC(p_cmd in varchar2)
as
x number;
begin
x := run_cmd(p_cmd);
end;
/

set serveroutput on size 10000
exec dbms_java.set_output(1000)
exec rc('/bin/ps -ef');


Tom Kyte
June 08, 2005 - 8:17 am UTC

not sure on the 3114, I cannot reproduce that at all.

but in 9i and 10g for me -- I had to wrap the ps call in a script to get the environment set up properly.

Have you checked the execution environment (eg: run /bin/env instead?)




Connected to:
Oracle Database 10g Enterprise Edition Release 10.1.0.4.0 - Production
With the Partitioning, OLAP and Data Mining options

worked straight away for me.

Further investigation of ORA-3113

Pete, June 08, 2005 - 1:31 pm UTC

To further narrow down the issue - I created a new user and granted as sys
EXECUTE dbms_java.grant_permission( 'HST60','SYS:java.io.FilePermission','<<ALL FILES>>','execute'); 
EXECUTE dbms_java.grant_permission( 'HST60','SYS:java.io.FilePermission','*','read,write'); 
EXECUTE dbms_java.grant_permission( 'HST60','SYS:java.lang.RuntimePermission','writeFileDescriptor','*' ); 
EXECUTE dbms_java.grant_permission( 'HST60','SYS:java.lang.RuntimePermission','readFileDescriptor','*' );
Next I created the class and stored procs using above code

To verify that the host call gets executed I did:

SQL> set serveroutput on size 10000
exec dbms_java.set_output(1000)
exec rc('/bin/env');SQL> 
PL/SQL procedure successfully completed.

SQL> 
java.io.IOException: can't exec: /bin/env doesn't exist

-ok my host call is attempted - I then proceeded with

Oracle Database 10g Enterprise Edition Release 10.1.0.3.0 - Production
With the Partitioning, OLAP and Data Mining options

SQL> set serveroutput on size 10000
exec dbms_java.set_output(1000)
exec rc('/usr/bin/env');SQL> 
PL/SQL procedure successfully completed.

SQL> 
ERROR:
ORA-03114: not connected to ORACLE


BEGIN rc('/usr/bin/env'); END;

*
ERROR at line 1:
ORA-03113: end-of-file on communication channel


SQL> !/usr/bin/env
LESSKEY=/etc/lesskey.bin
MANPATH=/usr/local/man:/usr/share/man:/usr/X11R6/man:/opt/gnome/share/man
INFODIR=/usr/local/info:/usr/share/info:/usr/info
NNTPSERVER=news

Script without environment fails
I then tried a script that sets environment and then executes

SQL> set serveroutput on size 10000
exec dbms_java.set_output(1000)
exec rc('/opt/iris/bin/shell.sh /usr/bin/env');SQL> 
PL/SQL procedure successfully completed.

SQL> 
ERROR:
ORA-03114: not connected to ORACLE


BEGIN rc('/opt/iris/bin/shell.sh /usr/bin/env'); END;

*
ERROR at line 1:
ORA-03113: end-of-file on communication channel

Shell.sh - I noted that the file hallo didn't get created 
oracle@risqube:~> more /opt/iris/bin/shell.sh 
#!/bin/sh
PATH=${PATH}:/opt/iris/bin:/bin:/usr/bin
export PATH
system "echo hallo >/opt/iris/log/hallo";
eval $*


java_pool_size 64M
large_pool_size 16M
I was thinking that maybe the java parameters could affect this but the fact that the db is running java stored procedures and javamail just fine so the ojvm is working - there are no invalid classes - the host call is the problem - Any ideas to troubleshoot this much appreciated

Many Thanks
Pete 

Tom Kyte
June 08, 2005 - 1:49 pm UTC

you'll want to work with support, they can help you set events to create trace information and debug this.

Executing shell scripts and passing parameters to

Azmat, June 26, 2005 - 12:45 pm UTC

Tom,

I have a shell script which accepts two parameters and creates a text file, this works good on unix environment. I need to call this scripts from PL/SQL environment so that I can store the generated file in a BLOB column and later display it on browser. How would I do it? Here is my shell call in unix environment.

$ itg.sh -a P -b 10 -out abc.txt

where itg.sh is a shell script, P and 10 are the two parameters value for -a and -b respectively and -out is is used for out parameter and result is abc.txt file. I want to store this text file on a BLOB column to display it on browser?

Thank you

Tom Kyte
June 26, 2005 - 1:55 pm UTC

you want to store text in a clob.

but, this page shows you how to run a shell script from plsql and then dbms_lob.loadfromfile will be useful to get the generated text file into the database.

But, if you just want to display it on the browser, you could also just use a BFILE instead of a lob in the database -- if the data is not going to persist for any duration of time.

executing shell script from DB

Azmat, June 26, 2005 - 11:00 pm UTC

Actually, I meant to ask if I can use following procedure ( created in this thred earlier) to run my shell script.

sql>exec run_exp('itg.sh -a P -b 10 -out abc.txt');

I am not sure if this will run or not. I wanted to be sure about this before asking all the permission ( dbms_java.grant_permission) from our DB group.

Thank you



Tom Kyte
June 27, 2005 - 7:02 am UTC

yes, you can run shell scripts.

RE: mapping a network drive on windows within a procedure

Edgar, June 27, 2005 - 2:47 am UTC

Hi,

Oracle by default on Windows run as service under LOCAL_SYSTEM account.

Because of Windows security features, LOCAL_SYSTEM is prohibited to USE network mapped drives.

Because of that, for example, you cannot use RMAN to disk-to-disk backup to network mapped drive, you cannot set ARCHIVE_LOG_DEST_n to network mapped drive.

There is a workaround (i find on Metalink) : you can change ownership of Oracle services (database, listener) to someone another user account (Administrator).
I don't remember Note #.

OS cp command

Laxman Kondal, July 15, 2005 - 3:29 pm UTC

Hi Tom

I have used run_cmd function for exp, imp and sqlldr and this 'cp' command I need your help please to work. 

SQL> exec :x := run_cmd('cp /tmp/exh_hi.dmp /tmp/exp_hi_1.dmp')

PL/SQL procedure successfully completed.


         X
----------
        -1

SQL>

This is the permission granted as sys

begin      
      dbms_java.grant_permission
      ('OPO_USER',
       'java.io.FilePermission',
       '/bin/cp',
       'execute');
         

      dbms_java.grant_permission
      ('OPO_USER',
      'java.lang.RuntimePermission',
      '*',
      'writeFileDescriptor' );    
end;
/

I used different files to copy .dmp, .txt, and .log - all in /tmp/ but all exit codes are -1.

What's I am missing or doing something wrong.

Thanks and regards. 

Tom Kyte
July 15, 2005 - 6:17 pm UTC

/bin/cp <> cp



OS cp command

Laxman Kondal, July 15, 2005 - 11:43 pm UTC

Hi Tom

Thanks for reply.

I am not sure about '/bin/cp <> cp' it should be in dbms_java.grant_permission and is it reqire to have '<>' for all os command?

Thanks and regards



Tom Kyte
July 16, 2005 - 9:16 am UTC

/bin/cp is not the same text as cp

cp might resolve to /usr/bin/cp or /home/badguy/cp or whatever


if you grant permission on /bin/cp, then you need to run /bin/cp.

And you should grant on /bin/cp, not just cp, so you know the right cp is being used and not a trojan horse cp.

What bout timeout

Denis, July 27, 2005 - 6:29 pm UTC

Tom, if I run some command and it is hanging, it would be very helpfull to be able to set timeout. Could you advice how to do it?

I need to run "scp" command on windows to transfer files between servers using public and private keys. I need to cache the key under account oracle is running. What is Windows account name oracle is running under?

Tom Kyte
July 27, 2005 - 8:41 pm UTC

commands typically do not "hang", they are doing something that takes a long time (AND it takes even longer in general to "undo" what they did).

Some things like waiting for a row to lock it can be waited for (for update wait <n>) but you program that into the transaction.

No idea what "scp" is - but you pick the service attributes for Oracle, you pick who it runs as if you want. If you are using 10g, you can look at dbms_file_transfer to move files between Oracle instances. But look at your service and see what it is set to run as.

timeout

Denis, July 28, 2005 - 2:40 pm UTC

Tom,

For example, I call command which loads data from table to flat file using sqlplus (</code> http://asktom.oracle.com/~tkyte/flat/index.html <code>. If I put there wrong filename and run manuallly from console, I will get an error message. If I run it from pl/sql using this java class, it will hang. is there any kind of timeout solution?



Tom Kyte
July 28, 2005 - 3:44 pm UTC

You must be excessively careful when calling interactive programs from any environment that isn't interactive though. Period.

but you could change the java class to poll for output instead of block on output if you like and time out - but then you have that nasty problem of "that thing is still out there" to deal with.

Best to ensure whatever you call is NOT interactive under any circumstances.

Hang or not to hang

Marcelo, July 28, 2005 - 8:17 pm UTC

Extracted from the comment above...

/quote
commands typically do not "hang", they are doing something that takes a long time (AND it takes even longer in general to "undo" what they did).
/quote

At the point of view of the database, it is true. But when running something in Windows it can (and surely will) hang. And I believe in this case the OS is really doing something, but that will never finish :)


Tom Kyte
July 29, 2005 - 8:18 am UTC

I was thinking of commands in the sense of a sql command. But, you are free to rewrite the java stored procedure in a polling fashion -- it is just code, you can in fact make it do whatever you like!

timeout and errors

Denis, July 28, 2005 - 9:34 pm UTC

Tom, maybe then in this case using DBMS_SCHEDULER is better idea? If it command fails, job fails. Nothing is hanging.

From other hand I tried to incorporate timeout into your code
and put this inside try block:

if (timeout > 0) {
Thread destroyProcess = new Thread() {
public void run() {
try {
sleep(timeout);
} catch (InterruptedException ie) {
} finally {
p.destroy();
}
}
};
destroyProcess.start();
}

But started getting interesting behavior. If my commands where correct, command did succeded but I got an error(below). if command is incorrect, I was getting the same error right away:

ORA-29516: Aurora assertion failure: Assertion failure at sjonio.c:128
WaitForMultipleObjects failed: errno = 6

Maybe we can't do timeout because java in oracle PL/SQL is single-threaded?

But even in case we don't need timeout, when we get error message right way, It is strange not to be able to through an error from Java (stop process and return -1) , if command failed. SQL server has similar functionality CMDSHELL extended stored procedure. But it throughs en error in case command is incorrect.

So using your code PL/SQL will always hang if command through an error? Right?

Thanks



Tom Kyte
July 29, 2005 - 8:22 am UTC

the problem is, the job would hang forever.

They have a command running that is waiting for the user to hit the enter key.

The user never will hit the enter key.

The job will be stuck forever.


POLL for data, don't do anything that blocks.

Trouble Executing Shell Script

TH, August 03, 2005 - 11:33 am UTC

Hey Tom

Thanks so much for this script. I think its going to change the way we do Data Warehousing forever because we can now do all of the things that we need to do from our Oracle packages.

One thing I have yet to figure out, is how to automate decryption of files using gpg. I have a script that automatically decrypts all the files in the same folder as the script. I can run the sh script that we have from a prompt, and it works fine, but when I run it via the procedure RC - it completes successfully, but does not actually execute the file. The return value is 127.

Any ideas?

Tom Kyte
August 03, 2005 - 12:06 pm UTC

well, if you are going to automate the decryption of something like this, one wonders why they are encrypted in the first place.


put debug into the script -- 999 times out of 1000 it is an environment issue. printout your environment, echo commands, redirect it to a "trace" file in tmp

Actually....

TH, August 03, 2005 - 2:34 pm UTC

I was wondering what the return value from the java means. I looked up the WaitFor() method, and it looks like is pauses the process, waiting for the thread to finish, and then kills it. It says that a return of 0 is normal. Anything other than that is not. What does the number that it returns represent?

As for why we are trying to automate encryption - the encryption is only to get the file from an outside source into our network.

Thanks!

Tom Kyte
August 03, 2005 - 5:57 pm UTC

I guess it means "not normal", it should probably be the return code from the shell script.

time to add debug to it! almost always an environment issue (bad path, missing something). remember the script runs in a "pristine, different, ORACLE environment separate from yours"

Still stumped....

TH, August 04, 2005 - 3:36 pm UTC

Tom - You can preface your response with how sick of me you are - i wont be offended. Im sick of me on this issue too.

I have a .sh file that runs to decrypt some files automatically. The problem is that the gpg binary is in a different directory, and even if I give the absolute path of the dir, it still does not work -- so the .sh looks like this...

!#/bin/sh
cd /stage/incoming
/usr/local/bin/gpg --decrypt-files *.pgp
exit

I know that the problem here is ennvironment, but I cannot figure out what to do to rectify it. I have had the Unix guys look at this and do everything they can to rule out an environment issue. I just dont know enough about Unix to know what to do next. I think the problem has to do with the gpg residing in a different directory than the files I want to decrypt.




Tom Kyte
August 04, 2005 - 8:40 pm UTC

does gpg have a "verbose mode"

do you know how to redirect stdout AND stderr to a tmp file (capture any and all output from gpg)


oh, and how does gpg work? where does it get the encryption keys from? how does it know where to find them?

calling Java program from PL/SQL.

Rajesh, August 22, 2005 - 10:18 am UTC

I want to call a java program from my pl/sql block. When I wrote a small program like this

create or replace and compile
java source named "Util"
as
public class Util {
public static String hi() {
System.out.println ("tracing here");
return "hello there";
}
}


the following error occured. Why? what can be the cause. I am using oracle 9i. Please help me!!!!

ERROR at line 2:
ORA-00600: internal error code, arguments: [KSMASG1], [4032], [4032], [], [],
[], [], []



Tom Kyte
August 23, 2005 - 3:58 am UTC

ora-600 always means "please contact support"


ops$tkyte@ORA9IR2> create or replace and compile
  2  java source named "Util"
  3  as
  4  public class Util {
  5    public static String hi() {
  6      System.out.println ("tracing here");
  7
  }
  7      return "hello there";
  8    }
  9  }
 10  /

Java created.

especially since it doesn't reproduce universally

 

dave, August 23, 2005 - 6:29 am UTC

take a look at metalink note 4014485.8

Looks like this could be for you

calling Java programs from PL/SQL

Rajesh, August 23, 2005 - 8:24 am UTC

Thank You very much. Java package was not installed initially. After installation it worked.

Java Program from PL/SQL

Rajesh, August 24, 2005 - 5:21 am UTC

I am importing these class files in my Java program.

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.openssl.PEMReader;

import java.security.interfaces.RSAPrivateKey;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.jce.provider.JCERSAPublicKey;

The code is working in Windows NT in java compiler.
My intention is to create a java source for this in oracle. So that i can access the methods described in the java program. which runs in unix box.

I have set the class path in unix box like this

export CLASSPATH=$CLASSPATH:$HOME/bcmail-jdk13-129.jar:$HOME/bcpg-jdk13-129

But I am getting error like this...

Class org.apache.commons.codec.binary.Base64 not

found in import.



0/0 Encropt:8: Class org.apache.commons.codec.binary.Hex not found

in import.



0/0 Encropt:9: Class org.bouncycastle.openssl.PEMReader not found in

import.



0/0 Encropt:11: Class

org.bouncycastle.jce.provider.BouncyCastleProvider not found in



LINE/COL ERROR

-------- -----------------------------------------------------------------

import.



0/0 Encropt:12: Class org.bouncycastle.jce.provider.JCERSAPublicKey

not found in import.



0/0 Info: 5 errors



What is the problem here? Is it the problem with my classpath settings. I opened the jar file in winzip and searched for the class files. the class files are there.


Tom Kyte
August 24, 2005 - 10:57 am UTC

you have to load the jars into the database, your classpath isn't relevant, everything must be contained within the database.

Loved it as always

Dmitriy N., September 06, 2005 - 5:33 pm UTC

I found exactly what I needed

Error: The handle is invalid.

Raman, September 07, 2005 - 3:08 pm UTC

Hello Tim,

When I run this small program for testing .... get this error:

SET SERVEROUTPUT ON SIZE 1000000
CALL DBMS_JAVA.SET_OUTPUT(1000000);
BEGIN
Host_Command (h_command => 'move C:\apr.txt D:\apr.txt');
END;
/


The handle is invalid.

PL/SQL procedure successfully completed.

What would be your suggetion ?? Any clue ??

regards,
-Raman

Tom Kyte
September 07, 2005 - 3:44 pm UTC

that would not be the full error stack would it.

Raman, September 07, 2005 - 3:55 pm UTC

This is the only error I get it ... At first I used to think, there's something wrong in my procedure where I used HOST command ... after debugging I found out that Java procedure is causing the error:

I have re-created every thing :

- Created Java Procedure
- PL/SQL wrapper
- Granted Privileges

EXEC Dbms_Java.Grant_Permission('SCHEMA-NAME', 'java.io.FilePermission', '<>', 'read ,write, execute, delete');

EXEC Dbms_Java.Grant_Permission('SCHEMA-NAME', 'SYS:java.lang.RuntimePermission', 'writeFileDescriptor', '');

EXEC Dbms_Java.Grant_Permission('SCHEMA-NAME', 'SYS:java.lang.RuntimePermission', 'readFileDescriptor', '');

- Tested it.


Could you please suggest me what to do to get rid of this error:

thanks.

Tom Kyte
September 07, 2005 - 7:34 pm UTC

no, because that error would not appear all by itself like that.


make a small 100% complete test case for us to look at.

Raman, September 09, 2005 - 12:04 am UTC

I had to run 'rmjvm.sql' and 'initjvm.sql' scripts ....
With companion CD, got rid of 'JAccelerator' error ...
Finally it works ....

thanks.

Command not executed

Mody, September 21, 2005 - 4:30 am UTC

Dear Tom,
I have create file mk in folder /home/oracle ,this file contains one line (mkdir /home/oracle/test),
then I use you example with some small modifications ,
the procedure runs well but the directory isn't created.

begin
dbms_java.grant_permission
('MKT',
'java.io.FilePermission',
'/home/oracle/mk',
'execute');

dbms_java.grant_permission
('MKT',
'java.io.FilePermission',
'/home/oracle/mk',
'execute');

dbms_java.grant_permission
('MKT',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;
/


create or replace and compile
java source named "Util"
as
import java.io.*;
import java.lang.*;

public class Util extends Object
{

public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;

try
{
Process p = rt.exec(args);

int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];
// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer, 0, len);
rc = p.waitFor();
}
catch (Exception e)
{
System.out.println("exception ya man");
e.printStackTrace();
rc = -2;
}
finally
{
return rc;
}
}
}
/

create or replace
function RUN_CMD( p_cmd in varchar2) return number
as
language java
name 'Util.RunThis(java.lang.String) return integer';
/


create or replace procedure RC(p_cmd in varchar2)
as
x number;
begin
x := run_cmd(p_cmd);
end;
/

set serveroutput on size 1000000
exec dbms_java.set_output(1000000)
exec rc('/home/oracle/mk');


Tom Kyte
September 21, 2005 - 7:11 pm UTC

likely a path problem.

mkdir is a "program"

so, is mkdir in the path of the oracle dedicated servers environment (best for security and because of this to be explicit -- /path/to/mkdir

and make sure the script starts with #!/bin/sh or whatever.

Run a Oracle Report through pl-sql

Nikhilesh, October 05, 2005 - 1:05 am UTC

Dear Tom,
I'm trying to run a Oracle Report from pl-sql(the report generates a .pdf file to a specific location).
Using java I'm able to run the commands like ps and ls but I'm not able to run rwclient.sh. I fact I want to run

exec rc('/u01/app/oracle/product/dev/bin/rwclient.sh server=myserver report=/export/home/myhome/my_rep.rdf userid=my_user/my_password@my_service desformat=pdf destype=file desname=/export/home/my_home/name/test.pdf')

Is it possible?? Should I keep on trying??
Please mention what will be the privileges I will require to run this.

Thanks a lot in advance........



Tom Kyte
October 05, 2005 - 7:11 am UTC

remember, the environment is "different" here - you might create a script that dumps the environment using '/bin/env' or whatever (use full qualified commands - you don't even know what the PATH is)

set all environment variables EXPLICITLY

and make sure the script starts with

#!/bin/shellname


if you read through this page - we've discussed this times before - you can run scripts.

What permissions are required??

Nikhilesh, October 06, 2005 - 12:59 am UTC

Dear Tom,
Thanks for your reply. Yesterday I could generate the report running script file through pl-sql. And as you said before running that I had run one extra script file which sets the environment before generating .pdf file report.
But the problem is I have granted read permission (using dbms_java.grant_permission)to all the files i.e. script and .rdf.
Now I want to know Do we need to grant the permission to the script file we are running or to all of the script files and the .rdf files we are using in the main script file?? Will this method be secure??


Tom Kyte
October 06, 2005 - 7:44 am UTC

you do not need the grants to read all of that, once the script is running, it is quite out of our control what you can and cannot access - the operating system is in charge at that point.

you only need to permissions to run the script.

A reader, October 06, 2005 - 1:17 pm UTC

If we want to send the control to background ( like & in unix) by using dbms_job.submit(a, 'RC(something);') ,
Do we have any way to check the value of X varibale to see the run_cmd(p_cmd) is successfull or not?

create or replace procedure RC(p_cmd in varchar2)
as
x number;
begin
x := run_cmd(p_cmd);
end;



Tom Kyte
October 06, 2005 - 1:46 pm UTC

sure, if the job you submit, that runs in the background were to notify you someway after the job completed (wrote a row into a table for example....)

A reader, October 11, 2005 - 6:29 pm UTC

To,

We just migrated our database from solaris to Linux. We had few java stored procedure (mostly copy from your site -like reading files from directory etc..). Suddenly it stops working in linux. Also I have notied that we have to grant permission on specifice file and directory permission is not working (java.io.FilePermission). for eg. if i have want to read file on /user/bin/ directory then i have grant permission on the file. directory permission is not working. Could you please help us.

note - We exported database from solaris and impored it into linux os using oracle export and import.
Do we have to recreate JVM? ie do we have to run
/javavm/install/rmjvm.sql
/javavm/install/initjvm.sql

again ?

appreciate any help
thanks




Tom Kyte
October 12, 2005 - 7:06 am UTC

examples? (i developed almost all of my examples on linux in the first place)

did you also happen to change *versions* of the database whilst doing this?

A reader, October 11, 2005 - 6:47 pm UTC

To,

We just migrated our database from solaris to Linux. We had few java stored procedure (mostly copy from your site -like reading files from directory etc..). Suddenly it stops working in linux. Also I have notied that we have to grant permission on specifice file and directory permission is not working (java.io.FilePermission). for eg. if i have want to read file on /user/bin/ directory then i have grant permission on the file. directory permission is not working. Could you please help us.

note - We exported database from solaris and impored it into linux os using oracle export and import.
Do we have to recreate JVM? ie do we have to run
/javavm/install/rmjvm.sql
/javavm/install/initjvm.sql

again ?

appreciate any help
thanks




A reader, October 12, 2005 - 9:32 am UTC

Hi Tom,

We upgraded our database from 8.1.7.4 to 9.2.0.6.

getting following errors

java.security.AccessControlException: the Permission (java.io.FilePermission /nfsprod2/mkt read) has not been granted to SBLINT. The PL/SQL to grant this is dbms_java.grant_permission( 'SBLINT', 'SYS:java.io.FilePermission', '/nfsprod2/mkt', 'read' )
at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
at java.security.AccessController.checkPermission(AccessController.java)
at java.lang.SecurityManager.checkPermission(SecurityManager.java)
at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java)
at java.lang.SecurityManager.checkRead(SecurityManager.java)
at oracle.aurora.rdbms.SecurityManagerImpl.checkRead(SecurityManagerImpl.java)
at java.io.File.list(File.java)
at java.io.File.listFiles(File.java)
at DirListName.getDirList(DirListName.java:8)

we are reading file (test.txt) from '/nfsprod2/mkt' dir and we have already granted this permisson

dbms_java.grant_permission( 'SBLINT', 'SYS:java.io.FilePermission', '/nfsprod2/mkt', 'read' )


Do I have do

dbms_java.grant_permission( 'SBLINT', 'SYS:java.io.FilePermission', '/nfsprod2/mkt/*', 'read' ) to select all files ??

Thanks




Tom Kyte
October 12, 2005 - 1:54 pm UTC

can you show me

a) you doing the grant
b) reconnecting
c) running the procedure and getting the failure

as a cut and paste from sqlplus

Is there a problem with this in version 10.1.0.3 ?

Holger Schweichler, October 14, 2005 - 10:55 am UTC

Hello Tom,

I've been struggling with running ksh scripts from PL/SQL using java for a couple of days now (already opened a TAR on this issue and uploaded the class and test script we're using, but it couldn't be reproduced by your colleagues so far while I see the same behaviour on 3 instances). Do you know of any issues in 10.1.0.3 when calling a shell script and passing some parameters? It works fine with some combinations, but returns a 255 on others (which is bogus because the ksh script is where it belongs and permissions are set correct, otherwise it won't work when calling the ksh with different parameters).

I went through this thread now and verified just the same behavior occurs when I use your example class/function/procedure... so the problem seems to be really a general one.
I will upgrade one instance to 10.1.0.4 this weekend and see if it still happens (since support couldn't reproduce on either 10.1.0.2 or 10.1.0.4).

TIA,

Holger

10.1.0.4 patch fixed above problem

Holger Schweichler, October 18, 2005 - 5:16 am UTC

... just wanted to let you know upgrading to 10.1.0.4 indeed fixed the problem, so it really looks like there's a bug in 10.1.0.3.

Holger ;-)

Tom Kyte
October 18, 2005 - 9:10 am UTC

Thank you very much for the followup!

Trying to use a shell script

Deba, November 10, 2005 - 12:50 pm UTC

Hi Tom,

I am trying to run a shell script using specified code.

Under SYS user :
=================
SQL> begin
   2  dbms_java.grant_permission
   3  ('YMDBAADM',
    4  'java.io.FilePermission',
  '  5  /nas/orasoft/baracuda/oracle/scripts/x.sh',
   6   'execute');
  7
  8   dbms_java.grant_permission
 (  9  'YMDBAADM',
 10    'java.lang.RuntimePermission',
  '*',
  'writeFileDescriptor' );
end;
/ 11   12   13   14

PL/SQL procedure successfully completed.

Under Oracle OS user
====================
/nas/orasoft/baracuda/oracle/scripts> ls -l x.sh
-rwxrwxrwx   1 oracle   oinstall      66 Nov 10 17:11 x.sh

/nas/orasoft/baracuda/oracle/scripts> pg x.sh
echo executing
ls > /nas/orasoft/baracuda/oracle/scripts/java.txt

Under YMDBAADM :
================
SQL> edit
Wrote file afiedt.buf

  1  create or replace and compile java source named "DebaShellUtil"
  2    as
  3    import java.io.*;
  4    import java.lang.*;
  5    public class DebaShellUtil extends Object
  6    {
  7      public static int RunThis(String args)
  8      {
  9      Runtime rt = Runtime.getRuntime();
 10      int        rc = -1;
 11      try
 12      {
 13         Process p = rt.exec(args);
 14         int bufSize = 4096;
 15         BufferedInputStream bis =
 16          new BufferedInputStream(p.getInputStream(), bufSize);
 17         int len;
 18         byte buffer[] = new byte[bufSize];
 19         // Echo back what the program spit out
 20         while ((len = bis.read(buffer, 0, bufSize)) != -1)
 21            System.out.write(buffer, 0, len);
 22         rc = p.waitFor();
 23      }
 24      catch (Exception e)
 25      {
 26         e.printStackTrace();
 27         rc = -1;
 28      }
 29      finally
 30      {
 31         return rc;
 32      }
 33      }
 34*   }
 35  /

Java created.

SQL> edit
Wrote file afiedt.buf

  1  create or replace function RUN_CMD(p_cmd in varchar2) return number
  2    as
  3    language java
  4*   name 'DebaShellUtil.RunThis(java.lang.String) return integer';
SQL> /

Function created.

SQL> variable x number;
SQL> set serveroutput on;
SQL> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

SQL> exec :x := RUN_CMD('/nas/orasoft/baracuda/oracle/scripts/x.sh');

PL/SQL procedure successfully completed.

SQL> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

SQL> exec :x := RUN_CMD('/nas/orasoft/baracuda/oracle/scripts/x.sh');

PL/SQL procedure successfully completed.

You can see that there is no output. There is permission for the script on OS level. If I use follwoing 
exec :x := RUN_CMD('/usr/bin/sh /nas/orasoft/baracuda/oracle/scripts/x.sh');
Then it is running fine. But you have already said this is not good idea to use, so I would like to know where is the problem in above mentioned process ??

Thanks
Deba 

Tom Kyte
November 11, 2005 - 11:55 am UTC

you are missing an important line in the shell script

#!/bin/sh


on line one and remember, the environment might not be what you think in the shell script when run from the database (different environment) so best to fully qualify things (prevent trojan horses - find the right programs)



Trying to execute shell script

A reader, November 15, 2005 - 12:32 pm UTC

Hi Tom,

In OS I have created two files as follows :

/nas/orasoft/baracuda/oracle/scripts> pg x.sh
#!/bin/sh
echo executing
sleep 60
ls > /nas/orasoft/baracuda/oracle/scripts/java.txt
echo ending x.sh

/nas/orasoft/baracuda/oracle/scripts> pg y.sh
#!/bin/sh
echo calling x.sh
nohup /nas/orasoft/baracuda/oracle/scripts/x.sh &
echo calling y.sh

chomd 777 x.sh
chmod 777 y.sh

Under SYS account I have executed following code :

begin
 dbms_java.grant_permission
 ('YMDBAADM',
  'java.io.FilePermission',
  '/usr/bin/sh',
  'execute');
  
dbms_java.grant_permission
 ('YMDBAADM',
  'java.io.FilePermission',
  '/nas/orasoft/baracuda/oracle/scripts/y.sh',
  'execute');
  
 dbms_java.grant_permission
 ('YMDBAADM',
  'java.lang.RuntimePermission',
  '*',
  'writeFileDescriptor' );
end;
/

Connecting to the database thru STPS2 :

connect YMDBAADM/YMDBAADM
Connected.

create or replace and compile java source named "DebaShellUtil"
  as
  import java.io.*;
  import java.lang.*;
  
  public class DebaShellUtil extends Object
  {
    public static int RunThis(String args)
    {
    Runtime rt = Runtime.getRuntime();
    int        rc = -1;
  
    try
    {
       Process p = rt.exec(args);
  
       int bufSize = 4096;
       BufferedInputStream bis =
        new BufferedInputStream(p.getInputStream(), bufSize);
       int len;
       byte buffer[] = new byte[bufSize];
  
       // Echo back what the program spit out
       while ((len = bis.read(buffer, 0, bufSize)) != -1)
          System.out.write(buffer, 0, len);
  
       rc = p.waitFor();
    }
    catch (Exception e)
    {
       e.printStackTrace();
       rc = -1;
    }
    finally
    {
       return rc;
    }
    }
  }
/
  
create or replace function RUN_CMD(p_cmd in varchar2) return number
  as
  language java
  name 'DebaShellUtil.RunThis(java.lang.String) return integer';
/

variable x number;
set serveroutput on  
exec dbms_java.set_output(100000);

SQL> exec :x := RUN_CMD('/nas/orasoft/baracuda/oracle/scripts/y.sh');
calling x.sh
calling y.sh
executing
ending x.sh

PL/SQL procedure successfully completed.

Thanks for your any help.

Deba 

Tom Kyte
November 15, 2005 - 1:56 pm UTC

dbms_java.grant_permission
('YMDBAADM',
'java.io.FilePermission',
'/usr/bin/sh',
'execute');

that's not good - that means "run anything"


sort of wished you had included "the problem" though....


but if it is because "it is waiting till x is done", that is something you'll need to poke around with in the java code, likely the waitfor call.

Trying to execute shell script

A reader, November 15, 2005 - 12:35 pm UTC

Hi Tom,

In the above post you can see that there is no effect of "&" . But I want to execute a sehll in the background . Now how we can get this ???

Deba

execute in background

EBer, December 15, 2005 - 10:16 am UTC

You can exec that command from a batch file and inside you write: command.sh &

If you want that command to be independent and hangup immune,
you can use command "nohup", but you can't have the output back.

Hope this hepls.
EBer

Is it possible without Java ?

EBer, December 15, 2005 - 10:29 am UTC

We haven't JServer in Production DB.

Tom Kyte
December 15, 2005 - 10:58 am UTC

you can use C based external routines as well.

in 10g, the scheduler can run external jobs natively.

You might want stderr as well as stdout

Scott Swank, December 29, 2005 - 5:00 pm UTC

CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "host"
AS
import java.io.*;
public class host
{
public static int runCommand(String command, String[] output)
{
StringBuffer outputBuffer = new StringBuffer();
output[0] = "";
Runtime rt = Runtime.getRuntime();
int rc = -1;
try
{
Process p = rt.exec(command);
String line = new String();
BufferedReader br;

br = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = br.readLine()) != null)
outputBuffer.append(line);
br.close();

br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = br.readLine()) != null)
outputBuffer.append(line);
br.close();

if (outputBuffer.length() > 32000)
{
output[0] = new String(outputBuffer.substring(0,32000));
}
else
{
output[0] = new String(outputBuffer);
}

rc = p.waitFor();
//rc = p.exitValue();
}
catch (Exception e)
{
output[0] = e.toString();
rc = -1;
}
finally
{
return rc;
}
}
}
/


Is there any way to wrap java source

Ian, January 18, 2006 - 10:46 am UTC

Is there any way to wrap java source in the same way that you can wrap pl/sql packages?

Regards

Ian

Tom Kyte
January 19, 2006 - 7:49 am UTC

you can load bytecode instead of java source.

Su Baba, March 05, 2006 - 2:00 pm UTC

Would Java procedures cache cursors so no soft parses are required much like PL/SQL does?

Tom Kyte
March 06, 2006 - 8:32 am UTC

No, not unless you explicity make it happen in your own code.

A reader, March 06, 2006 - 12:46 pm UTC

When you say "not unless you explicity make it happen in your own code", do you mean opening a cursor in your Java code and keep using it until you don't need it any more?

Tom Kyte
March 08, 2006 - 4:10 pm UTC

or using jdbc statement caching or something - but "something" has to be explicitly enabled, jdbc does not do it by itself.

Yogesh Shejwal, March 31, 2006 - 6:14 am UTC

I want to Pass TableName and Column_name,But the Column_name Datatype is CLOB.FRONT End is Forms9iDS.

In Backend i have Created A funtion that accepts all the above.The Function i tested in Back end works fine.But at front end i just get a Blank screen.

(Note: I could not Find the Page to Submit the Question so i am writing my Question here. I am a regular User Of these Site..gets lot of information)


Tom Kyte
March 31, 2006 - 12:22 pm UTC

(note: the front page of this website sort of has the box that says:

Sorry I have a large backlog right now, please ask a question later

See the "other resources" tab above and to the left for recommendations of places to go to get answers to questions!

when I'm not taking questions)



I've no idea why you would get a "blank screen", I don't really know what you are really even doing.

cannot get this batch to run

oracledb, May 01, 2006 - 3:20 pm UTC

Tim,

i keeping getting null on windows 2000,but execute fine on windows 2003..


windows 2000
SQL> SET SERVEROUTPUT ON SIZE 1000000
SQL> CALL DBMS_JAVA.SET_OUTPUT(1000000);

Call completed.

SQL> BEGIN
  2    PAS_HOST_COMMAND (p_command => '\\point-code\code$\sql\dev\sqltam\misc\test.bat');
  3  EXCEPTION
  4        WHEN OTHERS
  5        THEN
  6           DBMS_OUTPUT.PUT_LINE (SQLCODE);
  7           DBMS_OUTPUT.PUT_LINE (SQLERRM);
  8  END;
  9  /
null

PL/SQL procedure successfully completed.

code for test.bat ==> move test1.txt test2.txt
------------------------------------------
windows 2003
SQL>  BEGIN
  2     PAS_HOST_COMMAND (p_command => '\\point-code\code$\sql\dev\sqltam\misc\test.bat');
  3    EXCEPTION
  4          WHEN OTHERS
  5          THEN
  6             DBMS_OUTPUT.PUT_LINE (SQLCODE);
  7             DBMS_OUTPUT.PUT_LINE (SQLERRM);
  8    END;
  9  /
Process out :
Process out :C:\oracle\ora81\DATABASE>SQLPLUS.EXE BT15/BT15@BT15
@\\point-code\code$\sql\dev\sqltam\misc\TEST.SQL

PL/SQL procedure successfully completed.

code for test.bat ==> move test1.txt test2.txt 

Tom Kyte
May 02, 2006 - 3:24 am UTC

what sort of debugging have you tried on your own?

I mean - if you have two machines here (forget the OS version for a minute) who is to say they are remotely configured the "same". that UNC name (that can be very tricky to use with services, if it can be used at all), does it really exist for the user that the database service is running as.

you don't even mention database versions :(

cannot get this batch to run

oracledb, May 02, 2006 - 6:24 pm UTC

not sure if my post work so..

both are on oracle 8.1.7.4.1,

i don't know what the null means? and i don't really know how to debug..i've tried it on the 2000 using local path and network path..

Tom Kyte
May 03, 2006 - 1:45 am UTC

... and i don't really know how to debug ...


uh oh. start by putting some DEBUG CODE into your java subroutine, to sort of try to figure out where it is going awry.

System.out.println()'s

Error Bound

Tom, July 03, 2006 - 8:56 am UTC

   Hi Tom,

  I have tried your example on a Sun Machine and I have got the next:

   14:53:41 SQL> exec rc('/usr/bin/ps -ef');
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util.java:14)

Procedimiento PL/SQL terminado correctamente.

14:53:49 SQL> exec rc('/usr/bin/id > f');
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util.java:14)


   What could be the cause of this?

   I'll appreciate very much your help.
   

Tom Kyte
July 07, 2006 - 3:30 pm UTC

did you ctl-f for ArrayIndexOutOfBoundsException
on this very page?

I have just solved my problem

Jorge, July 03, 2006 - 11:09 am UTC


Thanks for your help!. I found the solution above.

Solution to tricky "env" problem

Jay Bostock, July 20, 2006 - 5:31 am UTC

Okay - this thread is getting way out of hand, but I just wanted to contribute a quick solution that I've used to make running a script as a different user from oracle, where you have all the environment issues (I'm sure it's in AskTom somewhere!). I've done it using rsh (ssh would be better). the command executed from within oracle would be something like:
sql> exec rc('/usr/bin/rsh localhost -l <username> <myShellScript>');

It doesn't have to be localhost, you can use any host name. You have to create $HOME/.rhosts file in the account you want to connect to with the line 'localhost oracle' (again, if the two accounts are on different machines, use the hostname rather than localhost. This allows oracle to login without supplying the password. A remote shell is created as the user you are connecting with (with the correct env), the command is run (in my case myShellScript, but any command can be run) and then the remote shell is exited.

It works brilliantly for me and saves loads of bother/confusion!

Hope this helps someone.

Cheers
Jay

Stored Proc Execution in Unix

A reader, August 09, 2006 - 8:33 am UTC

Hi ,

Can you let me know the commands to be used to execute a oracle Stored Proc in C Shell script and to output the results of the execution as to whether the execution was successful or there was an Exception in the execution to a Text file

Thanks for the same.


Tom Kyte
August 09, 2006 - 10:55 am UTC

same why you would execute anything and log the output in C shell.

anyway, create a script, eg

$ cat test.sql
exec dbms_output.put_line('hello world');
exit


so, the procedure I want to run is dbms_output. You run it as follows:


$ sqlplus / @test

SQL*Plus: Release 10.2.0.1.0 - Production on Wed Aug 9 10:40:17 2006

Copyright (c) 1982, 2005, Oracle. All rights reserved.


Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options

hello world

PL/SQL procedure successfully completed.

Disconnected from Oracle Database 10g Enterprise Edition Release 10.2.0.1.0 - Production
With the Partitioning, OLAP and Data Mining options




Then, you just use redirection to capture the output. pipe to grep if you just one "success":

$ sqlplus / @test | grep 'successfully'
PL/SQL procedure successfully completed.


or better yet, egrep to get success or failure (I'll make it fail)

$ sqlplus / @test | egrep '(successfully|ORA-)'
PL/SQL procedure successfully completed.



$ cat test.sql
exec dbms_output.put_line('hello world'); raise PROGRAM_ERROR;
exit
$ sqlplus / @test | egrep '(successfully|ORA-)'
ORA-06501: PL/SQL: program error
ORA-06512: at line 1


Did something in Java change between 9i and 10g?

Ron, August 09, 2006 - 2:04 pm UTC

Tom,

I have a java stored procedure that worked like a charm in 9i but when I try to use it on a 10g database, it doesn't seem to work.  I use it to capture the UNIX TZ environment variable of the database and place it in a PL/SQL variable.  Watch how it works in 9i and then doesn't in 10g:

12:37:34 SQL> connect sys@resd as sysdba
Enter password: *******
Connected.
12:37:35 SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.7.0 - 64bit Production
PL/SQL Release 9.2.0.7.0 - Production
CORE    9.2.0.7.0       Production
TNS for Solaris: Version 9.2.0.7.0 - Production
NLSRTL Version 9.2.0.7.0 - Production

Elapsed: 00:00:00.00
12:37:45 SQL> begin
12:38:06   2  dbms_java.grant_permission
12:38:06   3  ( 'MECSPY', 'SYS:java.io.FilePermission', 
12:38:06   4  '/opt/app/oracle/admin/cadhd/create/test_tz.sh',
12:38:06   5  'execute' );
12:38:06   6  
12:38:06   7  dbms_java.grant_permission
12:38:06   8  ('SYS',
12:38:06   9  'java.lang.RuntimePermission',
12:38:06  10  '*',
12:38:06  11  'writeFileDescriptor' );
12:38:06  12  end;
12:38:06  13  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:02.08
12:38:11 SQL> connect mecspy@resd
Enter password: *******
Connected.
12:38:29 SQL> create or replace
12:38:52   2  FUNCTION run_command_java_fx (
12:38:52   3      fv_command   IN   VARCHAR2,
12:38:52   4      fv_output    OUT  VARCHAR2
12:38:52   5    )
12:38:52   6      RETURN NUMBER
12:38:52   7    AS
12:38:52   8      LANGUAGE JAVA
12:38:52   9      NAME 'NcgOSj.runOsCmd( java.lang.String,
12:38:52  10                             java.lang.String[] ) return integer';
12:38:52  11  /

Function created.

Elapsed: 00:00:00.02
12:38:53 SQL> 
12:38:53 SQL> create or replace
12:38:53   2    PROCEDURE run_command_java (
12:38:53   3      fv_command   IN       VARCHAR2,
12:38:53   4      fv_output    OUT      VARCHAR2
12:38:53   5    )
12:38:53   6    IS
12:38:53   7      ln_return_code   NUMBER;
12:38:53   8    BEGIN
12:38:53   9      ln_return_code    := run_command_java_fx (fv_command, fv_output);
12:38:53  10    END run_command_java;
12:38:53  11  /

Procedure created.

Elapsed: 00:00:00.00
12:38:53 SQL> 
12:38:53 SQL> CREATE OR REPLACE AND COMPILE
12:38:53   2      JAVA SOURCE NAMED "NcgOSj"
12:38:53   3     AS
12:38:53   4      import java.io.*;
12:38:53   5      import java.lang.*;
12:38:53   6      
12:38:53   7      public class NcgOSj extends Object
12:38:53   8      {
12:38:53   9        public static int runOsCmd(String OsCmdLine,
12:38:53  10                                   String[] CmdOutput)
12:38:53  11       {
12:38:53  12       Runtime rt = Runtime.getRuntime();
12:38:53  13       int     rc = -1;
12:38:53  14       String  coutput = " ";
12:38:53  15       String  ot = " " ;
12:38:53  16  
12:38:53  17       if (OsCmdLine.length() < 1) {
12:38:53  18           System.out.println("USAGE: java NcgOSj.runOsCmd \'cmd\' OutputStringVariable"
);
12:38:53  19           System.exit(1);
12:38:53  20       } 
12:38:53  21       try
12:38:53  22       {
12:38:53  23          // The exec() method in java.lang.Runtime is overloaded and
12:38:53  24          // can be called in different forms.  The following use illustrates
12:38:53  25          // the simplest form of exec() which takes a string as a parameter.
12:38:53  26          //
12:38:53  27          // Execute the command using the Runtime object variable 'rt' and
12:38:53  28          // get the process 'p' which controls this command
12:38:53  29          Process p = rt.exec(OsCmdLine);
12:38:53  30     
12:38:53  31          int bufSize = 4096;
12:38:53  32          BufferedInputStream bis =
12:38:53  33           new BufferedInputStream(p.getInputStream(), bufSize);
12:38:53  34          int len;
12:38:53  35          byte buffer[] = new byte[bufSize];
12:38:53  36     
12:38:53  37          // Echo back what the program spit out
12:38:53  38          while ((len = bis.read(buffer, 0, bufSize)) != -1) {
12:38:53  39             System.out.write(buffer, 0, len);
12:38:53  40             ot = new String(buffer, 0, len) ;
12:38:53  41             coutput = coutput + ot ;
12:38:53  42          }
12:38:53  43          // Wait for the process 'p' to finish and get the return code
12:38:53  44          // from the process 
12:38:53  45          rc = p.waitFor();
12:38:53  46       }
12:38:53  47       catch (Exception e)
12:38:53  48       {
12:38:53  49          e.printStackTrace();
12:38:53  50          rc = -1;
12:38:53  51       }
12:38:53  52       finally
12:38:53  53       {
12:38:53  54          CmdOutput[0] = coutput;
12:38:53  55          return rc;
12:38:53  56       }
12:38:53  57       }
12:38:53  58     }
12:38:53  59  /

Java created.

Elapsed: 00:00:04.06
12:38:59 SQL> connect mecspy@resd
Enter password: *******
Connected.
12:39:06 SQL> variable outpt varchar2(2000)
12:39:31 SQL> set serveroutput on
12:39:31 SQL> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.05
12:39:33 SQL> exec run_command_java('/opt/app/oracle/admin/cadhd/create/test_tz.sh', :outpt);
US/Central

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.02
12:40:34 SQL> print :outpt

OUTPT
----------------------------------------------------------------------------------------------------
 US/Central

So that worked great - the :outpt variable contains the UNIX TZ setting.  Now I go over to a 10g database running on the same server and run the exact same processes including the exact same shell script:

12:43:28 SQL> connect sys@cadhd as sysdba
Enter password: ***********
Connected.
12:43:29 SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.2.0 - 64bi
PL/SQL Release 10.2.0.2.0 - Production
CORE    10.2.0.2.0      Production
TNS for Solaris: Version 10.2.0.2.0 - Production
NLSRTL Version 10.2.0.2.0 - Production

Elapsed: 00:00:00.00
12:43:40 SQL> begin
12:43:53   2  dbms_java.grant_permission
12:43:53   3  ( 'MECSPY', 'SYS:java.io.FilePermission', 
12:43:53   4  '/opt/app/oracle/admin/cadhd/create/test_tz.sh',
12:43:53   5  'execute' );
12:43:53   6  
12:43:53   7  dbms_java.grant_permission
12:43:53   8  ('SYS',
12:43:53   9  'java.lang.RuntimePermission',
12:43:53  10  '*',
12:43:53  11  'writeFileDescriptor' );
12:43:53  12  end;
12:43:53  13  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.00
12:43:54 SQL> connect mecspy@cadhd
Enter password: *******
Connected.
12:44:02 SQL> create or replace
12:44:12   2  FUNCTION run_command_java_fx (
12:44:12   3      fv_command   IN   VARCHAR2,
12:44:12   4      fv_output    OUT  VARCHAR2
12:44:12   5    )
12:44:12   6      RETURN NUMBER
12:44:12   7    AS
12:44:12   8      LANGUAGE JAVA
12:44:12   9      NAME 'NcgOSj.runOsCmd( java.lang.String,
12:44:12  10                             java.lang.String[] ) return integer';
12:44:12  11  /

Function created.

Elapsed: 00:00:00.00
12:44:12 SQL> 
12:44:12 SQL> create or replace
12:44:12   2    PROCEDURE run_command_java (
12:44:12   3      fv_command   IN       VARCHAR2,
12:44:12   4      fv_output    OUT      VARCHAR2
12:44:12   5    )
12:44:12   6    IS
12:44:12   7      ln_return_code   NUMBER;
12:44:12   8    BEGIN
12:44:12   9      ln_return_code    := run_command_java_fx (fv_command, fv_output);
12:44:12  10    END run_command_java;
12:44:12  11  /

Procedure created.

Elapsed: 00:00:00.00
12:44:12 SQL> 
12:44:12 SQL> CREATE OR REPLACE AND COMPILE
12:44:12   2      JAVA SOURCE NAMED "NcgOSj"
12:44:12   3     AS
12:44:12   4      import java.io.*;
12:44:12   5      import java.lang.*;
12:44:12   6      
12:44:12   7      public class NcgOSj extends Object
12:44:12   8      {
12:44:12   9        public static int runOsCmd(String OsCmdLine,
12:44:12  10                                   String[] CmdOutput)
12:44:12  11       {
12:44:12  12       Runtime rt = Runtime.getRuntime();
12:44:12  13       int     rc = -1;
12:44:12  14       String  coutput = " ";
12:44:12  15       String  ot = " " ;
12:44:12  16  
12:44:12  17       if (OsCmdLine.length() < 1) {
12:44:13  18           System.out.println("USAGE: java NcgOSj.runOsCmd \'cmd\' OutputStringVariable"
);
12:44:13  19           System.exit(1);
12:44:13  20       } 
12:44:13  21       try
12:44:13  22       {
12:44:13  23          // The exec() method in java.lang.Runtime is overloaded and
12:44:13  24          // can be called in different forms.  The following use illustrates
12:44:13  25          // the simplest form of exec() which takes a string as a parameter.
12:44:13  26          //
12:44:13  27          // Execute the command using the Runtime object variable 'rt' and
12:44:13  28          // get the process 'p' which controls this command
12:44:13  29          Process p = rt.exec(OsCmdLine);
12:44:13  30     
12:44:13  31          int bufSize = 4096;
12:44:13  32          BufferedInputStream bis =
12:44:13  33           new BufferedInputStream(p.getInputStream(), bufSize);
12:44:13  34          int len;
12:44:13  35          byte buffer[] = new byte[bufSize];
12:44:13  36     
12:44:13  37          // Echo back what the program spit out
12:44:13  38          while ((len = bis.read(buffer, 0, bufSize)) != -1) {
12:44:13  39             System.out.write(buffer, 0, len);
12:44:13  40             ot = new String(buffer, 0, len) ;
12:44:13  41             coutput = coutput + ot ;
12:44:13  42          }
12:44:13  43          // Wait for the process 'p' to finish and get the return code
12:44:13  44          // from the process 
12:44:13  45          rc = p.waitFor();
12:44:13  46       }
12:44:13  47       catch (Exception e)
12:44:13  48       {
12:44:13  49          e.printStackTrace();
12:44:13  50          rc = -1;
12:44:13  51       }
12:44:13  52       finally
12:44:13  53       {
12:44:13  54          CmdOutput[0] = coutput;
12:44:13  55          return rc;
12:44:13  56       }
12:44:13  57       }
12:44:13  58     }
12:44:13  59  /

Java created.

Elapsed: 00:00:01.04
12:44:15 SQL> connect mecspy@cadhd
Enter password: *******
Connected.
12:44:35 SQL> variable outpt varchar2(2000)
12:44:36 SQL> set serveroutput on
12:44:36 SQL> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.03
12:44:37 SQL> exec run_command_java('/opt/app/oracle/admin/cadhd/create/test_tz.sh', :outpt);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.02
12:44:57 SQL> print :outpt

OUTPT
----------------------------------------------------------------------------------------------------


Note how this time in the 10g database the :outpt variable is empty - no UNIX TZ variable setting.  Did something subtle in
Java happen to cause this in 10g? 

Tom Kyte
August 09, 2006 - 4:53 pm UTC

everything but the sh script :(

oh well.

anyway, are you SURE the TZ environment variable is in fact set? Why not quickly test some other variable - like ORACLE_HOME, pretty sure that one would be.

(just because they are on the same machine doesn't mean they have the same environment)

Here's the .sh script and the test using it

Ron, August 10, 2006 - 8:59 am UTC

Here's the contents of the test_tz.sh script that shows the value of the ORACLE_HOME followed by the java test too:

---- in unix

dm556:/opt/app/oracle/admin/cadhd/create:oracle >cat test_tz.sh
#!/bin/ksh
export VALUE=`env | grep ORACLE_HOME | awk -F= '{print $2}'`
echo $VALUE
dm556:/opt/app/oracle/admin/cadhd/create:oracle >test_tz.sh    
/opt/app/oracle/product/10.2.0.2.0

----- back to sql*plus

07:35:34 SQL> connect sys@cadhd as sysdba
Enter password: ***********
Connected.
07:44:26 SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.2.0 - 64bi
PL/SQL Release 10.2.0.2.0 - Production
CORE    10.2.0.2.0      Production
TNS for Solaris: Version 10.2.0.2.0 - Production
NLSRTL Version 10.2.0.2.0 - Production

Elapsed: 00:00:00.00
07:44:34 SQL> begin
07:45:19   2  dbms_java.grant_permission
07:45:19   3  ( 'MECSPY', 'SYS:java.io.FilePermission', 
07:45:19   4  '/opt/app/oracle/admin/cadhd/create/test_tz.sh',
07:45:19   5  'execute' );
07:45:19   6  
07:45:19   7  dbms_java.grant_permission
07:45:19   8  ('SYS',
07:45:19   9  'java.lang.RuntimePermission',
07:45:19  10  '*',
07:45:19  11  'writeFileDescriptor' );
07:45:19  12  end;
07:45:19  13  /

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.04
07:45:19 SQL> connect mecspy@cadhd
Enter password: *******
Connected.
07:46:57 SQL> create or replace
07:47:14   2  FUNCTION run_command_java_fx (
07:47:14   3      fv_command   IN   VARCHAR2,
07:47:14   4      fv_output    OUT  VARCHAR2
07:47:14   5    )
07:47:14   6      RETURN NUMBER
07:47:14   7    AS
07:47:14   8      LANGUAGE JAVA
07:47:14   9      NAME 'NcgOSj.runOsCmd( java.lang.String,
07:47:14  10                             java.lang.String[] ) return integer';
07:47:14  11  /

Function created.

Elapsed: 00:00:00.00
07:47:14 SQL> 
07:47:14 SQL> create or replace
07:47:14   2    PROCEDURE run_command_java (
07:47:14   3      fv_command   IN       VARCHAR2,
07:47:14   4      fv_output    OUT      VARCHAR2
07:47:14   5    )
07:47:14   6    IS
07:47:14   7      ln_return_code   NUMBER;
07:47:14   8    BEGIN
07:47:14   9      ln_return_code    := run_command_java_fx (fv_command, fv_output);
07:47:14  10    END run_command_java;
07:47:14  11  /

Procedure created.

Elapsed: 00:00:00.00
07:47:14 SQL> 
07:47:14 SQL> CREATE OR REPLACE AND COMPILE
07:47:14   2      JAVA SOURCE NAMED "NcgOSj"
07:47:14   3     AS
07:47:14   4      import java.io.*;
07:47:14   5      import java.lang.*;
07:47:14   6      
07:47:14   7      public class NcgOSj extends Object
07:47:14   8      {
07:47:14   9        public static int runOsCmd(String OsCmdLine,
07:47:14  10                                   String[] CmdOutput)
07:47:14  11       {
07:47:14  12       Runtime rt = Runtime.getRuntime();
07:47:14  13       int     rc = -1;
07:47:14  14       String  coutput = " ";
07:47:14  15       String  ot = " " ;
07:47:14  16  
07:47:14  17       if (OsCmdLine.length() < 1) {
07:47:14  18           System.out.println("USAGE: java NcgOSj.runOsCmd \'cmd\' OutputStringVariable"
);
07:47:14  19           System.exit(1);
07:47:14  20       } 
07:47:14  21       try
07:47:14  22       {
07:47:14  23          // The exec() method in java.lang.Runtime is overloaded and
07:47:14  24          // can be called in different forms.  The following use illustrates
07:47:14  25          // the simplest form of exec() which takes a string as a parameter.
07:47:14  26          //
07:47:14  27          // Execute the command using the Runtime object variable 'rt' and
07:47:14  28          // get the process 'p' which controls this command
07:47:14  29          Process p = rt.exec(OsCmdLine);
07:47:14  30     
07:47:14  31          int bufSize = 4096;
07:47:14  32          BufferedInputStream bis =
07:47:14  33           new BufferedInputStream(p.getInputStream(), bufSize);
07:47:14  34          int len;
07:47:14  35          byte buffer[] = new byte[bufSize];
07:47:14  36     
07:47:14  37          // Echo back what the program spit out
07:47:14  38          while ((len = bis.read(buffer, 0, bufSize)) != -1) {
07:47:14  39             System.out.write(buffer, 0, len);
07:47:14  40             ot = new String(buffer, 0, len) ;
07:47:14  41             coutput = coutput + ot ;
07:47:14  42          }
07:47:14  43          // Wait for the process 'p' to finish and get the return code
07:47:14  44          // from the process 
07:47:14  45          rc = p.waitFor();
07:47:14  46       }
07:47:14  47       catch (Exception e)
07:47:14  48       {
07:47:14  49          e.printStackTrace();
07:47:14  50          rc = -1;
07:47:14  51       }
07:47:14  52       finally
07:47:14  53       {
07:47:14  54          CmdOutput[0] = coutput;
07:47:14  55          return rc;
07:47:14  56       }
07:47:14  57       }
07:47:14  58     }
07:47:14  59  /

Java created.

Elapsed: 00:00:01.01
07:47:16 SQL> connect mecspy@cadhd
Enter password: *******
Connected.
07:47:26 SQL> variable outpt varchar2(2000)
07:47:51 SQL> set serveroutput on
07:47:51 SQL> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
07:48:17 SQL> exec run_command_java('/opt/app/oracle/admin/cadhd/create/test_tz.sh', :outpt);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.01
07:52:07 SQL> print :outpt

OUTPT
----------------------------------------------------------------------------------------------------

 

Tom Kyte
August 10, 2006 - 9:38 am UTC

can you tell if the script is being executed at all? touch a file or something (eg: debug it, add trace/diagnostic information)

The script's not being executed.

Ron, August 10, 2006 - 10:25 am UTC

That's a good idea. I touched a file within the .sh script. When I run it from the 9i database I can see the touched file on the file system - when I run it in the 10g database the touched file isn't there proving that the script isn't being executed. Now I just have to figure out why.

Cannot compile ...

Stefanie, August 23, 2006 - 9:32 am UTC

Trying to compile the Java code I get errors:

create or replace and compile
java source named "Util"
as
import java.io.*;
import java.lang.*;
public class Util extends Object
{
public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;
try
{
Process p = rt.exec(args);
int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];
// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer, 0, len);
rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
* }
/



Oracle tells me the following:

Util:7: Class string not found.
Util:9: Class runtime not found.
Util:9: Undefined variable or class name: runtime
Util:14: Class process not found.

And so on.

There are public synonyms and execution grants on all Java stuff under sys. My user has every Java-ish role assigned.
Where does this error come from?

Thanks for your help,

Steff

Tom Kyte
August 27, 2006 - 3:40 pm UTC

can we see a cut and paste?

ops$tkyte%ORA10GR2>  create or replace and compile
  2       java source named "Util"
  3       as
  4       import java.io.*;
  5       import java.lang.*;
  6       public class Util extends Object
  7       {
  8         public static int RunThis(String args)
  9         {
 10         Runtime rt = Runtime.getRuntime();
 11         int        rc = -1;
 12         try
 13          {
 14             Process p = rt.exec(args);
 15             int bufSize = 4096;
 16             BufferedInputStream bis =
 17              new BufferedInputStream(p.getInputStream(), bufSize);
 18             int len;
 19             byte buffer[] = new byte[bufSize];
 20             // Echo back what the program spit out
 21             while ((len = bis.read(buffer, 0, bufSize)) != -1)
 22                System.out.write(buffer, 0, len);
 23             rc = p.waitFor();
 24          }
 25          catch (Exception e)
 26          {
 27             e.printStackTrace();
 28             rc = -1;
 29          }
 30          finally
 31          {
 32             return rc;
 33          }
 34          }
 35      }
 36  /

Java created.
 

Scheiss Gallier

Stefanie, August 23, 2006 - 10:22 am UTC

It was the asterix in the second last line ... *aaargh* ... ;o)

unable to print out put of oerr command in pl/sql

V Bhavani Sankar, August 28, 2006 - 3:43 am UTC

Dear Tom,
Thank you very much for u r example . with that example i was able to run almost all os commans. but i'm unable to print the output of "oerr " tool.

Does any other settings are required for running tools like oerr.

here is sample output
LAB65>select test1_call_cmd('/bin/ls -la') from dual;

TEST1_CALL_CMD('/BIN/LS-LA')
---------------------------------------------------------------------------------
total 28320
drwxr-xr-x 2 oracle dba 4096 Aug 14 10:24 .
drwxr-xr-x 55 oracle dba 4096 Apr 20 17:10 ..
-rwxr-xr-x 1 oracle dba 1544 Apr 15 16:16 hc_aplab65.dat
-rwxr-xr-x 1 oracle dba 1544 Apr 13 17:05 hc_ora10g.dat
-rwxr-xr-x 1 oracle dba 1400 Jul 15 13:18 initaplab65.ora
-rwxr-xr-x 1 oracle dba 12920 May 3 2001 initdw.ora
-rwxr-xr-x 1 oracle dba 8385 Sep 11 1998 init.ora
-rwxr-xr-x 1 oracle dba 24 Apr 15 16:16 lkAPLAB65
-rw-r----- 1 oracle dba 1536 Aug 24 14:28 orapwaplab65
-rw-r----- 1 oracle dba 1536 Aug 3 16:41 orapwaplab65.bak
-rw-r----- 1 oracle dba 1536 Aug 3 17:01 orapwaplab65.bak1
-rw-r----- 1 oracle dba 1536 Aug 4 10:11 orapwaplab65.bak2
-rw-r----- 1 oracle dba 28819456 Aug 25 14:40 snapcf_aplab65.f
-rwxr-xr-x 1 oracle dba 3584 Apr 20 22:06 spfileaplab65.bak
-rw-r----- 1 oracle dba 3584 Aug 28 12:01 spfileaplab65.ora
-rwxr-xr-x 1 root root 2622 Apr 19 15:33 sqlnet.log

LAB65>select test1_call_cmd('/apps/app/oracle/product/10.2.0/bin/oerr ora 1003') from dual;

TEST1_CALL_CMD('/APPS/APP/ORAC
-----------------------------------------------------------------------------------------------



Thank you very much for the help



Tom Kyte
August 28, 2006 - 10:36 am UTC

u r ???


/bin/ls - that is an executable

/.../oerr - that is a shell script

ctl-f for cnelson and try some of that.

Thank you for the responce.

Bhavani Sankar, August 29, 2006 - 3:09 am UTC

Dear Tom,
 sorry for that "u r" in last reply.   

 i dont think my problem with enironment. because simple echo command from a script also not giving output. 
 when i run any script for pl/sql function  the wait status of Process p.waitfor() coming as 255.

here is what i've done.

exec dbms_java.grant_permission('DOTSOFT','SYS:java.io.FilePermission','/home/oracle/sayhi','execute');

contents of sayhi file
[oracle@lab65 ~]$ cat sayhi
echo hello

permission of the file
[oracle@lab65 ~]$ ll sayhi
-rwxrwxrwx  1 oracle dba 24 Aug 29 12:19 sayhi

select test_call_cmd('/home/oracle/showerr') from dual;
TEST_CALL_CMD('/HOME/ORACLE/SH
------------------------------
                           255

later i changed sayhi to 
[oracle@lab65 ~]$ cat sayhi
/usr/bin/env
echo hello

once again i run the function
SQL> select test_call_cmd('/home/oracle/sayhi') from dual;

TEST_CALL_CMD('/HOME/ORACLE/SA
------------------------------
                           255

output is same.

if i directly call 'echo' then it is ok

select test_call_cmd('/bin/echo hello') from dual;
TEST_CALL_CMD('/BIN/ECHOHELLO
-----------------------------
                            0

SQL> exec test_call_fun('/bin/echo hello');
hello

PL/SQL procedure successfully completed.

SQL> exec test_call_fun('/home/oracle/sayhi');

PL/SQL procedure successfully completed.




i got oerr output with direct grep command. my problem is solved. but i want to know why scripts are not running even though they are by oracle itself.

Thank you very much for your help 

Tom Kyte
August 29, 2006 - 7:12 am UTC

put a SHELL in the beginng of that script

#!/bin/sh




Thank you

A reader, August 30, 2006 - 3:28 am UTC

Thank you very much

One More time

Dick Goulet, October 18, 2006 - 4:32 pm UTC

Tom,

I found this very useful & thank you for it, but as a few above me have said I'm no JAVA head. What I want is to issue a 'df -k' on a file system(solaris) and get back the available disk space. What I get today is:

/dev/md/dsk/d2 12397228 3936915 8336341 33% /

What I want is: 8336341

Anyway to get there from here?

Tom Kyte
October 18, 2006 - 4:48 pm UTC

get that string from java....

and then substr it in sql/plsql :)

that is what *I* would do...



Host Command In Java

Dick Goulet, October 19, 2006 - 10:30 am UTC

Tom,

Can't we be a little more elegant?? I've done this with external C procedures before, but I'm trying to move into the 21st century. Thanks anyway, it was worth the effort to ask.

Tom Kyte
October 19, 2006 - 2:06 pm UTC

you may well be able to - but the problem is "i am not a java guru" either, I'm much better with plsql/sql and C :)

Running o/s commands from pl/sql

a reader, November 20, 2006 - 6:51 am UTC

I used the scripts from above to run the operating system command from within pl/sql. It doesn't return anything back to pl/sql program, it doesn't throw any error either. Below is the script that I have used. I know that granting privilege to /usr/bin/ksh is not a good idea, so if there is a workaround then please let me know.

Basically I am trying to get the available disk space on our file system. At the moment, my korn shell script contains hard coded file system but I ideally want to pass this as a parameter. However, I am not being able to run this even with the hardcoded file system, so need your help. Please let me know why it is not returning any result back to pl/sql program unit.

Thanks in advance


drop user rt_test cascade;

create user rt_test identified by rt_test;

grant connect, resource to rt_test;

begin
-- Grant execute permission on df to rt_test user.
dbms_java.grant_permission(
'rt_test', 'java.io.FilePermission',
'/usr/xpg4/bin/df',
'execute');

-- Grant execute permission on grep to rt_test user.
dbms_java.grant_permission(
'rt_test', 'java.io.FilePermission',
'/usr/xpg4/bin/grep',
'execute');

-- Grant execute permission on awk to rt_test user.
dbms_java.grant_permission(
'rt_test', 'java.io.FilePermission',
'/usr/xpg4/bin/awk',
'execute');

-- Grant execute permission on ksh to rt_test user.
dbms_java.grant_permission(
'rt_test', 'java.io.FilePermission',
'/usr/bin/ksh',
'execute');

-- Grant execute permission on dfp to rt_test user.
dbms_java.grant_permission(
'rt_test', 'java.io.FilePermission',
'/projects/atlas/dba/part/scripts/.temp/dfp',
'execute');
dbms_java.grant_permission
('rt_test',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;
/

-- The korn shell script /projects/atlas/dba/part/scripts/.temp/dfp contains
#!/usr/bin/ksh
df -k /export/data/db1|grep "^/" | awk '{print $4;}'

------------------------------------
connect rt_test/rt_test

create or replace and compile
java source named "Util"
as
import java.io.*;
import java.lang.*;
public class Util extends Object
{
public static int RunThis(String args, String[] cmdOutput)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;
String coutput = " ";
String ot = " ";
try
{
Process p = rt.exec(args);
int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];
// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1) {
System.out.write(buffer, 0, len);
ot = new String(buffer, 0, len);
coutput = coutput + ot;
}
rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
cmdOutput[0] = coutput;
return rc;
}
}
}
/

create or replace function RUN_CMD( p_cmd in varchar2, p_cmd_out out varchar2) return number as
language java
name 'Util.RunThis(java.lang.String, java.lang.String[]) return integer';
/

create or replace procedure RC(p_cmd in varchar2, p_cmd_out out varchar2) as
x number;
begin
x := run_cmd(p_cmd, p_cmd_out);
dbms_output.put_line('Cmd output:' || p_cmd_out);
end;
/

set serveroutput on size 1000000
execute dbms_java.set_output(1000000)
declare
r varchar2(4000);
begin
rc('/projects/atlas/dba/part/scripts/.temp/dfp', r);
dbms_output.put_line('Return value:' || r);
end;
/


running o/s commands using java

a reader, November 21, 2006 - 7:33 am UTC

Hi Tom,

Please could you reply to the above query. I am using 10.2.0.1 database.

Thanks


running o/s command using java

a reader, November 23, 2006 - 7:30 am UTC

Hi Tom,,

Please could you reply to the query above where I am trying to return the available disk space on a file system?

Thanks

Exception error

Krishna, November 27, 2006 - 1:57 am UTC

Hi Tom,

I am using Oracle9i Enterprise Edition Release 9.2.0.6.0 ver, I used the same code but while executing the procedure I am getting Exception errors 

SQL> exec rc('/u13/mdrdev/ps');
java.lang.NoSuchMethodException: No applicable method found
at
oracle.aurora.util.JRIExtensions.getMaximallySpecificMethod(JRIExtensions.java)
at
oracle.aurora.util.JRIExtensions.getMaximallySpecificMethod(JRIExtensions.java)
BEGIN rc('/u03/radartst/ps'); END;

*
ERROR at line 1:
ORA-29531: no method RunThis in class util
ORA-06512: at "MDR.RUN_CMD", line 0
ORA-06512: at "MDR.RC", line 5
ORA-06512: at line 1  

Thanks in Advance 

Tom Kyte
November 27, 2006 - 7:58 am UTC

you did something, well, wrong.

look at the code again. You seem to be missing the "RunThis" method.

Exception error

user, November 27, 2006 - 2:31 am UTC

Hi Tom,

In continuation with the above problem, I am including all the code
create or replace procedure java_permission
as
begin
        dbms_java.grant_permission
         ('MDR',
         'java.io.FilePermission',
         '/bin/ps',
         'execute');

         
         dbms_java.grant_permission
        ('MDR',
         'java.io.FilePermission',
         '/bin/sh',
         'execute');dbms_java.grant_permission
        ('MDR',
        'java.lang.RuntimePermission',
        '*',
        'writeFileDescriptor' );

   end;
--- executed sucessfully

create or replace and compile java source named util as
import java.io.*;
    import java.lang.*;
    
    public class Util extends Object
    {
      public static int RunThis(String args)
     {
     Runtime rt = Runtime.getRuntime();
     int        rc = -1;
   
     try
     {
        Process p = rt.exec(args);
   
        int bufSize = 4096;
        BufferedInputStream bis =
         new BufferedInputStream(p.getInputStream(), bufSize);
        int len;
        byte buffer[] = new byte[bufSize];
   
        // Echo back what the program spit out
        while ((len = bis.read(buffer, 0, bufSize)) != -1)
           System.out.write(buffer, 0, len);
   
        rc = p.waitFor();
     }
     catch (Exception e)
     {
        e.printStackTrace();
        rc = -1;
     }
     finally
     {
        return rc;
     }
     }
   }

-- compiled sucessfully
create or replace function RUN_CMD( p_cmd  in varchar2) return number
    as
    language java
    name 'Util.RunThis(java.lang.String[]) return integer';

-- compiled sucessfully   
create or replace procedure RC(p_cmd in varchar2)
    as
      x number;
    begin
      x := run_cmd(p_cmd);
    end;
-- compiled sucessfully 
SQL> exec rc('/bin/ps');
java.lang.NoSuchMethodException: No applicable method found
at
oracle.aurora.util.JRIExtensions.getMaximallySpecificMethod(JRIExtensions.java)
at
oracle.aurora.util.JRIExtensions.getMaximallySpecificMethod(JRIExtensions.java)
BEGIN rc('/bin/ps'); END;

*
ERROR at line 1:
ORA-29531: no method RunThis in class util
ORA-06512: at "MDR.RUN_CMD", line 0
ORA-06512: at "MDR.RC", line 5
ORA-06512: at line 1  

Thanks in Advance 
  

  


 

Tom Kyte
November 27, 2006 - 8:42 am UTC

you need to put the "" around util again in the create or replace and lose the [] in the run_cmd function - ctl-f on this page for ArrayI and look at the code again, you are not using what I had last (for 9i)

running system commands using java

a reader, November 27, 2006 - 11:32 am UTC

could you reply to my query, the one before the last question (on returning the amount of disk space available in a file system using java).

thanks


Tom Kyte
November 27, 2006 - 7:34 pm UTC

back up and simplify it. what have you done to "debug" - have you had the script redirect to a file for example just to verify it "works", print out the environment, and so on.

Run time permission error

A reader, November 28, 2006 - 7:05 am UTC

Hi Tom,

Thanks for your code, this is very much helpful, I am getting errors when I want to run a sh file

I got the following permissions from DBA

dbms_java.grant_permission
('MDR',
'java.io.FilePermission',
'/bin/ps',
'execute');

dbms_java.grant_permission
('MDR',
'java.io.FilePermission',
'/bin/pwd',
'execute');

dbms_java.grant_permission
('MDR',
'java.io.FilePermission',
'/bin/sh',
'execute');

dbms_java.grant_permission
('MDR',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );

I was able to run the following commands

exec rc('/bin/ps'); ---sucess with output
exec rc('/bin/pwd'); --output /opt/oracle/product9206/dbs

so every command is referring to this /opt/oracle/product9206/dbs directory

Actually I need to execute a sh file which is in /u13/mdrdev directory

I got the permission for this execution from dba as
execute dbms_java.grant_permission

('MDR','java.io.FilePermission','/bin/sh /u13/mdrdev/sample.sh', 'execute');

When I ran from linux this command is working
]$ /bin/sh /u13/mdrdev/sample.sh

but when I tried to execute the same as
exec rc('/bin/sh /u13/mdrdev/sample.sh'), I couldn't get any output

I feel the problem is in giving the permissions statement from DBA.

Your suggestions are very much needful,please help me in framing the DBA permission

Thanks in Advance




Tom Kyte
November 28, 2006 - 9:34 am UTC

do not use /bin/sh - you would give permission on /bin/sh and THAT WOULD LET YOU RUN VIRTUALLY ANYTHING.

grant execute on /u13/mdrdev/sample.sh

and make sure the first line of the script is

#!/bin/sh

running o/s commands using java

a reader, December 01, 2006 - 9:55 am UTC

Hi Tom,

Regarding available disk space, please see the scripts and the output below. I am using 10g database. The problem I am seeing is that the returned value is not captured. Please advise where is it going wrong.

1. Content of the korn shell script

#!/usr/bin/ksh                                      
df -k /export/data/db1|grep "^/" | awk '{print $4;}'

2. Output of the korn shell script when ran from the unix.

$ /projects/atlas/dba/part/scripts/.temp/dfp
2208752

The above korn shell script returns the size of the file system /export/data/db1 in KBytes.

3. Scripts used:

connect dbauser/dbapassword

drop user rt_test cascade;
create user rt_test identified by rt_test;
grant connect, resource to rt_test;

begin
  -- Grant execute permission on dfp to rt_test user.
  dbms_java.grant_permission(
  'RT_TEST', 'java.io.FilePermission',
  '/projects/atlas/dba/part/scripts/.temp/dfp',
  'execute');

  dbms_java.grant_permission
  ('RT_TEST',
  'java.lang.RuntimePermission',
  '*',
  'writeFileDescriptor' );
end;
/

connect rt_test/rt_test
SQL> l
  1  create or replace and compile
  2    java source named "Util"
  3    as
  4    import java.io.*;
  5    import java.lang.*;
  6    public class Util extends Object
  7    {
  8     public static int RunThis(String args, String[] cmdOutput)
  9     {
 10      Runtime rt = Runtime.getRuntime();
 11      int        rc = -1;
 12      String coutput = " ";
 13      String ot = " ";
 14      try
 15      {
 16       Process p = rt.exec(args);
 17       int bufSize = 4096;
 18       BufferedInputStream bis =
 19       new BufferedInputStream(p.getInputStream(), bufSize);
 20       int len;
 21       byte buffer[] = new byte[bufSize];
 22       // Echo back what the program spit out
 23       while ((len = bis.read(buffer, 0, bufSize)) != -1) {
 24         System.out.write(buffer, 0, len);
 25         ot = new String(buffer, 0, len);
 26         coutput = coutput + ot;
 27       }
 28         rc = p.waitFor();
 29       }
 30       catch (Exception e)
 31       {
 32  System.out.println("Error running command: " + args + "\n" + e.getMessage());
 33        e.printStackTrace();
 34        rc = -1;
 35       }
 36      finally
 37      {
 38       cmdOutput[0] = coutput;
 39       return rc;
 40      }
 41     }
 42*  }
SQL> /

Java created.

SQL> create or replace function RUN_CMD( p_cmd  in varchar2, p_cmd_out out varchar2) return number as
language java                                                                                        
name 'Util.RunThis(java.lang.String, java.lang.String[]) return integer';                            
/                                                                                                    
                                                                                                     
  2    3    4                                                                                        
Function created.


SQL> create or replace procedure RC(p_cmd in varchar2, p_cmd_out out varchar2) as 
  x number;                                                                       
begin                                                                             
  x := run_cmd(p_cmd, p_cmd_out);                                                 
dbms_output.put_line('Cmd output:' || p_cmd_out);                                 
end;                                                                              
/                                                                                 
  2    3    4    5    6    7                                                      
Procedure created.

4. Output from the procedure RC:

SQL> set serveroutput on size 1000000                           
SQL> execute dbms_java.set_output(1000000)                      
                                                                
PL/SQL procedure successfully completed.                        
                                                                
SQL> declare                                                    
  2    r varchar2(4000);                                        
  3  begin                                                      
  4    rc('/projects/atlas/dba/part/scripts/.temp/dfp', r);     
  5    dbms_output.put_line('Return value:' || r);              
  6  end;                                                       
  7  /                                                          
Cmd output:                                                     
Return value:                                                   
    
PL/SQL procedure successfully completed.
 

Tom Kyte
December 01, 2006 - 10:14 am UTC

so, echo somethings out - start simple, add stuff. see what you see.

DEBUG IT.

a reader

a reader, December 01, 2006 - 10:28 am UTC

ok. i have added few println statements as shown in the script below. the output also is shown below. it looks like it is not going inside the while loop. i don't know why.

create or replace and compile
  java source named "Util"
  as
  import java.io.*;
  import java.lang.*;
  public class Util extends Object
  {
   public static int RunThis(String args, String[] cmdOutput)
   {
    Runtime rt = Runtime.getRuntime();
    int        rc = -1;
    String coutput = " ";
    String ot = " ";
    try
    {
     Process p = rt.exec(args);
     int bufSize = 4096;
     BufferedInputStream bis =
     new BufferedInputStream(p.getInputStream(), bufSize);
     int len;
     byte buffer[] = new byte[bufSize];
     // Echo back what the program spit out
System.out.println("Before the loop. ");
     while ((len = bis.read(buffer, 0, bufSize)) != -1) {
       System.out.write(buffer, 0, len);
       ot = new String(buffer, 0, len);
       coutput = coutput + ot;
System.out.println("Within the loop. coutput:" + coutput);
     }
System.out.println("Before wait");
       rc = p.waitFor();
     }
     catch (Exception e)
     {
      System.out.println("Error running command: " + args + "\n" + e.getMessage());
      e.printStackTrace();
      rc = -1;
     }
    finally
    {
     cmdOutput[0] = coutput;
System.out.println("coutput in finally:" + coutput);
     return rc;
    }
   }
 }
/

SQL> l                                                     
  1  declare                                               
  2    r varchar2(4000);                                   
  3  begin                                                 
  4    rc('/projects/atlas/dba/part/scripts/.temp/dfp', r);
  5    dbms_output.put_line('Return value:' || r);         
  6* end;                                                  
SQL> /                                                     
Before the loop.                                           
Before wait                                                
coutput in finally:                                        
Cmd output:                                                
Return value:                                              
                                                           
PL/SQL procedure successfully completed.                   
 

Tom Kyte
December 01, 2006 - 10:35 am UTC

i meant put DEBUG IN THE SCRIPT.

do a couple of /bin/echo'es in there - touch a file, echo something to a file - prove that the script is running for example.



running os commands using java

a reader, December 01, 2006 - 11:44 am UTC

the korn shell script is now changed to redirect the output to output.txt under the same directory. i ran the script from unix prompt and it did produce the file and contained the expected output. the output.txt file was deleted before running the procedure. after running the procedure, it did generate the output.txt file but it is empty. so it did call the korn shell script. the file size for output.txt as shown below is zero.

Korn shell script dfp:
#!/usr/bin/ksh
df -k /export/data/db1|grep "^/" | awk '{print $4;}' > /projects/atlas/dba/part/scripts/.temp/output.txt


SQL> declare
  2    r varchar2(4000);
  3  begin
  4    rc('/projects/atlas/dba/part/scripts/.temp/dfp', r);
  5    dbms_output.put_line('Return value:' || r);
  6  end;
  7  /
Before the loop.
Before wait
coutput in finally:
Cmd output:
Return value:

PL/SQL procedure successfully completed.

SQL> !ls -lrt /projects/atlas/dba/part/scripts/.temp/

drwxrwxr--   4 oracle   dba         2048 Sep 29 13:46 ..
-rwxrwxrwx   1 oracle   dba          120 Dec  1 16:26 dfp
-rw-rw-r--   1 oracle   dba            0 Dec  1 16:30 output.txt
drwxrwxr--   3 oracle   dba         1024 Dec  1 16:30 .
 

Tom Kyte
December 01, 2006 - 12:46 pm UTC

maybe it cannot find df and maybe stderr (which is not captured) is saying "no program df"

maybe put an explicit path on df.

running os command using java

a reader, December 04, 2006 - 5:59 am UTC

You were right, it wasn't capturing the error message.

I put the full path for df and it still wouldn't work. So I decided to trap the error message by adding "2> /projects/atlas/dba/part/scripts/.temp/err.txt" at the end of the df command. It correctly showed the error message as "awk:not found". So I put the full path for grep and awk commands in the shell script and it worked like a treat.

I want to thank you very much as you got me to think in the right direction. You are just the best.


replace string by passing parameters in unix script

Lily, December 04, 2006 - 1:52 pm UTC

Tom,
We are write some unix script for our DBA tasks.when I write some unix script to
replace string, I can use sed to accomplish it.
For example, if I want to replase string of REUSE with SET in some text file, I may do:

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> cat rp_string.txt
REUSE

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> vi t.ksh

#!/usr/bin/ksh

file=/tmp/rp_string.txt

cat rp_string.txt| sed 's/REUSE/SET/' > rp_string.txt.tmp

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> chmod u+x t.ksh

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> t.ksh

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> more rp_string.txt.tmp
SET

But if I want to replace the string by using parameter with $ sign,
how can I do it? For example, I have some ORACLE_SID as 'prd' in the text file,
I want to replace all 'prd' to 'stg' in the text file by passing parameters $SID_1 (represents prd) and $SID_2( represents stg), the way using sed with string won't work. Please see below:

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> cat rp_string.txt.2
/db/db02/oradata/prd
/db/db01/oradata/prd

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> vi t2.ksh
"t2.ksh" 8 lines, 102 characters
#!/usr/bin/ksh

SID_1=$1
SID_2=$2

file=/tmp/rp_string.txt.2

cat rp_string.txt.2| sed 's/$1/$2/' > rp_string.txt.tmp.2

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> chmod u+x t2.ksh

<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> t2.ksh prd stg
<dbdev2.ny.sothebys.com:oracle:anetdev:/tmp> more rp_string.txt.tmp.2
/db/db02/oradata/prd
/db/db01/oradata/prd

You are not only the expert for ORACLE, but also the expert for unix script,
so could you please help me for it?

Thanks in advance.


Tom Kyte
December 05, 2006 - 9:30 pm UTC

hey, look at that, I've been promoted....

[tkyte@desktop ~]$ cat ./test.ksh
#!/bin/ksh

echo 'hello world' | sed "s/$1/$2/"
[tkyte@desktop ~]$ ./test.ksh hello bye
bye world
[tkyte@desktop ~]$


excellent answer

Lily, December 06, 2006 - 10:28 am UTC

Tom
You example is very helpful for replace the string. But how about if I want to keep all other stuff in the new file, like

from

/db/db02/oradata/prd
/db/db01/oradata/prd


to

/db/db02/oradata/stg
/db/db01/oradata/stg


Thanks again.




Watch those quotes

Greg, December 06, 2006 - 2:46 pm UTC

Lily - if you didn't catch the change from Tom's example:

you have to use double quotes (") in ksh to get parameter substitution. Your script has single quotes ('). Also - you reference an invalid file in your 'cat' command, and you set variables in your script, but don't use them.

check out this example:
#!/bin/ksh
SID_1=$1
SID_2=$2

file=/tmp/rp_string.txt.2

cat $file | sed 's/$SID_1/$SID_2/' > rp_string.txt.tmp.2
cat rp_string.txt.tmp.2

cat $file | sed "s/$SID_1/$SID_2/" > rp_string.txt.tmp.2
cat rp_string.txt.tmp.2

when I run it:
sands> ./t2.ksh prd stg
/db/db02/oradata/prd
/db/db01/oradata/prd

/db/db02/oradata/stg
/db/db01/oradata/stg


Excellent answer and it solved my problem

Lily, December 06, 2006 - 5:34 pm UTC

Tom and Greg,
Thanks sooooo much for your helps. I was so careless and didn't catch Tom's answer with double quotes -- I still used single quotes when testing. Thanks to Greg pointed it out.

I feel very happy and believe it is the best web site for DBA.




CREATE OR REPLACE AND COMPILE vs. loadjava

Stewart Bryson, December 26, 2006 - 10:26 am UTC

Tom:

I know you're not a Java expert, but I simply cannot find another online resource that discusses Java stored procedures. OTN has relegated it to boutique status, I guess.

What is the difference between defining the class in this manner (create or replace and compile) versus writing a class file and using loadjava to load it to the database? Is the class you've defined here able to be imported in other java stored code?

Thanks.
Tom Kyte
December 26, 2006 - 9:08 pm UTC

well, loadjava will just typically load bytecode (no source code) and doesn't compile. (normal way to use it)

create or replace and compile takes the source code, compiles it into bytecode and loads the source and bytecode.

loadjava is a standalone command line program, create or replace needs a "sqlplus like environment" to work.


http://asktom.oracle.com/Misc/first-there-was.html

that is a book written by the guy that "owns" java in the database here at Oracle.

Thanks Tom

Stewart Bryson, December 26, 2006 - 10:20 pm UTC

I had about 20 follow-up questions, but i decided to just buy the book instead.

Thanks as always.

The Mensah book is excellent

Stewart Bryson, January 04, 2007 - 12:58 pm UTC

I'm only 50 pages in, and it's already worth the money. There's a nice little forward by one Mr. Tom Kyte as well.

Running OS cmd using java

praguefish, January 15, 2007 - 4:54 am UTC

Hi, I get the following error when trying to run the 1st example (usr/bin/ps):
java.lang.CloneNotSupportedException
at java.lang.Object.clone(Object.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at java.lang.Runtime.exec(Runtime.java)
at Util.RunThis(Util.java:14)

can anyone help??

java.lang.CloneNotSupportedException

Kuassi Mensah, January 20, 2007 - 2:03 am UTC

> Hi, I get the following error when trying to run the 1st > example (usr/bin/ps):
> java.lang.CloneNotSupportedException
> at java.lang.Object.clone(Object.java)
> at java.lang.Runtime.exec(Runtime.java)
> at java.lang.Runtime.exec(Runtime.java)
> at java.lang.Runtime.exec(Runtime.java)
> at Util.RunThis(Util.java:14)

This looks like a bug; which version of the RDBMS (and therefore Java VM) are you using?

Kuassi, http://db360.blogspot.com

Java SP vs PL/SQL SP

Priyanka Baxi, February 12, 2007 - 7:50 am UTC

Hi Tom,

I was working on Java Stored Procedure(SP) and comparing it with PL/SQL SP.While executing the respective procedures I found that Java SP takes less time as compared to PL/SQL SP.Could you please explain why it is so?The script that I executed is as follows:


create table test_java_sp as select * from all_objects;

insert into test_java_sp select * from all_objects;

insert into test_java_sp select * from all_objects;

insert into test_java_sp select * from all_objects;

insert into test_java_sp select * from all_objects;

insert into test_java_sp select * from all_objects;

insert into test_java_sp select * from all_objects;

insert into test_java_sp select * from all_objects;

insert into test_java_sp select * from all_objects;

commit;

CREATE OR REPLACE AND COMPILE
java source named "Demo"
as
import java.sql.*;
import oracle.jdbc.driver.*;
import java.util.ArrayList;
public class Demo {
//Call to Stored Procedure To Count The Rows
public static int Ob(){
try{
Connection conn = (new oracle.jdbc.OracleDriver()).defaultConnection();
conn.setAutoCommit(false);
String sql = "SELECT * from test_java_sp";
PreparedStatement prepStatement = conn.prepareStatement(sql);
ResultSet result = prepStatement.executeQuery();
int count1 = 0;
if(result!=null){
while(result.next()){
count1++;
}
result.close();
prepStatement.close();
conn.commit();
conn.setAutoCommit(true);
return count1;
}
else
{
return 1;
}

}
catch(SQLException sqlException){
sqlException.printStackTrace();
return 1;
}

}

}
/




Create or replace FUNCTION Java_Demo return number is language java name 'Demo.Ob() return integer';
/



CREATE OR REPLACE FUNCTION Pl_Demo RETURN NUMBER
AS
CURSOR test_cur IS SELECT * FROM test_java_sp;
test_rec test_cur%ROWTYPE;
count1 NUMBER:=0;
BEGIN
OPEN test_cur;
LOOP
FETCH test_cur INTO test_rec;
EXIT WHEN test_cur%NOTFOUND;
count1:=count1+1;
END LOOP;
CLOSE test_cur;
RETURN count1;
EXCEPTION
WHEN OTHERS THEN
IF test_cur%ISOPEN
THEN
CLOSE test_cur;
RETURN NULL;
END IF;
Raise_Application_Error (-20000,SQLCODE ||SQLERRM);
END;
/


set timing on

set serveroutput on
ALTER SYSTEM FLUSH SHARED_POOL;
ALTER SYSTEM FLUSH BUFFER_CACHE;
ALTER SESSION SET TRACEFILE_IDENTIFIER = 'pl_sql';

VARIABLE pl_count number

CALL Pl_Demo() into :pl_count;

ALTER SYSTEM FLUSH SHARED_POOL;
ALTER SYSTEM FLUSH BUFFER_CACHE;
ALTER SESSION SET TRACEFILE_IDENTIFIER = 'java';

VARIABLE java_count number

CALL Java_Demo() into :java_count;

Print java_count

Print pl_count

Regards,
Priyanka Baxi
Tom Kyte
February 12, 2007 - 10:52 am UTC

well, you are comparing apples to toasters.

You don't actually do anything of use here - did you trying for example accessing the data??

You would never do this code in real life, in real life a real programmer would

select count(*) from (select ....);

if they needed to count the rows.

the "reason", java is array fetching and you have (due to inefficient plsql coding) removed PLSQL's ability to do that.

In 10g, we just code:

CREATE OR REPLACE FUNCTION Pl_Demo RETURN NUMBER
AS
    count1 number := 0;
BEGIN
    for x in ( select * from test_java_sp )
    loop
        count1 := count1+1;
    end loop;
    return count1;
END;
/


and:



ops$tkyte%ORA10GR2> ALTER SYSTEM FLUSH SHARED_POOL;

System altered.

Elapsed: 00:00:00.31
ops$tkyte%ORA10GR2> ALTER SYSTEM FLUSH BUFFER_CACHE;

System altered.

Elapsed: 00:00:12.87
ops$tkyte%ORA10GR2> ALTER SESSION SET TRACEFILE_IDENTIFIER = 'pl_sql';

Session altered.

Elapsed: 00:00:00.01
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> VARIABLE pl_count number
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> CALL Pl_Demo() into :pl_count;

Call completed.

Elapsed: 00:00:02.56
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> ALTER SYSTEM FLUSH SHARED_POOL;

System altered.

Elapsed: 00:00:00.28
ops$tkyte%ORA10GR2> ALTER SYSTEM FLUSH BUFFER_CACHE;

System altered.

Elapsed: 00:00:07.71
ops$tkyte%ORA10GR2> ALTER SESSION SET TRACEFILE_IDENTIFIER = 'java';

Session altered.

Elapsed: 00:00:00.03
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> VARIABLE java_count number
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> CALL Java_Demo() into :java_count;

Call completed.

Elapsed: 00:00:03.27
ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> Print java_count

JAVA_COUNT
----------
    451099

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> Print pl_count

  PL_COUNT
----------
    451099

ops$tkyte%ORA10GR2> set echo off
ops$tkyte%ORA10GR2>



and in 9i, we might use bulk collect - but in ALL RELEASES I WOULD ENCOURAGE YOU (demand actually) that you actually compare something "useful" - no one would write code that does this in real life, benchmarks should reflect what you need to do.

What is difference between this logic and DBMS_SCHEDULER

GopiKrishna, February 15, 2007 - 2:08 am UTC

Hi Tom,

This is an excellent piece of work, but I heard in 10g there is DBMS_SCHEDULER PACKAGE, please explain how it differs with this logic.

Also I want to know whether any of Oracle 9i versions support DBMS_SCHEDULER package

Thanks
Tom Kyte
February 15, 2007 - 11:48 am UTC

you can use dbms_scheduler in 10g to execute code in the operating system, yes.

A reader, February 15, 2007 - 3:32 pm UTC

Tom,

I need to unzip file from Oracle PL/SQL. I am using java stored procedure from this post.

Zip file is located at UTL_FILE folder /mhsiebeldev/siebel/data/BIDAILY_MH_CUSTADDR_20070214.ZIP.
if I run below commnad from SQL*Plus nothing happens

SQL> exec rc('/bin/tar -xvZf /mhsiebeldev/siebel/data/BIDAILY_MH_CUSTADDR_20070214.ZIP')

PL/SQL procedure successfully completed.


If i run '/bin/ls -ltr' I get the below output.

Looks like I need to give correct path as command will be executed as Oracle system user

Can you please help?


SQL> exec rc('/bin/ls -ltr');
total 424
-rw-r--r-- 1 oracle amontfx 12920 Mar 8 2002 initdw.ora
-rw-rw-r-- 1 oracle amontfx 8385 Mar 9 2002 init.ora
-rw-r--r-- 1 oracle amontfx 1677 Aug 29 2005 initCRMDEV2.ora
-rw-r--r-- 1 oracle amontfx 1514 May 17 2006 initRMANDEV.temp
-rw-r--r-- 1 oracle amontfx 1574 May 17 2006 initRMANDEV.old
-rwSr----- 1 oracle amontfx 1536 May 18 2006 orapwRMANDEV
-rw-r----- 1 oracle amontfx 3584 May 18 2006 spfileRMANDEV.old
-rw-rw---- 1 oracle amontfx 24 May 22 2006 lkRMANDEV
-rw-r----- 1 oracle amontfx 4608 Jun 30 2006 spfileCRMDEV.ora
-rwSr----- 1 oracle amontfx 1536 Sep 7 16:18 orapwCRMDEV
-rw-r----- 1 oracle amontfx 4608 Nov 22 11:01 spfileCRMDEV2.ora
-rw-r----- 1 oracle dba 4608 Jan 29 17:00 spfileCRMDEV20129.bkp
-rw-r----- 1 oracle dba 4608 Jan 29 17:00 spfileCRMDEV0129.bkp
-rw-r--r-- 1 oracle dba 1677 Jan 29 17:00 initCRMDEV20129.bkp
-rw-r----- 1 oracle dba 4608 Jan 30 17:00 spfileCRMDEV20130.bkp
-rw-r----- 1 oracle dba 4608 Jan 30 17:00 spfileCRMDEV0130.bkp
-rw-r--r-- 1 oracle dba 1677 Jan 30 17:00 initCRMDEV20130.bkp
-rw-r----- 1 oracle dba 4608 Jan 31 17:00 spfileCRMDEV20131.bkp
-rw-r----- 1 oracle dba 4608 Jan 31 17:00 spfileCRMDEV0131.bkp
-rw-r--r-- 1 oracle dba 1677 Jan 31 17:00 initCRMDEV20131.bkp
-rw-r----- 1 oracle dba 4608 Feb 1 17:00 spfileCRMDEV20201.bkp
-rw-r----- 1 oracle dba 4608 Feb 1 17:00 spfileCRMDEV0201.bkp
-rw-r--r-- 1 oracle dba 1677 Feb 1 17:00 initCRMDEV20201.bkp
-rw-r----- 1 oracle dba 4608 Feb 2 17:00 spfileCRMDEV20202.bkp
-rw-r----- 1 oracle dba 4608 Feb 2 17:00 spfileCRMDEV0202.bkp
dba 1677 Feb 11 17:00 initCRMDEV20211.bkp

PL/SQL procedure successfully completed.

SQL>
Tom Kyte
February 16, 2007 - 1:34 pm UTC

put some debug in there please - basic stuff - read this thread - been down this "debug it please" path over and over.

Calculator Command in windows Hangs

A reader, February 28, 2007 - 10:02 am UTC

Tom,

I ran the code you provided and made a call to the calculator application in windows xp.

exec :x := RUN_CMD('C:\windows\system32\calc.exe')

The calc.exe runs but it Hangs. When i kill it at OS level the function completes successfully.

I don't understand what kind of interaction the calculator is asking. I made a batch file :

do_calc.bat
@echo off
c:\windows\system32\calc.exe

When I double click this batch file it calls the calculator.

Please guide me through this?
Tom Kyte
February 28, 2007 - 3:48 pm UTC

the database is running as a service

the service doesn't have a console, it is running in the background

so, when the service that is the database runs "calc.exe", it is running somewhere off in the ether - it cannot see your console.

A reader, March 02, 2007 - 9:02 am UTC

Hmmm, I understand that. Thanks for a brief explanation.

But then I have another question.

How to call the calculator from a database procedure?

Thank you for your time.
Tom Kyte
March 04, 2007 - 6:04 pm UTC

why would you want to call a GUI from a stored procedure - what would you possibly accomplish that way?

Java Web service calling C executable on OC4J

Gayatri, March 02, 2007 - 8:05 pm UTC

Tom,

I am looking for a way to expose C executable as a web service using Jdev. So I have created a java class that calls the C executable:

public class JavaInvokeC {
    public JavaInvokeC() {
    }

    public int invoke() throws java.io.IOException, 
                               java.lang.InterruptedException {
        String program = 
            "G:\\public_html\\targetexe.exe 11";
        System.out.println("invoking program: " + program);
        Process p = Runtime.getRuntime().exec(program);
        int exitValue = p.waitFor();
        System.out.println("exit val: " + p.exitValue());
        return exitValue;
    }
}

This code runs fine when I call this method from another class' Main method in Jdev. I am able to convert this java class into a web service and deploy the web service on the standalone OC4J. However the C executable is not being invoked.

I get back a message from the web service as 'Unable to get header stream in saveChanges'.

The method you have described is for executing unix command on a Database server. Is there something similar for OC4J. How can I get OC4J to run the C executable that is invoked by the Java web service?

Any pointers of how I can resolve this problem will help.

Thank you

Gaya3
Tom Kyte
March 04, 2007 - 12:55 pm UTC

what is "g:"

it is a network drive or something

can you not debug your java - have it print out useful stuff like "checking for file existence, found file, file is executable, attemtping to execute file.... blah blah blah..."

java code

A reader, March 04, 2007 - 3:24 pm UTC

The java code is very useful.

run COMMAND

sam, March 04, 2007 - 3:31 pm UTC

Tom:

Can you use RUN_CMD above to actually run perl or unix shell scripts from PL/SQL and pass parameters from PL/SQL.

FOr example, let us say I have a perl program that creates directories on the fielsystem (mkdir).

Can I have pl/sql read a column value in a table and then do create a directory on the file system /A or /B

If (field='A') then
run_cmd my_perl_program(A);
elsif (filed='B') then
run cmd my_perl_program(B);
END IF;


2. Would the run_CMD work for remote unix server through the web server on the remote machine? Does that perl have to be in the web server directory.
Tom Kyte
March 04, 2007 - 7:06 pm UTC

you can use run_cmd to pretty much run whatever you can type on the command line, yes.

if you can type:

$ my_perl_program(A)

then yes.

and run cmd will run things on the DATABASE SERVER only

run command

sam, March 04, 2007 - 8:34 pm UTC

Tom:

1. What do you mean by database server only? you mean the file system where the database is running?

2. Is there a way to do it on a remote system if you have a userid/password for the remote machine?

3. or by running a CGI program on the remote machine using a URL with utl_http?
Tom Kyte
March 05, 2007 - 12:27 pm UTC

1) yes.
2) no, well, that file system would have to be made available to the database server.
3) you would be posting the file, back to square one - right where you started from in the first place.

PL/SQL script for clean-up dump directories

Kamran, April 10, 2007 - 1:19 pm UTC

I wonder is it possible to clean up the bdump and udump directories based on a time parameter !



Tom Kyte
April 10, 2007 - 3:58 pm UTC

sure it is, not sure I'd use plsql (you'd need to use a bit of java to read the directory...)

if you don't care about them, just limit the max dump size to zero (apparently you don't)

or write a shell script and let cron (or whatever works like cron on your OS) wipe em out.

PL/SQL cycle alert log

kamran, April 10, 2007 - 1:29 pm UTC

Hi,

Could you give me a trick how to clean-up the bdump and udump directories on a time parameter from PL/SQL script !


Reg.

Kamran
Tom Kyte
April 10, 2007 - 3:58 pm UTC

why do you ask TWICE!?

Appologize

kamran, April 10, 2007 - 5:20 pm UTC

I appologize for it .It was my mistake as I thought, my first submt was unsuccessful. But it was there. I'll be careful next time !

Thanks

Kamran, April 12, 2007 - 11:52 am UTC

wow, great, after setting max_dump_size=0, our problem has been solved.

Thanks again !



utl_file

Kamran, April 16, 2007 - 1:02 pm UTC

I have a slight change in the requirement.

We don't like to use max_dump_size as on some of our databases we need all trace files
without any size specification. We would to just remove trace files after 7 days on all of
our servers ranging from oracle 8 to oracle 10g. Due to a vast rang of databases , we also
don't like to use java inside pl/sql .

This is some sort of management decision to use pl/sql without java and not to use parameter.

Is it possible to use utl_file package for this purpose ! If yes, kindly let me know how to do this. I'm in a horrible condition :)




Thx.

Kamran
Tom Kyte
April 16, 2007 - 1:41 pm UTC

you need java to read the directory and then, as stated, utl_file can fremove a file.

but you need to know the NAME of the file over 7 days and for that you will write java.

so, I'd probably rather just schedule a cron job and be done with it. A simple FIND command would do this in one line of shell script

you could even use dbms_scheduler in 10g to run said shell script if you wanted.

Regarding JVM Installation

A reader, May 09, 2007 - 2:55 am UTC

Hi Tom,

Our Java team has written Java stored procedures and packaged them in a JAR file.

They use loadjava utility to deploy the jar file in the database.

The deployment would happen from an Application Server and the Java Stored Procedures would be running on Database Server.

They have raised a concern saying that do they need to mention any pre-requisite for using loadjava on Application Server and JSP(JVM installed in database and the version of it).

Database Server Version : 10.2.0.3
Database Client Version : 9.2.0.8

Regards,
Sourabh S Jain

Need Function To Obtain Output

JC, June 05, 2007 - 1:34 pm UTC

Hi Tom


Thanks in advance for the JAVA code.

I have been able to modify your java to use on Windows OS and I was hoping that you could show me some code that calls the java procedure, captures the output into a buffer, and returns that buffer of information in a function call.


Thanks
Tom Kyte
June 06, 2007 - 1:27 pm UTC

in your program, just call dbms_output.get_lines (after making sure to have enabled dbms_output.enable)

it is in the dbms_output "buffer", sqlplus just calls get_lines to print to your screen, you can do the same.

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:45027262935845

Just A Thank You

Jim, June 06, 2007 - 2:07 pm UTC

I will look at this info you provided.
Just wanted to say thanks for your patience and guidence
I appreciate your knowledge being shared to folks like me that do not nearly have half the expertise.


Much simpler way to get TZ variable setting

Ron, July 11, 2007 - 2:08 pm UTC

I stumbled across the following method to get the TZ variable that the database was started with rather than having to use java to read the UNIX shell variable:

17:11:21 SQL> connect system@cado
Enter password: *******
Connected.
12:59:52 SQL> select dbms_scheduler.GET_SYS_TIME_ZONE_NAME from dual;

GET_SYS_TIME_ZONE_NAME
---------------------------------------------------------------------
UTC

Elapsed: 00:00:00.05

Too cool.

"sed" not found error when java procedure calls a unix script from oracle database

Ravinder, July 23, 2007 - 2:37 pm UTC

we are getting an error "sed" not found when a java procedure calls a shell script from a database/plsql

below are the steps to call a shell script from java procedure(java procedure inturn called from plsql)
****************************************************
Step1:
create or replace
FUNCTION run_cmd (cmd IN VARCHAR)
RETURN NUMBER
AS LANGUAGE JAVA NAME 'Utils.runScript(java.lang.String) return java.lang.String';
**********************************************************
step 2:
CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "Utils" AS
import java.io.*;
import java.lang.*;

public class Utils {
static public int runScript(String cmd)
throws IOException, InterruptedException {
int rv = -1;
Process proc = Runtime.getRuntime().exec(cmd);
InputStream err = proc.getErrorStream();
InputStream outProc = proc.getInputStream();
int nreadErr, nreadOut;
byte[] buf = new byte[1024];
do {
nreadErr = err.read(buf);
if (nreadErr > 0) {
System.err.write(buf,0,nreadErr);
}
nreadOut = outProc.read(buf);
if (nreadOut > 0) {
System.out.write(buf,0,nreadOut);
}
} while (nreadErr>0 && nreadOut>0);
rv = proc.waitFor();

return rv;
}
static public int raiseError(String uxcode, String message)
throws IOException, InterruptedException {
int rv = -1;
String cmdarray[] = new String[7];
cmdarray[0] = "/bin/logger";
cmdarray[1] = "-i";
cmdarray[2] = "-p";
cmdarray[3] = "local0.err";
cmdarray[4] = "-t";
cmdarray[5] = uxcode;
cmdarray[6] = message;
Process proc = Runtime.getRuntime().exec(cmdarray);
rv = proc.waitFor();

return rv;
}
static public String getProperty(String name) {
String val = "";
try {
val = System.getProperty(name);
} catch (Exception excp) {
val = excp.toString();
}
return val;
}
}

************************************************************
we are using 10.2.0 (10g),Solaris 5.10 and oracle application 11.5.10



it is working fine in oracle 9.2.0 and Solaris 5.10

Please let me know what could be the problem for throwing this error.


Tom Kyte
July 24, 2007 - 9:05 am UTC

you are making assumptions about your environment

your path is not what you think it is, it is the path of the dedicated server.

use fully qualified paths in your script - to avoid trojans, to be sure you are running what you think you should be running, and to avoid this.

Possible side effect

Mahomed Suria, September 11, 2007 - 12:45 pm UTC

I am using the following java stored proc to run a unix shell command through the oracle users job schedule.

CREATE OR REPLACE and COMPILE JAVA SOURCE
NAMED "MyCommand"
AS
import java.io.*;
import java.lang.*;

public class MyCommand extends Object
{

public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;

try
{
Process p = rt.exec(args);

int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];

// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer, 0, len);

rc = p.waitFor();
// do not leave object lying around, good practice to destroy
p.destroy();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}
/

I have a possible side effect which is that some processes of the form ora_j.... are being left behind.

e.g
oracle9 15177 1 4 Sep 1 ? 18:47 ora_j000_DB9
oracle9 15115 1 0 Sep 1 ? 9:46 ora_j002_DB9
oracle9 15179 1 0 Sep 1 ? 14:38 ora_j001_DB9

When I examine these processes, they have always run or are running the following sql:

select longdbcs from javasnm$ where short = :1

Any help would be appreciated !!



Tom Kyte
September 15, 2007 - 3:45 pm UTC

those are just the job queue processes, they will eventually go away, they will be idle (not actually RUNNING that sql, that might have been the last bit they ran) when not executing a job.

Accessing different server through oracle

Shubham, October 04, 2007 - 8:06 am UTC

Hi Tom,

I have a oracle instance in a Unix server (say A) and Informatica instance on another Unix server (say B).
(earlier both were on same server).

I have datafiles comming on B which is manipulated from Pl/Sql procedure on server A.
What should I do in this case.
Do we have something as sharing in Unix, which can suffice my need.

Thanks

preserving/setting env's

Tanya, October 04, 2007 - 1:31 pm UTC

Hi Tom,

I have this whole setup working, but am running into some environment problems.

I have tested the script that I'm calling from my ApEx app and it works fine at the UNIX level as oracle user. However, when it is called thru Apex, most of my PATH is just GONE!!! to system level commands such as wc and grep.

I've tried setting my env in my script but that doesn't seem to do any good.

Any ideas?

Thanks, Tanya.

perl script

A reader, October 08, 2007 - 7:09 am UTC

Dear Tom,
I need to run a perl command thru pl-sql.

BEGIN
dbms_java.set_output(1000000);
rc('/nikhilesh/test.sh');
rc('/usr/bin/perl -p -i -e ''s/Sam/Ram/g'' /nikhilesh/test.dat');
rc('/usr/bin/cat /nikhilesh/test.dat');
END;

test.sh contains
#!/bin/ksh
ls /projects/GLOSSIBaseline/Deployments/DataStream/Reports/ravi
perl -p -i -e 's/Sam/Ram/g' test.dat
cat /nikhilesh/test.dat

All permissions are in place. It doesn'r throw any error.
executes ls and cat properly but dosent change ravi.dat as a result of perl command.

BEGIN
dbms_java.grant_permission('NIKHIL','SYS:java.io.FilePermission','/nikhilesh/*','read,write,execute');
dbms_java.grant_permission
('NIKHIL',
'SYS:java.io.FilePermission',
'/usr/bin/perl',
'execute');
dbms_java.grant_permission
('NIKHIL',
'SYS:java.io.FilePermission',
'/usr/bin/ls',
'execute');
dbms_java.grant_permission
('NIKHIL',
'SYS:java.io.FilePermission',
'/usr/bin/cat',
'execute');
dbms_java.grant_permission
('NIKHIL',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
END;

Could you please help.
Thanks in advance.

Nikhilesh

Rights Issue

BC, October 09, 2007 - 2:14 pm UTC

I am running into invoker vs definer rights issue.
The objective is as follows
"GENERAL" is to house all common utilities. ( We have several users / schemas that use utilities stored in this schema )
"APP" should be able to execute this utility ( Listed below )

GRANTEE         TYPE_NAME                           NAME                                ACTION                                     SEQ ENABLED
--------------- ----------------------------------- ----------------------------------- ----------------------------------- ---------- --------
GENERAL         java.lang.RuntimePermission         readFileDescriptor                                                             464 ENABLED
GENERAL         java.lang.RuntimePermission         writeFileDescriptor                                                            444 ENABLED
APP             java.io.FilePermission              /usr/bin/script1                    execute                                    507 ENABLED
APP             java.lang.RuntimePermission         readFileDescriptor                                                             505 ENABLED
APP             java.lang.RuntimePermission         writeFileDescriptor                                                            504 ENABLED


When I log in as "APP" and execute the following

declare
   l_num number;
begin
   l_num := system_command.run_command('/usr/bin/script1 /usr2/dev/app/out/file_to_process.txt');
end;
/


I get the below message

java.security.AccessControlException: the Permission (java.io.FilePermission /usr/bin/script1 execute) has not
been granted to GENERAL. The PL/SQL to grant this is dbms_java.grant_permission( 'GENERAL', 'SYS:java.io.FilePermission',
'/usr/bin/script1', 'execute' )
        at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
        at java.security.AccessController.checkPermission(AccessController.java)
        at java.lang.SecurityManager.checkPermission(SecurityManager.java)
        at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java)
        at java.lang.SecurityManager.checkExec(SecurityManager.java)
        at java.lang.Runtime.exec(Runtime.java)
        at java.lang.Runtime.exec(Runtime.java)
        at java.lang.Runtime.exec(Runtime.java)
        at java.lang.Runtime.exec(Runtime.java)
        at java_util.RunCmd(JAVA_UTIL:32)
-1


In the "GENERAL" schema, I created the following,

create or replace and compile java source named java_util authid current_user as
import java.io.*;
import java.sql.*;

public class java_util
{

   public static int RunCmd(String args)
   {
      Runtime rt = Runtime.getRuntime();
      int rc = -1;
      try
      {
         Process p = rt.exec(args);
         int bufSize = 4096;
         BufferedInputStream bis =
         new BufferedInputStream(p.getInputStream(), bufSize);
         int len;
         byte buffer[] = new byte[bufSize];

         // Echo back what the program spit out
         while ((len = bis.read(buffer, 0, bufSize)) != -1)
            System.out.write(buffer, 0, len);
            rc = p.waitFor();
      }
      catch (Exception e)
      {
         e.printStackTrace();
         rc = -1;
      }
      finally
      {
         return rc;
      }
   }
}   

create or replace package system_command authid current_user is
   
   function run_command
   (
      p_command          in          varchar2
   )
   return number;
   
end system_command;
   
create or replace package body system_command is

   function run_command
   (
      p_command          in          varchar2
   )
   return number 
   as
   language java name 'java_util.RunCmd(java.lang.String) return integer';
   
end system_command;


The shell script contains the following
/usr/bin/script1 
================
#!/usr/bin/ksh
GNUPGHOME=/systemadmin/gpg
export GNUPGHOME
/usr/bin/gpg -quite --yes --batch --armor --no-permission-warning -e -r xxx -o yyy $1
Return=$?


When I grant execute on /usr/bin/script1 to "GENERAL" the programs work as expected. I don't want to do that as we have several users / applications that may uses these utilities.

Database Version 10.2
Operating System Linux

Tom, Thank you very much your help is highly appreciated.


Thanks

BC, October 17, 2007 - 2:20 pm UTC

Tom,

I found the answer to this in your followup ( Followup June 6, 2007 - 12pm US/Eastern) to another post.

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:255615160805

Thank you, you are awesome.

BC

CloneNotSupportedException

Asis, October 26, 2007 - 4:32 am UTC

Hi Tom,

I am executing the below procedure as explained above and getting the error:

declare
x number;
begin
dbms_java.set_output(1000000);
dbms_output.enable(1000000);
x:=run_cmd('/home/oracle/upload/ls');
dbms_output.put_line('Returned value='||x);
exception
when others then dbms_output.put_line('Sql error='||substr(sqlerrm,1,250));
end;
/

java.lang.CloneNotSupportedException
at java.lang.Object.clone(Native Method)
at java.lang.Runtime.exec(Runtime.java:543)
at java.lang.Runtime.exec(Runtime.java:491)
at java.lang.Runtime.exec(Runtime.java:457)
at Util.RunThis(Util:11)

Any idea how to resolve this clone not supported exception?

Tom Kyte
October 29, 2007 - 10:37 am UTC

you know what, that exception block of yours makes me ill.

I
will
never
understand

I will never ever understand why people do that. Time after time after time.

Makes me sick. Makes me frightened for the future of programming.

I refuse to look at anything that has it anymore. I consider when others, not followed by raise, to be a bug. Maybe that is your issue (it isn't, but I refuse to look any further).

Please - tell us why you do that - when others re-print the error and make the error code GO AWAY so no one knows that an error happened.

Why did you waste the keystrokes - what is the thought process behind catching ALL and ANY exception and hiding it?

java.lang.CloneNotSupportedException

Asis, October 29, 2007 - 2:54 am UTC

Hi Tom,

I have been struggling to get this work for weeks now but unable to understand whether my 10.2.0.1.0 version 10g database does not understand the code or i am doing something wrong.

I would appreciate your input on this please..

Thanks,
Asis
Tom Kyte
October 29, 2007 - 12:52 pm UTC

I cannot reproduce, cut and paste this example from your system for us.



ops$tkyte%ORA10GR2> drop user rt_test cascade;

User dropped.

ops$tkyte%ORA10GR2> create user rt_test identified by rt_test;

User created.

ops$tkyte%ORA10GR2> grant create session, create procedure to rt_test;

Grant succeeded.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> begin
  2    dbms_java.grant_permission
  3    ('RT_TEST',
  4     'java.io.FilePermission',
  5     '/bin/ls',
  6     'execute');
  7
  8    dbms_java.grant_permission
  9    ('RT_TEST',
 10     'java.lang.RuntimePermission',
 11     '*',
 12     'writeFileDescriptor' );
 13  end;
 14  /

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> connect rt_test/rt_test
Connected.
rt_test%ORA10GR2> 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    public static int RunThis(String args)
 10    {
 11    Runtime rt = Runtime.getRuntime();
 12    int        rc = -1;
 13
 14    try
 15    {
 16       Process p = rt.exec(args);
 17
 18       int bufSize = 4096;
 19       BufferedInputStream bis =
 20        new BufferedInputStream(p.getInputStream(), bufSize);
 21       int len;
 22       byte buffer[] = new byte[bufSize];
 23
 24       // Echo back what the program spit out
 25       while ((len = bis.read(buffer, 0, bufSize)) != -1)
 26          System.out.write(buffer, 0, len);
 27
 28       rc = p.waitFor();
 29    }
 30    catch (Exception e)
 31    {
 32       e.printStackTrace();
 33       rc = -1;
 34    }
 35    finally
 36    {
 37       return rc;
 38    }
 39    }
 40  }
 41  /

Java created.

rt_test%ORA10GR2> 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.

rt_test%ORA10GR2> create or replace procedure RC(p_cmd in varchar2)
  2  as
  3    x number;
  4  begin
  5    x := run_cmd(p_cmd);
  6  end;
  7  /

Procedure created.

rt_test%ORA10GR2> variable x number;
rt_test%ORA10GR2> set serveroutput on
rt_test%ORA10GR2> exec dbms_java.set_output(100000);

PL/SQL procedure successfully completed.

rt_test%ORA10GR2> exec :x := RUN_CMD('/bin/ls /tmp');
1_62.dbf
1_63.dbf
1_64.dbf
1_65.dbf

executing custom shell script from PL/SQL

Asis, November 08, 2007 - 12:36 am UTC

Hi Tom,

I am trying to execute a custom shell script and not a command. I am giving the SYS:java.io.FilePermission to execute the custom shell script which will call sql loader to load data into table - but this is showing again the following error:
java.lang.CloneNotSupportedException
at java.lang.Object.clone(Native Method)
at java.lang.Runtime.exec(Runtime.java:543)
at java.lang.Runtime.exec(Runtime.java:491)
at java.lang.Runtime.exec(Runtime.java:457)
at Util.RunThis(Util:11)
Returned value=-1
I would appreciate your guidance on this please...
Thanks a lot

It Worked!

Asis, November 08, 2007 - 5:46 am UTC

Hi Tom,

It worked. I replaced java.io.FilePermission with SYS:java.io.FilePermission, as i was giving the permissions from SYS account.

Thanks a lot.

cal shell script from pl/sql proc

kanna, November 13, 2007 - 2:08 am UTC

Thanks Tom for the above java proc to call a script file.......


but is that i have very little knowledge to understand this but i have to get this done as early as possible i mean calling a shell script from plsql .....

i have run successfully the java proc UTIL ..
please find below wht i have done

create or replace and compile
java source named "Util"
as
import java.io.*;
import java.lang.*;

public class Util extends Object
{
public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;
try
{
Process p = rt.exec(args);
int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];

// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer, 0, len);
rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}
-------------------------------

create or replace
function RUN_CMD(p_cmd in varchar2) return number
as
language java
name 'Util.RunThis(java.lang.String) return integer';

------------------------------------

create or replace procedure RC(p_cmd in varchar2)
as
x number;
begin
x := run_cmd(p_cmd);
end;





begin
dbms_java.grant_permission
('APPS',
'java.io.FilePermission',
'/usr/bin/ls',
'read, write, execute, delete');

dbms_java.grant_permission
('APPS',
'java.io.FilePermission',
'/usr/tmp/sh',
'read, write, execute, delete');


dbms_java.grant_permission
('APPS',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;

---------------------------

variable x number;
set serveroutput on
exec dbms_java.set_output(100000);

exec :x := RUN_CMD('/usr/bin/ls /tmp');

we r getting all the files listed in folder /tmp

but we r unable to do this below where we would like to create a log file using this command

exec :x := RUN_CMD('/usr/tmp/sh tst.sh');

can you pls let us know whts going wrong from our side









Tom Kyte
November 16, 2007 - 2:15 pm UTC

these are words that scare me to death:

but is that i have very little knowledge to understand this but i have to get
this done as early as possible i mean calling a shell script from plsql .....


translation:

I have no idea what I'm doing.
But this looks like it might do something useful.
I have no idea how it works, or what security implications there might be and I won't take the time to get there.
Please make it do what I mean to do.


your attempt to run a shell script by granting execute on sh to this user opens up the ability to run ANY SHELL SCRIPT AS ORACLE by this user.

that and the "a" and "e" keys are apparently broken on your keyboard.


you'll find you have a permission or environment problem. does /usr/tmp/sh exist. is it executable by the ORACLE process (you should get a cold shudder if the answer is yes hopefully now - now that you understand the rather large hole you've exposed in your system).


I suggest:

if you have 10g, use dbms_scheduler, it can run external processes. And scripts. And if you follow its directions, you stand a chance of securing it a bit too...

execute Unix script from java stored procedure

Krishna Chaitanya, December 08, 2007 - 12:10 pm UTC

Hi Tom,

i used the java stored procedure to execute a unix script from oracle.

but it works only halfway. while trying to FTP the file it doesnt work.while this script works when executed through unix server.

#!/usr/bin/sh
VALUE=`sqlplus -s safari_owner/welcome@colldmqa <<END
rem -------------------
set linesize 80
set arraysize 1
set verify off
set feedback off
rem -------------------

set serveroutput on

whenever oserror exit sql.oscode
whenever sqlerror exit sql.sqlcode

execute safari_owner.SAFARI_UPLOAD_FILE_STATUS;
exit sql.sqlcode;
END`
echo $VALUE
if [ -z "$VALUE" ]; then
echo "No rows returned from database"
exit 0
else
e=`head -1 "$VALUE"|awk '{print $1}'`
ft="ftp_xml_file_new.sh $e"
sh $ft
fi



please help ....the java program and oracle function and procedure works well to execute a simple script like "echo"
let me know if you require the to check the java procedure and oracle funtion and procedure.


its really urgent for me ..
Thanks
Krishna

Tom Kyte
December 10, 2007 - 10:54 am UTC

well, not any clue for you

since I don't have your entire suite of scripts.

I would suggest perhaps adding some DEBUG to your scripts, so you can see what is and what is not getting executed.

that is where I would start.

trigger executing SP that calls unix script

Krishna Chaitanya, December 10, 2007 - 8:09 pm UTC

Hi Tom,

it was my mistake and i resolved it.
just wanted to know is there any way to create such a tigger from which we can pass values to the procedure that executes Unix script.

Basically your oracle procedure helped me to execute Unix script but i am unable to execute this procedure through trigger (AFTER INSERT ) and take the values as reference in Unix script..

please help me to get this problem resolved.

Thanks in advance.
Krishna
Tom Kyte
December 11, 2007 - 7:38 am UTC

you just "pass them in"


exec rc('/usr/bin/ps -ef');

just like that.

krishna chaitanya, December 11, 2007 - 10:09 am UTC

Hi Tom,

below is the code of the trigger that i am using to execute the script.but i need the value of the in this procedure.
how to pass values(:new.file_name :new.FILE_UPLOAD_KEY :new.UPLOAD_STATUS_CODE) in the procedure with the help of trigger.

CREATE OR REPLACE TRIGGER safari_owner.safari_upload_trig
AFTER INSERT
ON safari_owner.SAFARI_UPLOAD_REQUEST
REFERENCING NEW AS NEW
FOR EACH ROW
BEGIN
dbms_output.enable(1000000);
dbms_java.set_output(1000000);
safari_owner.rc('/usr/bin/sh /home/powermart/krishna/scripts/retry :new.file_name :new.FILE_UPLOAD_KEY :new.UPLOAD_STATUS_CODE');
END;
/

pleae help..

Thanks
Krishna
Tom Kyte
December 11, 2007 - 11:07 am UTC

concatenate - you build a string....

(careful there, you gave execute on /usr/bin/sh - you can execute ANYTHING, that would not fly on a real production system, quite dangerous)


..../scripts/retry ' || :new.file_name || ' ' || :new.file_upload_key .....


krishna chaitanya, December 11, 2007 - 11:13 am UTC

thanks tom for the great suggesstion.

krishna chaitanya, December 11, 2007 - 5:34 pm UTC

Hi Tom,

i am stuck at one point and need your help very urgently.
Problem: how can i take the output of unix script as a out parameter of the procedure written below that executes the unix script

CREATE OR REPLACE procedure SAFARI_OWNER.RC(p_cmd in varchar2)
as
x number;
begin
x := run_cmd(p_cmd);
end;
/

please suggest.

Thanks in advance
Krishna

One question on this issue

Reader from India, December 12, 2007 - 11:57 pm UTC

Say I have two databases OraDB1 and OraDB2. I have written a Java class in OraDB2. Can I access this class from a Java or PL/SQL procedure in OraDB1. (not through DB LINK)
Tom Kyte
December 13, 2007 - 9:44 am UTC

by magic?

I mean - come on - without the dblink how do you think this would work.


In theory, you could load the type-4 thin jdbc driver into the database and open a connection to the remote server using a jdbc java program you load into db1 - but that would be "not an easy or smart thing" to do. It would not be able to participate in the same transaction, you'd have to pass a username and password around, ugh.

A database link is the correct approach here.

connection of .net with oracle backend

Krishna Chaitanya, December 14, 2007 - 11:58 pm UTC

Hi Tom,

i really appreciate for the quick response and very useful clues.
again i have a big prob,
basically i have a frontend application from which user generates a file name and this filename entry goes to a table.
now since i have trigger on the same table so this trigger calls the proc and finally proc executes the unix script and it takes around 2-3 hrs to complete this script functionality.
so i wanted to know if i generate the file name from the frontend then i close the frontend window at the same time so will the backgound process will continue its execution or not. because user will generate the file name but he should not wait for the whole backend process to complete. i.e the frontend process should be independent of the backend ..

if this wont work then please propose a solution so that i can get rid of this issue.

Thanks
Krishna

Tom Kyte
December 17, 2007 - 10:52 am UTC

if you want some stored procedure to run in the background, you would use dbms_job or dbms_scheduler.

If you say you have a SCRIPT that runs in the OS for hours, I would not suggest or even consider running it from a stored procedure - in fact running any script is sort of shaky since you cannot really "professionally interact with the script", it is not like an API (application program interface) subroutine call or anything. If you have a script to run for hours, you'll want to find some other way to do it - not from the database.

use of DBMS_job and dbms_scheduler

A reader, December 17, 2007 - 10:48 pm UTC

Hi Tom,

please explain in brief how can i user dbms_job to run the stored procedure when a row is inserted into the table.

my requirement is like we are inserting a row through frontend using VB.net.
now after a row is inserted the procedure has to run and perform the activity .so how can DBMS_JOB or DBMS_SCHEDULER would be useful.

thanks
Krishna
Tom Kyte
December 18, 2007 - 1:29 pm UTC

1) this is as brief as I can be
create trigger t after insert on t
declare
  l_job number;
begin
  dbms_job.submit( l_job, 'proc;' );
end;
/




Just what i was looking for

Dave, January 08, 2008 - 4:28 pm UTC

This thread just helped me a ton.

thanks Tom

Setting sqlplus environment through plsql

Sharon, February 11, 2008 - 12:47 am UTC

Hello Tom,
I have been reading your threads and find them very useful and I get lots of relevant information from them.
I have a question:
I want to use command SET SQLPROMPT <username> when ever a user is logged in. For e.g.: If SCOTT is login to sql plus I want the SQL > to be displayed as 'SCOTT >'. I plan to fire this command in a LOGON Trigger. Is there any work around for this?
I am using Oracle 10g, on windows 2k.
Please help.
Thanks.

Tom Kyte
February 11, 2008 - 10:16 pm UTC

think about this please...


sqlprompt - there is some variable in memory somewhere in sqlplus, a program, a program you or I could have written.

You want the database to be able to magically "just write to the client memory, execute some code on the client, silently, magically"

that is called a virus.


You would use a login.sql or glogin.sql file on a shared install - that is a script SQLPLUS runs upon startup.

Would you not be very upset if the database could actually reach out and modify memory arbitrarily in your own developed applications?

To Sharon from UAE - Setting sqlplus environment through plsql

A reader, February 11, 2008 - 11:44 am UTC

Hi sharon,

Your question has nothing to do with original post... However.. please check following link :
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:446220075876

Alternatively, user following
http://asktom.oracle.com/pls/ask/search?p_string=login.sql

Thanks Tom

Sharon, February 13, 2008 - 1:10 am UTC

Hi,
As you said writing such a script in java was not good, I understand that, and I agree to it.
As writing script in glogin/login, I had given it a try. In 8i for a reconnect from the same sqlplus screen it was not giving the required result, for 10g I got my desired result.
Thanks for your time and help.

Really Useful Trick !!

Jekyl, March 10, 2008 - 7:56 am UTC

Excellent Article Tom.

Everything worked firne with me excep the final result, I got this error :-

SQL> set serveroutput on size 1000000;
SQL> exec dbms_java.set_output(1000000);

PL/SQL procedure successfully completed.

SQL> exec rc('/usr/bin/ps -ef');
java.lang.ArrayIndexOutOfBoundsException
at Util.RunThis(Util.java:14)

PL/SQL procedure successfully completed.

What may be the reason ?

Tom Kyte
March 10, 2008 - 11:45 am UTC

ctl-f for the word ArrayIndexOutOfBoundsException on this page and see what you see...

about $path issue - historics ?

Jens Ludwig, April 10, 2008 - 4:53 pm UTC

Good evening,

just a historic question for trying to understand such a path issue i just encountered.

running the same stored procedure on a 9.2 (not set up by me) and a 10g2 (set up by me)it seems to behave different regarding unsetting $PATH in the shell.

9.2 doesnt seem to unset the $PATH but i´m not sure if this is due to slightly differen enviroment setups or if that unset was introduced with oracle 10.

Tom Kyte
April 10, 2008 - 8:32 pm UTC

I don't know what you are referring to here.

can JAVA stored procedure run commands on client ?

A reader, April 11, 2008 - 3:59 pm UTC

Hi Tom,
Above examples show how to run host commands from database using JAVA stored procedure. The host commands run on the server hosting the database. Is it possible to use same approach to run client commands ?
Assuming "oscmd" is a java stored program in database residing on server X. If i call "oscmd" remotely from a client Y using TNS connection then commands will run on server X. Is there a way to run host commands on client Y from java program in database on server X ? If it is not possible with this approach is there any other way ?

thanks

Tom Kyte
April 11, 2008 - 4:12 pm UTC

that would be very virus like wouldn't it.

Think about this - you really want a program running on machine X to be able to execute arbitrary code "as some user" (heck, what user?) on some other machine?

No, it will not happen, unless that client machine itself that you want to execute code on HAS A SERVER of some sort, providing a published service that other machines can connect to and run stuff with.

Unix script not executed

Vikram Rathore, April 24, 2008 - 6:21 am UTC

Tom,

I have implemented the code as below:-
begin
      dbms_java.grant_permission
      ('ASR_OWNER',
       'java.io.FilePermission',
       '/d2/users/rathorv2/*',
       'execute');      
      dbms_java.grant_permission
      ('ASR_OWNER',
       'java.io.FilePermission',
       '/u36/app/1SR/v69/*',
       'execute');             
      dbms_java.grant_permission
      ('ASR_OWNER',
       'java.io.FilePermission',
       '/usr/bin/*',
       'execute');
  
      dbms_java.grant_permission
      ('ASR_OWNER',
       'java.lang.RuntimePermission',
       '*',
       'writeFileDescriptor' );
      
      dbms_java.grant_permission
      ( 'ASR_OWNER', 
 'SYS:java.io.FilePermission',
 '<<ALL FILES>>', 
 'execute' );
  end;
  /


create or replace and compile
  java source named "Util"
  as
  import java.io.*;
  import java.lang.*;
  
  public class Util extends Object
  {
  
    public static int RunThis(String args)
    {
    Runtime rt = Runtime.getRuntime();
    int        rc = -1;
  
    try
    {
       System.out.println(args);
       Process p = rt.exec(args);
  
       int bufSize = 4096;
       BufferedInputStream bis =
        new BufferedInputStream(p.getInputStream(), bufSize);
       int len;
       byte buffer[] = new byte[bufSize];
  
       // Echo back what the program spit out
       while ((len = bis.read(buffer, 0, bufSize)) != -1)
          System.out.write(buffer, 0, len);
  
       rc = p.waitFor();
    }
    catch (Exception e)
    {
       e.printStackTrace();
       rc = -1;
    }
    finally
    {
       return rc;
    }
    }
  }
  /

create or replace
function RUN_CMD( p_cmd  in varchar2) return number
as
language java
name 'Util.RunThis(java.lang.String) return integer';


create or replace procedure RC(p_cmd in varchar2)
as
x number;
begin
x := run_cmd(p_cmd);
end;

Till this point it's all exactly the same code as given by you.
Now I have created unix script

t1.sh
#!/bin/sh
/usr/bin/nohup sqlplus asr_owner/XXXXXX @temp.sql > nohup_temp.log &

exit;

temp.sql
d2/users/rathorv2> $cat temp.sql
SET HEAD OFF
SET PAGESIZE 0
SET VERIFY OFF
SET TERMOUT OFF
SET LINE 100
SET WRAP ON
SET FEEDBACK OFF
SET TRIMSPOOL ON

select *
from asr_owner.emp

spool gl_2006_09.csv
/
spool off

exit;

However when I run this it neither generates the log file nor the csv file.
SQL> set serveroutput on size 1000000
SQL> exec dbms_java.set_output(1000000);

PL/SQL procedure successfully completed.

SQL> exec rc('/usr/bin/sh /d2/users/rathorv2/t1.sh');
/usr/bin/sh /d2/users/rathorv2/t1.sh

PL/SQL procedure successfully completed.

d2/users/rathorv2> $ls -altr *.log
ls: *.log not found

d2/users/rathorv2> $ls -altr gl_2006_09.csv
ls: gl_2006_09.csv not found

Can you please help me on this. Am I doing something wrong or am I missing some settings
Tom Kyte
April 28, 2008 - 11:37 am UTC

*environment*

what is "sqlplus", think about this.... where is sqlplus... what sqlplus might you be running (or not) if the environment is not set up....

you are running in someone else's environment! not yours.


how about starting with "echo hello > /tmp/something.txt"

just to see it works, then start debugging from there on up.

Process hangs

Christoph, May 05, 2008 - 6:03 am UTC

Dear Tom,

above "A Reader" was stating that the run_cmd is hanging in a windows environment when running calc.exe. I can understand your doubts about the gui running inside the db service. but when i want to run a program without any gui i face the same problems. in my particular case i want to run sysinternals pskill tool. when i execute it, it creates a new system process pskill and unless i remove this process manually my sql*plus session is blocked.
Is there anyway to accomplish my needs with the run_cmd approach.

Thanks in advance
Christoph
Tom Kyte
May 05, 2008 - 10:20 am UTC

your pskill is probably waiting on some terminal input/output - and there ISN'T any terminal.

This has to do with the way windows works - undoubtedly here - pskill is waiting for you to type something - and you aren't.

By the way, the database runs with a low privileged user, it is doubtful that it'll work - perhaps that is the problem in the first place - pskill is executed, processed your command line arguments and is saying something like "so sorry, we cannot do that, press enter to continue"


I would discourage this approach, it is not likely you want to kill OS processes from a stored procedure executed in the database - I cannot think of anything good coming from this.

Process hangs

Christoph, May 05, 2008 - 11:47 am UTC

Dear Tom,

our problem in this case is that our customer demnads the database to be the process monitoring system that the application is working transparent over mutliple operating systems. thing is, we are using the run_cmd to start and stop and eventually kill a c++ program which is responsible for tcp/ip communication with plcs. there are times when we need to get rid of the whole process tree (including all threads of the process) if something really bad (on the other side) happens. we know that this is not the way to go as it does not solve the problem, but... anyway - do you think we have a chance to use the run_cmd in a non blocking way? would it help to write a wrapper? what kind of privileges we would need?

thanks in advance
Christoph
Tom Kyte
May 05, 2008 - 2:52 pm UTC

sorry, but you won't get there from here - i will reiterate a million times: killing a process from a stored procedure sounds like a horrible idea - you should change that "requirement"

You would best be served by creating a "monitoring bit of software - sort of like Oracle has Enterprise manager - to control your processes"

You will not be very successful on windows unless you install the database to run as "your user" which would be beyond a bad idea.

You need the privileges to kill a process on windows - windows would tell you that.

executing custom shell script from PL/SQL

Raj Thangaraj, May 29, 2008 - 1:12 pm UTC

I am trying to execute custom shell script from PL/SQL.

When I run "exec rc('/tmp/putOraclemessage.sh ./test.msg &');", I see this result "PL/SQL procedure successfully completed."

But looks like this is not executed. This script will run a java class.

Please help.
Tom Kyte
May 29, 2008 - 1:33 pm UTC

you know, that & is sort of "meaningless"

ctl-f for

"you are running a shell specific command"

on this page to see that discussion.



executing custom shell script from PL/SQL

Raj Thangaraj, June 02, 2008 - 9:12 am UTC

I am trying to execute custom shell script from PL/SQL.

These are my permissions. ------------------------------------------------------------------------
begin
dbms_java.grant_permission
('JAVAUSER',
'SYS:java.io.FilePermission',
'/bea/gsipjapps/oracleutility/putOraclemessage.sh',
'execute');

dbms_java.grant_permission
('JAVAUSER',
'SYS:java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;
/
------------------------------------------------------------------------

------------------------------------------------------------------------
begin
dbms_java.grant_permission
('JAVAUSER',
'java.io.FilePermission',
'/bea/gsipjapps/oracleutility/putOraclemessage.sh',
'execute');

dbms_java.grant_permission
('JAVAUSER',
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
end;
/
------------------------------------------------------------------------

Here is my custom script named "Utility.sh" . I have given 777 permission to this script.........
------------------------------------------------------------------------
JAVA_HOME=/jdk142_10

export CLASSPATH=${CLASSPATH}:./log4j.jar
export CLASSPATH=${CLASSPATH}:./JavaProject.jar

echo CLASSPATH=${CLASSPATH}

${JAVA_HOME}/bin/java -version

${JAVA_HOME}/bin/java -classpath ${CLASSPATH} -Dlog4j.configuration=file:./OracleUtility_log4j.xml com.gm.gsip.utility.OraclePutJMSMQMessage $1
-----------------------------------------------------------------------

This is the command I use in sql...................
-----------------------------------------------------------------------
exec rc('/bea/gsipjapps/oracleutility/Utility.sh ./input.file &');
-----------------------------------------------------------------------

When I run the exec command, I don't see any errors. But nothing is happening. When I do a exec rc('/usr/bin/ps -ef'); it works!!

Please help!!!!!
Tom Kyte
June 02, 2008 - 11:44 am UTC

hmmm, one wonders what directory might "." be.

How about this - how about you take 15 steps back and debug this?

eg: put as the beginning of the shell script something like:

#!/bin/sh # tell someone what shell you might be wanting to use
echo Hello World > /tmp/$$.dat
exit



See that you can RUN a script first. Then, move up from there.


Please remember - you don't know what directory you are in (so, you might well need to cd somewhere)

You don't know what your environment is, you have no idea what the classpath is - yet you add to the END OF IT? You should probably just be OVERWRITING it entirely - you have no idea what it might be.

You didn't say what shell to even use - you are not running this from a shell (that is why a default shell might work sometimes there - you run from a shell and that shell says "I am the default", when you run from Oracle there is no default shell there...)


and well, we already covered the & - it is MEANINGLESS IN THIS CONTEXT - get rid of it.



tried this..

Raj Thangaraj, June 02, 2008 - 9:37 am UTC

I tried this and it did not work too..I don't see any errors.

exec rc('sh -c "/tmp/Utility.sh ./test.msg"');

Also I have given this permission

dbms_java.grant_permission
('JAVAUSER',
'SYS:java.io.FilePermission',
'<<ALL FILES>>',
'execute');

dbms_java.grant_permission
('JAVAUSER',
'java.io.FilePermission',
'<<ALL FILES>>',
'execute');

Tom Kyte
June 02, 2008 - 11:45 am UTC

holy cow

stop, please - do the ctl-f I told you to, use debugging 101 techniques.

but DO NOT RUN SH!!! please think about what that would mean security wise - please

One step closer

Raj Thangaraj, June 02, 2008 - 10:11 am UTC

Looks like finally, my script is getting executed using

exec rc('/usr/bin/sh -c "/tmp/Utility.sh"');

I am trying to run Java in the script. That is not getting executed.

Here is my script
-----------------------------------------------
export JAVA_HOME=/jdk142_10
export APP_PATH=/tmp

export CLASSPATH=${CLASSPATH}:${APP_PATH}/log4j.jar
export CLASSPATH=${CLASSPATH}:${APP_PATH}/JavaProjct.jar

echo JAVA_HOME=${JAVA_HOME}
echo APP_PATH=${APP_PATH}
echo CLASSPATH=${CLASSPATH}

sh -c '${JAVA_HOME}/bin/java -version'

sh -c '${JAVA_HOME}/bin/java -classpath ${CLASSPATH} -Dlog4j.configuration=file:./OracleUtility_log4j.xml com.utility.javautility ./test.msg'
-----------------------------------------------

I am getting the output
JAVA_HOME=/jdk142_10
APP_PATH=/tmp/oracleutility
CLASSPATH=:/bea/gsipjapps/oracleutility/log4j.jar:/bea/gsipjapps/oracleutility/JavaP
roject.jar
--------------------------------

Just my java is not getting executed
Tom Kyte
June 02, 2008 - 11:56 am UTC

stop it with the /usr/bin/sh - you are as about insecure here as you can be. stop grasping at straws here - do not use the sh that way.

just put #!/usr/bin/sh in the script.


it should be obvious why you are not running java. Why do you presume your environment includes /usr/bin - "sh" is not a command that is there apparently, it is not in your path.

removed sh

Raj Thangaraj, June 02, 2008 - 1:26 pm UTC

Sorry, I removed the sh.

This is my procedure call
exec rc('sh -c "/tmp/utility.sh /tmp/test.msg"');

This is my script, utility.sh
--------------------------------------------------------------
#!/usr/bin/sh

export JAVA_HOME=/jdk142_10
export APP_PATH=/tmp

export CLASSPATH=${CLASSPATH}:${APP_PATH}/log4j.jar
export CLASSPATH=${CLASSPATH}:${APP_PATH}/JavaProjct.jar

echo JAVA_HOME=${JAVA_HOME}
echo APP_PATH=${APP_PATH}
echo CLASSPATH=${CLASSPATH}
echo Filename=${1}

${JAVA_HOME}/bin/java -version

${JAVA_HOME}/bin/java -classpath ${CLASSPATH} -Dlog4j.configuration=file:./OracleUtility_log4j.xml com.javautility ./MQ_dev.properties $1
--------------------------------------------------------------

This is my output in the sql window.
--------------------------------------------------------------
JAVA_HOME=/jdk142_10
APP_PATH=/tmp
CLASSPATH=:/tmp/log4j.jar:/tmp/JavaProjct.jar
Filename=

PL/SQL procedure successfully completed.

--------------------------------------------------------------
Some how the java is not executed. Also the test.msg parameter is not passed to the script. I am able to run the script from unix command line and it works perfectly fine.

I am not sure what mistake I am doing. Please help
Tom Kyte
June 02, 2008 - 2:34 pm UTC


exec rc('sh -c "/tmp/utility.sh /tmp/test.msg"');
         ^^^^^^ that is BAD very very BAD do not do that!!!!!


why? because next, I'll just


exec rc('sh -c rm -rf *')

you have given the owner of RC carte blanche on your server.

Still java is not executed

Raj Thangaraj, June 02, 2008 - 4:14 pm UTC

I removed the sh from the proc call.

exec rc('/tmp/utility.sh /tmp/test.msg');

Seeing parameter, but still the java is not getting executed

This is the output
----------------------------------------------
JAVA_HOME=/jdk142_10
APP_PATH=/tmp
CLASSPATH=:/tmp/log4j.jar:/tmp/JavaProject.jar
Filename=/tmp/test.msg

PL/SQL procedure successfully completed.
----------------------------------------------
Tom Kyte
June 02, 2008 - 5:18 pm UTC

continue debugging....

come on.... you have this:


-------------------------------------------------------
${JAVA_HOME}/bin/java -version

${JAVA_HOME}/bin/java -classpath ${CLASSPATH} -Dlog4j.configuration=file:./OracleUtility_log4j.xml
com.javautility ./MQ_dev.properties $1
-------------------------------------------------------


and it is not running, what might be the first thing you'd think to try to debug this, maybe adding:

ls -lag ${JAVA_HOME}/bin/java
which ${JAVA_HOME}/bin/java

let's see if we can "see" the file (think permissions, you know that script - it isn't running as "you" here.

I can see the file

Raj Thangaraj, June 03, 2008 - 9:17 am UTC

I can see the file. Looks like I have all the permissions.
-----------------------------------------------------------------------
JAVA_HOME=/jdk142_10
APP_PATH=/tmp
CLASSPATH=:/tmp/log4j.jar:/tmp/JavaP
roject.jar
Filename=/tmp/test.msg
-r-xr-xr-x 1 mqm 138936 Jan 17 2006 /jdk142_10/bin/java
-----------------------------------------------------------------------
Tom Kyte
June 03, 2008 - 12:06 pm UTC

did you do a which on it.

and what does this "java do"

and if this java fails does it write to stdout or stderr

so maybe you need to redirect the output of the java program (both stdout and stderr) and then cat that file

for I only retrieve by design stdout.... (you are free to change that of course, you have all of the code...)

I think I figured

Raj Thangaraj, June 03, 2008 - 9:46 am UTC

Looks like, I cannot call the java execution from the java. I am doing something like
From Java, call Unix shell script
From Shell script, call java again

I tried to run the script using one of my local run command java programs and got back the same result. Looks like I have to do something else(using C may be).

Thanks a lot for your helping this dumbo!!
Tom Kyte
June 03, 2008 - 12:09 pm UTC

please, that doesn't even begin to make sense.

of course you can execute a program. Java is just a program.

a java stored procedure runs a script.
that script runs programs (you've already shown that it can)
java is just another program - it is not MAGIC, it is not SPECIAL, it just be a program

and one that is probably spewing forth information on stderr which you are not seeing.


so, use redirection to redirect the stdout and sdterr to a file (say /tmp/$$$.java.out) and either cat that file or read it after you are done

Java Mismatch

Raj Thangaraj, June 06, 2008 - 1:45 pm UTC

Oracle is using Java 1.3. But I have Java 1.4 installed in the box and using it(I cannot use Java 1.3). Would that be the difference

This is my call
-----------------------------
exec rc('/tmp/Utility.sh /tmp/test.msg > /tmp/cat.out');
-----------------------------

This is my Utility.sh script
------------------------------------------------
#!/usr/bin/sh

export JAVA_HOME=/jdk142_10
export APP_PATH=/tmp

export CLASSPATH=${CLASSPATH}:${APP_PATH}/log4j.jar
export CLASSPATH=${CLASSPATH}:${APP_PATH}/JavaProjct.jar

echo JAVA_HOME=${JAVA_HOME}
echo APP_PATH=${APP_PATH}
echo CLASSPATH=${CLASSPATH}
echo Filename=${1}

ls -lag ${JAVA_HOME}/bin/java

${JAVA_HOME}/bin/java -version > ${APP_PATH}/cat1.out

${JAVA_HOME}/bin/java -classpath ${CLASSPATH} -Dlog4j.configuration=file:${APP_PATH}/Utility_log4j.xml com.gm.gsip.utility.OraclePutJMSMQMessage ${APP_PATH}/MQ_dev.properties $1 > ${APP_PATH}/cat2.out
----------------------------------------

When I run it, cat1.out & cat2.out is empty. I don''t see a file cat.out

What am I doing wrong?

Stewart Bryson, June 07, 2008 - 11:28 pm UTC

The JVM seems to want unlimited permissions.

SQL> select * from v$version;

BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.3.0 - 64bi
PL/SQL Release 10.2.0.3.0 - Production
CORE 10.2.0.3.0 Production
TNS for Linux: Version 10.2.0.3.0 - Production
NLSRTL Version 10.2.0.3.0 - Production

5 rows selected.

Elapsed: 00:00:00.21
SQL> 

SQL> EXEC dbms_java.grant_permission('RT_TEST','java.io.FilePermission','/bin/ls','execute');

PL/SQL procedure successfully completed.

Elapsed: 00:00:04.12
SQL> 
Output from buffer 'qwer2.sql':
SQL> EXEC dbms_java.grant_permission('RT_TEST','java.lang.RuntimePermission','*','writeFileDescriptor' );

PL/SQL procedure successfully completed.

Elapsed: 00:00:01.98
SQL> 
Output from buffer 'qwer2.sql':
SQL> connect rt_test/rt_test@dtdinc1
Connected.
SQL> 
SQL> 
SQL> 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      public static int RunThis(String args)
 10      {
 11      Runtime rt = Runtime.getRuntime();
 12      int        rc = -1;
 13  
 14      try
 15      {
 16         Process p = rt.exec(args);
 17  
 18         int bufSize = 4096;
 19         BufferedInputStream bis =
 20          new BufferedInputStream(p.getInputStream(), bufSize);
 21         int len;
 22         byte buffer[] = new byte[bufSize];
 23  
 24         // Echo back what the program spit out
 25         while ((len = bis.read(buffer, 0, bufSize)) != -1)
 26            System.out.write(buffer, 0, len);
 27  
 28         rc = p.waitFor();
 29      }
 30      catch (Exception e)
 31      {
 32         e.printStackTrace();
 33         rc = -1;
 34      }
 35      finally
 36      {
 37         return rc;
 38      }
 39      }
 40    }
 41    /

Java created.

Elapsed: 00:00:02.54
SQL> 
SQL> 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.

Elapsed: 00:00:00.42
SQL> 
SQL> create or replace procedure RC(p_cmd in varchar2)
  2    as
  3      x number;
  4    begin
  5      x := run_cmd(p_cmd);
  6    end;
  7    /

Procedure created.

Elapsed: 00:00:00.17
SQL> 
SQL> exec rc('ls -l');

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.34
SQL> exec dbms_java.set_output(1000000);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.21
SQL> exec rc('ls -l');
java.security.AccessControlException: the Permission (java.io.FilePermission <<ALL FILES>> execute) has not been granted to RT_TEST. The PL/SQL to grant this is dbms_java.grant_permission( 'RT_TEST', 'SYS:java.io.FilePermission', '<<ALL FILES>>', 'execute
' )
 at java.security.AccessControlContext.checkPermission(AccessControlContext.java)
 at java.security.AccessController.checkPermission(AccessController.java)
 at java.lang.SecurityManager.checkPermission(SecurityManager.java)
 at oracle.aurora.rdbms.SecurityManagerImpl.checkPermission(SecurityManagerImpl.java)
 at java.lang.SecurityManager.checkExec(SecurityManager.java)
 at java.lang.Runtime.exec(Runtime.java)
 at java.lang.Runtime.exec(Runtime.java)
 at java.lang.Runtime.exec(Runtime.java)
 at java.lang.Runtime.exec(Runtime.java)
 at Util.RunThis(Util:13)

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.15
SQL>

think I solved it

Stewart Bryson, June 08, 2008 - 6:43 pm UTC

Copying the "ls" program to another directory and then calling that executable did the trick. I guess Java needs some permissions on the holding directory for execution that is not required normally at the command line.

Thanks.

Still can't figure out

Raj Thangaraj, June 11, 2008 - 9:27 am UTC

I am still not able to call the "Java" from the procedure. Oracle is using Java 1.3. But I have Java 1.4 installed in the box and using it(I cannot use Java 1.3). I even changed my java home to use the oracle's jdk

This is my call
-----------------------------
exec rc('/tmp/Utility.sh /tmp/test.msg');
-----------------------------

This is my Utility.sh script
------------------------------------------------
#!/usr/bin/sh

export JAVA_HOME=/jdk142_10
export APP_PATH=/tmp

echo JAVA_HOME=${JAVA_HOME}
echo APP_PATH=${APP_PATH}
echo CLASSPATH=${CLASSPATH}
echo Filename=${1}

ls -lag ${JAVA_HOME}/bin/java

${JAVA_HOME}/bin/java -version > ${APP_PATH}/cat1.out

ls -lag ${JAVA_HOME}/bin/java

----------------------------------------

When I run it, this is my output
----------------------------------------
JAVA_HOME=/u01/app/oracle/product/9.2.0.1/jdk
APP_PATH=/tmp
CLASSPATH=
Filename=/tmp/test.msg

lrwxr-xr-x 1 dba 13 Sep 26 2005 /u01/app/oracle/product/9.2.0.1/jdk/bin/java -> .java_wrapper

lrwxr-xr-x 1 dba 13 Sep 26 2005 /u01/app/oracle/product/9.2.0.1/jdk/bin/java -> .java_wrapper
----------------------------------------

I dont see the output of the command
${JAVA_HOME}/bin/java -version > ${APP_PATH}/cat1.out

cat1.out is empty too. Please help
Tom Kyte
June 11, 2008 - 9:53 am UTC

I've tried to tell you....


you are capturing STDOUT

you want to see STDERR

please - just from the command line you can see this:

sh-3.00$ java -version > /tmp/x
java version "1.4.2_08"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_08-b03)
Java HotSpot(TM) Client VM (build 1.4.2_08-b03, mixed mode)
sh-3.00$ cat /tmp/x
sh-3.00$ java -version >& /tmp/x
sh-3.00$ cat /tmp/x

java version "1.4.2_08"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2_08-b03)
Java HotSpot(TM) Client VM (build 1.4.2_08-b03, mixed mode)
sh-3.00$


do you see how the first redirect - did not redirect - the output was just there on screen, /tmp/x is empty - because java writes to stderr!

see how the second redirect, using the syntax for sh - >& - captured stderr (and standard out) to /tmp/x


Simple command call

Raj Thangaraj, June 11, 2008 - 9:45 am UTC

OK. Here I am not calling the script, but calling the java program. Nothing is showing up

exec rc('/usr/bin/ls -lag /bea/jdk142_10/bin/java')
-------------output-------------------------------------------
-r-xr-xr-x 1 mqm 138936 Jan 17 2006 /bea/jdk142_10/bin/java

PL/SQL procedure successfully ompleted.
-----------------------------------------------------------------

exec rc('/bea/jdk142_10/bin/java -version')
------------------output--------------------------------------
PL/SQL procedure successfully completed.
-----------------------------------------------------------------

I even did this to redirect the output to the file. But this file is not created
exec rc('/bea/jdk142_10/bin/java -version > /tmp/cat4.out')
------------------output--------------------------------------
PL/SQL procedure successfully completed.
-----------------------------------------------------------------

Tom Kyte
June 11, 2008 - 9:54 am UTC

sigh..... read above

and stop using > in the rc call, we've been over and over and over that. >, &, etc are SHELL things, you are running a program, programs do not understand ">"

From command prompt

Raj Thangaraj, June 17, 2008 - 12:33 pm UTC

From Command Line if i do

usahs245:bea /tmp//jdk142_10/bin/java -version >& /cat.out

I am getting this error:

ksh: /tmp/cat.out: bad file unit number
Tom Kyte
June 17, 2008 - 2:56 pm UTC

please look up the right commands and syntax for your OS then. Come on, you are using this OS - this is all about interfacing with the shell on your OS, this is pretty basic stuff (redirection, it is what unix is built on - pipes and redirection)

make sure you are using the same interactive shell as you are using in the script in the background...

From Command Prompt

Murali Hatwar, June 24, 2008 - 1:01 pm UTC

All,
Please remember that Runtime.exec() is not a command interpreter.
If you try doing redirection then you will have to handle it from within the javacode using threads for the streams.
It is better if you can put the commands which you run in a .sh or .bat file depending upon your OS and run that when needed instead of running the redirecting commands as a argument to the exec method.

Tom Kyte
June 24, 2008 - 1:19 pm UTC

yeah, that is what I've been saying over and over...

use redirection to get whatever you want to appear on stdout, and then the little java routine does the rest.

Java source

Nantha, December 02, 2008 - 4:36 pm UTC

Hi Tom,

We have some java code in the database and I would like to view the java source for a particular one (ex EmpManager.java).
Could you please let me know how we can extract that from database?

Thanks,
Nantha
Tom Kyte
December 09, 2008 - 9:56 am UTC

it depends...

was the *source code* ever LOADED? Most of the time, people load compiled byte code - not the source.

So, was the source loaded?


ops$tkyte%ORA10GR2> select text from user_source where name = 'Util' order by line;

TEXT
-------------------------------------------------------------------------------
import java.io.*;
import java.lang.*;

public class Util extends Object
{
  public static int RunThis(String args)
  {
  Runtime rt = Runtime.getRuntime();
  int        rc = -1;

  try
  {
     Process p = rt.exec(args);

     int bufSize = 4096;
     BufferedInputStream bis =
      new BufferedInputStream(p.getInputStream(), bufSize);
     int len;
     byte buffer[] = new byte[bufSize];

     // Echo back what the program spit out
     while ((len = bis.read(buffer, 0, bufSize)) != -1)
        System.out.write(buffer, 0, len);

     rc = p.waitFor();
  }
  catch (Exception e)
  {
     e.printStackTrace();
     rc = -1;
  }
  finally
  {
     return rc;
  }
  }
}

37 rows selected.



if you just loaded byte code, we won't have the source of course.

Is this will work with Windows 2000 OS

Gopinath, January 28, 2009 - 8:58 am UTC

Is this will work with windows 2000 OS?
I had tried it.it is creating the Process but it is not actualy runing the exe.
Please help to solve this.


Tom Kyte
January 28, 2009 - 3:44 pm UTC

how do you know it is not?
and the .exe is not a GUI program correct?

eg: GIVE A LOT MORE DETAIL

yes, this works, even on windoze

More details about what i did

Gopinath, January 28, 2009 - 11:49 pm UTC

I had created the java class as follows




CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED MM_ADMIN."MyCommandgi" as
import java.io.*;
import java.lang.*;
import oracle.sql.*;
import java.sql.*;
import java.util.*;
public class MyCommandgi
{
public static oracle.sql.CHAR RunThisgi(String args)throws SQLException
{
Runtime rt = Runtime.getRuntime();
String rc = "ok";
String line;
try
{
String[] finalCommand;
finalCommand = new String[1];
finalCommand[0] = args;
final Process pr = Runtime.getRuntime().exec(finalCommand);
BufferedReader input =new BufferedReader(new InputStreamReader(pr.getInputStream()));
input.close();
}
catch (Exception e)
{
e.printStackTrace();
rc = "IO Exception "+e;
return new oracle.sql.CHAR(rc,null);
}
//finally
{
return new oracle.sql.CHAR(rc,null);
}
}
}
/

Then i had created the function
as follows
CREATE OR REPLACE FUNCTION MM_ADMIN.f_cmd2 (p_command IN VARCHAR2)
return VARCHAR2
AS LANGUAGE JAVA
NAME 'MyCommandgi.RunThisgi(java.lang.String) return oracle.sql.CHAR';
/


finally my calling procedure is

DECLARE
L_MSG VARCHAR2(1000);
BEGIN
L_MSG:=F_CMD2('C:\Program Files\Microsoft Office\Office\excel.exe');
DBMS_OUTPUT.PUT_LINE(L_MSG);
END;
/

this is creating a process in windows but it is not actually opening the excel application

i had give all the java file permission required.

Please help me to open any exe through,oracle procedure.




Tom Kyte
January 30, 2009 - 1:58 pm UTC

ok, please think about this.

Where will excel "appear" exactly? It has nowhere to "appear", you cannot possibly even consider running a GUI application, it would appear on the database servers 'console' - a thing that doesn't really exist! The server is running as a service, it has no screen.

qustion

mohannad, February 03, 2009 - 6:46 am UTC

Dear Tom,
it was very usefull for me to implent this feature, i followed the steps you mentioned above. it was ok for simple cmd comand like md temp, the folder was created. i neeed to run a program, when i run this comand from cmd its working:
adbulkexport.exe /users /path:cn=users,dc=smsglab,dc=com /samaccountname /userprincipalname /password /givenname /sn /file:c:\mkh.csv
so i but it i batch file and i called this batch file from the procedure rc, its not working. do you have any idea why??
thanks.
Tom Kyte
February 03, 2009 - 10:29 am UTC

read this page again - we've addressed this multiple times.


http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:952229840241#29824294728739

http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:952229840241#12438781580891

likely reasons:

a) path is not what you think
b) environment is not what you think



You might want to use dbms_scheduler as a 'better' way to run a bat/cmd file, it is setup to do that.

JAccelerator in relation to Java?

Stuart, February 10, 2009 - 3:42 pm UTC

Hi Tom,

I installed a new application into a fresh 10.2.0.4 database (front end=MS Server 2003), and noticed shortly afterward that DB Console was displaying an info message in the policy violations recommending I install JAccelerator (NCOMP).

There doesn't seem to be any Java stored procedures in our DB apart from Oracle-related ones.

WTS: SYS AS SYSDBA> select owner, object_type, count(*)
     from all_objects
     where object_type like '%JAVA%'
     group by owner, object_type;

OWNER                          OBJECT_TYPE           COUNT(*)
------------------------------ ------------------- ----------
EXFSYS                         JAVA RESOURCE                1
ORDSYS                         JAVA CLASS                1389
MDSYS                          JAVA CLASS                 273
MDSYS                          JAVA RESOURCE                4
EXFSYS                         JAVA CLASS                  41
SYS                            JAVA DATA                  298
SYS                            JAVA CLASS               14747
SYS                            JAVA RESOURCE              704
ORDSYS                         JAVA RESOURCE               66

9 rows selected.

In fact, the application schema doesn't have much in the way of stored procedures...

WTS: SYS AS SYSDBA> select object_type, count(*)
     from all_objects
     where owner = 'WTS'
     group by object_type;

OBJECT_TYPE           COUNT(*)
------------------- ----------
SEQUENCE                    85
PROCEDURE                    3
PACKAGE                      1
PACKAGE BODY                 1
TRIGGER                     84
VIEW                       518
TABLE                      212
INDEX                      272

8 rows selected.

Questions:
1. I had a quick look at Metalink (Note 452024.1), where it says the NComp utility is to native compile Java code.  Does this mean DB Console is just wanting me to install this for the sake of the system-related Java procedures/packages? 

2. Metalink Note 134985.1 has info on how to use NComp, but it makes references to 8i (although the modified date is Sep 2008).  Is the NComp utility pretty much the same through 9i-11g?

3. Would using NComp to compile java natively result in less memory requirements (i.e. my java_ parameters being set lower), as opposed to not using NComp?

finally clause cannot complete normally

Jim Cox, June 01, 2009 - 3:11 pm UTC

Hi Tom

I have been using the code you supplied for "Util" and I am not sure if this just happened since I went from 9i to 10g, but even though the code compiles with no errors

when i check dba_errors:

TYPE SEQUENCE TEXT ATTRIBUTE MESSAGE_NUMBER
------------ ---------- ------------------------------------------------------------ --------- --------------
JAVA SOURCE 1 Util:35: warning: finally clause cannot complete normally ERROR 0
JAVA SOURCE 2 } ERROR 0
JAVA SOURCE 3 ^ ERROR 0
JAVA SOURCE 4 1 warning ERROR 0


when i check dba_objects:


Owner Object Type Object Name Status Created
------------ ------------------ ------------------------------------ ---------- ---------
LLPROD JAVA CLASS Util VALID 14-FEB-09
LLPROD JAVA SOURCE Util VALID 14-FEB-09

2 rows selected.

any idea if i should be concerned about this warning ?

Thanks For Your Time

Tom Kyte
June 01, 2009 - 8:22 pm UTC

how about you either very very very explicitly point to the code in question or post it?

this is a very large page.

Util Code

Jim Cox, June 02, 2009 - 12:33 pm UTC

Sorry Tom

here is the code i was referring to

create or replace and compile
java source named "Util"
as
import java.io.*;
import java.lang.*;

public class Util extends Object
{
public static int RunThis(String args)
{
Runtime rt = Runtime.getRuntime();
int rc = -1;

try
{
Process p = rt.exec(args);

int bufSize = 4096;
BufferedInputStream bis =
new BufferedInputStream(p.getInputStream(), bufSize);
int len;
byte buffer[] = new byte[bufSize];

// Echo back what the program spit out
while ((len = bis.read(buffer, 0, bufSize)) != -1)
System.out.write(buffer, 0, len);

rc = p.waitFor();
}
catch (Exception e)
{
e.printStackTrace();
rc = -1;
}
finally
{
return rc;
}
}
}
/

Thanks Again
Tom Kyte
June 02, 2009 - 6:45 pm UTC

Thanks For The Info

Jim Cox, June 05, 2009 - 1:46 pm UTC

just a thank you

Error in executing

Ahmed, June 08, 2009 - 10:24 am UTC

Dear Tom. 
After I did steps you mentioned to execute ps command through PL I face the following message

SQL> exec :x := RUN_CMD('/usr/ucb/ps -ef');
java.lang.ArrayIndexOutOfBoundsException
        at Util.RunThis(Util:11)

PL/SQL procedure successfully completed.

I use 10.2 database & Redhat AS 3

Tom Kyte
June 08, 2009 - 1:36 pm UTC

and when you ctl-f'ed for

ArrayIndexOutOfBoundsException


on this very page.... what did you see?

Executing of exec rc('/usr/bin/ps')

Ahmed, June 09, 2009 - 1:51 am UTC

Dear Tom

Command is not executed in the background

Thanks
Tom Kyte
June 09, 2009 - 10:22 am UTC

of course it isn't, it is obviously run in the foreground, what use would it be to run it in the background - it simply produces output and doesn't do anything (doesn't change anything). So, if you ran it in the background - the output would be produced and immediate "disappeared" - what use could that be???

Good example

A, July 29, 2009 - 10:52 am UTC

Hello Tom,
Take your example, I tried exporting for 2 tables

exec rc('/dboracle/admin/oracle/product/9.2.8/bin/exp my_user/my_user indexes=n statistics=none tables='||'''TABLE1,TABLE2''' || ' file='||'''/dboracle/admin/oracle/data_dump.dmp''' || ' log='||'''/dboracle/admin/oracle/data_log.log''');

but Im getting the error

Connected to: Oracle9i Enterprise Edition Release 9.2.0.8.0 - 64bit Production
With the Partitioning, OLAP and Oracle Data Mining options
JServer Release 9.2.0.8.0 - Production
Export done in US7ASCII character set and AL16UTF16 NCHAR character set
Note: indexes on tables will not be exported

About to export specified tables via Conventional Path ...
EXP-00011: MY_USER.TABLE1, TABLE2 does not exist
Export terminated successfully with warnings.

Specifying one table is working.

exec rc('/dboracle/admin/oracle/product/9.2.8/bin/exp my_user/my_user indexes=n statistics=none tables='||'''TABLE1''' || ' file='||'''/dboracle/admin/oracle/data_dump.dmp''' || ' log='||'''/dboracle/admin/oracle/data_log.log''');

Also is there any way I can show the output of export command on sqlprompt ?

Tom Kyte
August 03, 2009 - 2:12 pm UTC

export writes to stdout and stderr, you would have to modify the code to redirect both (eg: find a java programmer or read up enough to figure out how to do that)


Good example

A, July 29, 2009 - 10:58 am UTC

Hello Tom,
Instead of "Take your example" it should be read as "Taking your example" in the above question.

Thanks

shell script execution issue

Thanks Tom!, September 01, 2009 - 7:05 pm UTC

Hello Tom,
I am invoking your script from our application (on a different tier) and it works well when I give echo, touch, mv, chmod etc., but when I try to put these in a shell script it does not work. I do have a #!/bin/sh in the script. Any help would be appreciated.
Thanks!
Tom Kyte
September 02, 2009 - 10:15 am UTC

fully qualify things.

where is your 'touch', what is your path in your environment (your shelled out environment, not YOUR command line, the command line Oracle has).


do a 'which touch' on your system first

and then fully qualify it, eg, on my linux machine I would code


/bin/touch



shell script execution issue

Thanks Tom!, September 02, 2009 - 2:33 pm UTC

Thanks for the hint! It was not an issue with the script at all and with the way I was handling the shell command. Doing as you suggested helped. Thanks again.

java store procedures can't use sun.jdbc.odbc.JdbcOdbcDriver

Kato, January 12, 2010 - 12:57 pm UTC

Java store procedures can't use sun.jdbc.odbc.JdbcOdbcDriver

This is my java class:

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "Trans"
AS import java.io.*;
import java.lang.*;
import java.sql.*;
import oracle.jdbc.driver.*;
import java.util.*;
import oracle.sql.*;


public class Trans extends Object
{

public static String Transfer (String str)
{
System.out.println("BD DSN-ODBC Connection");
try
{
System.out.println("Driver JDBC ODBC");
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
}
catch (ClassNotFoundException e)
{
System.err.println (e) ;
System.exit (-1) ;
}
.....
connDSN = DriverManager.getConnection(dbUrl, cUser, cPassword);

.....
}
}
/

And this is the error:

ORA-29515: exit called from Java code with status 4294967295

java.lang.ClassNotFoundException: sun/jdbc/odbc/JdbcOdbcDriver

What is necesary to use sun.jdbc.odbc.JdbcOdbcDriver and create ODBC connections?

Thanks.

Kato
Tom Kyte
January 18, 2010 - 3:44 pm UTC

it would need to be loaded into the database, which will work if and only if the jdbc/odbc driver is "pure java"

however, that said, if you have an odbc data source, why wouldn't you just use a database link and query it - you don't need to approach java in any way shape or form here, it would be the hard way to do it.

OS command not running correctly from the procedure

Jay, January 22, 2010 - 7:03 pm UTC

Hi Tom,

I have used your suggestion to create the function as follows.

As sys user, provided the permission to 
begin
dbms_java.grant_permission('WATER','java.io.FilePermission','C:\Program Files\ArcGIS\ArcSDE\ora11gexe\bin\sdetable','execute');
dbms_java.grant_permission('WATER','java.lang.RuntimePermission','*','writeFileDescriptor');
end;
/

As user WATER, successfully created the java source.

create or replace and compile
  java source named "Util"
  as
  import java.io.*;
  import java.lang.*;
  
  public class Util extends Object
  {
    public static int RunThis(String args)
    {
    Runtime rt = Runtime.getRuntime();
    int        rc = -1;
  
    try
    {
       Process p = rt.exec(args);
  
       int bufSize = 4096;
       BufferedInputStream bis =
        new BufferedInputStream(p.getInputStream(), bufSize);
       int len;
       byte buffer[] = new byte[bufSize];
  
       // Echo back what the program spit out
       while ((len = bis.read(buffer, 0, bufSize)) != -1)
          System.out.write(buffer, 0, len);
  
       rc = p.waitFor();
    }
    catch (Exception e)
    {
       e.printStackTrace();
       rc = -1;
    }
    finally
    {
       return rc;
    }
    }
  }
/

Then created the function.

create or replace function RUN_CMD(p_cmd in varchar2) return number as language java name 'Util.RunThis(java.lang.String) return integer';

Created a procedure to run the sdetable command.

set serveroutput on

CREATE OR REPLACE PROCEDURE runcmd(fcname_cap varchar2)
AS
   
   sql_stmt22      VARCHAR2 (900);
   
BEGIN
   
   DBMS_OUTPUT.ENABLE (10000000);

sql_stmt22 := 'select RUN_CMD(''sdetable -o alter_reg -V SINGLE -t '||fcname_cap||' -i sde:oracle11g -u trwater -p WATER@gis -N'') from dual';

execute immediate sql_stmt22; 
COMMIT;
END runcmd;
/
-----
When I execute the procedure, I get the following.

SQL> exec runcmd('wnetworkvalve')
select RUN_CMD('sdetable -o alter_reg -V SINGLE -t wnetworkvalve -i
sde:oracle11g -u trwater -p TRWATER@nytrgist -N') from dual

PL/SQL procedure successfully completed.

However, it does not execute the procedure.
I have tried using the following sql statement and it works perfectly.

SQL> select RUN_CMD('sdetable -o alter_reg -V SINGLE -t WNETWORKVALVE -i sde:oracle11g -u trwater -p
 TRWATER@nytrgist -N') from dual;

RUN_CMD('SDETABLE-OALTER_REG-VSINGLE-TWNETWORKVALVE-ISDE:ORACLE11G-UTRWATER-PTRW
--------------------------------------------------------------------------------
                                                                               0

ArcSDE 9.3  for Oracle11g Build 546 Thu Sep 18 12:35:50  2008
Attribute        Administration Utility
-----------------------------------------------------
Table WNETWORKVALVE's registration successfully altered.

Can you please tell me why doesn;t it work, when I run the procedure using the RUN_CMD function?

Thanks,
Jay



Tom Kyte
January 25, 2010 - 5:54 am UTC

because you 'execute' the statement, but never 'fetch' it. You didn't actually run it.

...
sql_stmt22 := 'select RUN_CMD(''sdetable -o alter_reg -V SINGLE -t
'||fcname_cap||' -i sde:oracle11g -u trwater -p WATER@gis -N'') from dual';

execute immediate sql_stmt22;

....

that should just be:

is
n number;
begin
n := run_cmd( 'sdetable .... ' || fcname_cap || ' -i ......' );
end;


No dynamic SQL necessary nor desired.

and definitely, absolutely NO COMMIT - that commit is worse that useless, it is quite harmful (and WRONG)

Ignore the username, password and database name in my last post

Jay, January 22, 2010 - 7:47 pm UTC

In my last post, there is a discrepancy of username, password and database contained in the procedure and the sql statement executed at the end. There is a typo and the username, password and db name is actually same.


Olga, January 26, 2010 - 10:31 am UTC

Tom, I have been trying this solution in 11.1.0.6.0, but unfortunatelly I am getting "ORA-03113: end-of-file on communication channel" error when executing " exec rc('/bin/df -k');". The same solution works in 10.2.4.0. Do you know of any issues with 11g?
Tom Kyte
January 29, 2010 - 2:40 pm UTC

Please utilize support for that, most likely a networking configuration issue (3113 many times is). No issues that I'm aware of.

pricedure doesn't work

Mauricio Rossetto, March 01, 2010 - 2:52 pm UTC

Hi Tom,

I'm trying to run a simple OS command, but it doesn't work.

This is my step to step:

1) java source compiled:
create or replace and compile java source named util as
import java.io.*;
import java.lang.*;

public class Util extends Object
{
  public static int RunThis(String args)
  {
  Runtime rt = Runtime.getRuntime();
  int        rc = -1;

  try
  {
     Process p = rt.exec(args);

     int bufSize = 4096;
     BufferedInputStream bis =
      new BufferedInputStream(p.getInputStream(), bufSize);
     int len;
     byte buffer[] = new byte[bufSize];

     // Echo back what the program spit out
     while ((len = bis.read(buffer, 0, bufSize)) != -1) 
       System.out.write(buffer, 0, len);
    
     rc = p.waitFor();
  }
  catch (Exception e)
  {
     e.printStackTrace();
     rc = -1;
  }
  finally
  {
     return rc;
  }
  }
}
/

2) function compiled: 
create or replace function RUN_CMD(p_cmd in varchar2) return number
as
language java
name 'Util.RunThis(java.lang.String) return integer';
/

3) procedure compiled:
create or replace procedure RC(p_cmd in varchar2)
as
  x number;
begin
  x := run_cmd(p_cmd);
end;
/

when I run for example:
SQL> exec rc('ls -la /home/oracle');

PL/SQL procedure successfully completed

The procedure is completed, but it not shows the output.

What do I need to the procedure shows the output?

Thanks

Tom Kyte
March 02, 2010 - 7:10 am UTC

maybe

rt_test@DEV816> set serveroutput on size 1000000
rt_test@DEV816> exec dbms_java.set_output(1000000)


as above??


ops$tkyte%ORA10GR2> set serveroutput on size 1000000
ops$tkyte%ORA10GR2> exec dbms_java.set_output(1000000)

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> exec rc('ls -la /tmp');
total 12704
drwxrwxrwt  61 root     root          12288 Mar  2 08:10 .
drwxr-xr-x  30 root     root           4096 Mar  1 07:41 ..
drwxrwxrwt   2 root     root           4096 Mar  1 07:42 .font-unix
drwx------   3 tkyte    tkyte          4096 Mar  1 07:42 gconfd-tkyte

procedure doesn't work part 2

Mauricio Rossetto, March 02, 2010 - 11:00 am UTC

Thanks for your help;

I have called the function as: call dbms_java.set_output(1000000);

But, it should be executed as: exec dbms_java.set_output(1000000)

So, I have another doubt:

I'm trying to call a shell script, but it doens't work fine.

Steps:
SQL> exec rc('/home/oracle/insert_tmp3.sh');

PL/SQL procedure successfully completed

The insert_tmp3.sh file has the following code:
#!/bin/bash
ls -la /home/oracle

So, my question is: Should it shows the output?

Thanks again

Tom Kyte
March 02, 2010 - 12:49 pm UTC

ctl-f and read about shell scripts and issues with them on this page, it is all here already.


differences between Oracle versions?

Franky, May 01, 2010 - 1:49 am UTC

Hello Tom,

I have just experienced, the following:

- whenever I call a java stored procedure with '/usr/bin/env' on 9.2.0.8 (SPARC Solaris 10) then I basically get the Unix oracle user profile,

- but if I do the same call on 10.2.0.4 (SPARC Solaris 10) then the output/result cannot be associated with the user's profile, since a lot of extra variables are there, but for example the PATH is empty.

Do you know the reason behind this? Is there a way to force 10g to use the variables defined in the user's profile whenever a java call is spawned on the OS level?

Thanks!

Tom Kyte
May 06, 2010 - 10:34 am UTC

No, there never was - it didn't really change between 9 and 10, what changed was the way you connected.

Say you connect using:

sqlplus scott/tiger

No tns entry, no network. The what happens is your dedicated server is created (forked()) by your SQLPLUS process. the environment of your dedicated server is INHERITED from your sqlplus process. The environment your dedicated server (and hence a java stored procedure) sees is based on the "end users" environment.


Now, suppose (same database!!) you use:

sqlplus scott/tiger@database

You use the network and further assume this connect is made using DEDICATED server again. The environment your dedicated server gets this time COMES FROM THE LISTENER. Not from you - from the listener. Because the listener forks the dedicated server.


Now, support (same database!!! same listener!!!!!) you use:

sqlplus scott/tiger@database_using_shared_server

You connect to the same database, same listener - but use shared server. now your server process gets it's environment NOT FROM YOU, NOT FROM THE LISTENER but from the database software account, since it is forked by the DATABASE instance.


Same database, same software - at least THREE environments possible...

which leads me to the point:


never ever rely on defaults. Your script should explicitly set the EXACT path it needs every single time and further, it should NOT rely on the path for finding programs to execute, it should explicitly call them out - fully qualified - every time, to avoid confusion and to avoid trojan horse programs.

Every single time.

interesting...

Franky, May 10, 2010 - 3:57 pm UTC

Hello Tom,

I didn't mention that in my examples I was connected to dedicated severs via tns and the Oracle 10g environment is RAC. According to your words : this case the environment comes from the listener, but for some reason this does not apply here. Let's see the differences:

Oracle Unix user .profile (Oracle 9i environment)

oracle$ env | grep -w PATH
PATH=.:/usr/local/bin:/usr/ccs/bin:/usr/bin:/etc:/usr/openwin/bin:/home/oracle/OraHome9i/bin


Oracle 9i listener environment (Unix level):

oracle$ ps -ef | grep -v grep | grep LISTENER
  oracle 14076     1   0   Mar 08 ?          52:50 /home/oracle/OraHome9i/bin/tnslsnr LISTENER -inherit

oracle$ pargs -e 14076 | grep -w PATH
envp[2]: PATH=.:/usr/local/bin:/usr/ccs/bin:/usr/bin:/etc:/usr/openwin/bin:/home/oracle/OraHome9i/bin


Oracle 9i java process environment (Unix level) connected as user@tns from remote client:

select oscmd('/usr/bin/env') from dual; 

PATH -->   PATH=.:/usr/local/bin:/usr/ccs/bin:/usr/bin:/etc:/usr/openwin/bin:/home/oracle/OraHome9i/bin

Everything looks good in 9i, PATH variable contents are the same. Let's check 10g:

Oracle Unix user .profile (Oracle 10g environment)

oracle$ env | grep -w PATH
PATH=/u01/app/oracle/product/10.2.0/db_1/bin:/u01/app/oracle/product/10.2.0/db_1/OPatch:/usr/sbin:/usr/ccs/bin:/usr/bin:

Oracle 10g listener environment (Unix level):

oracle$ ps -ef | grep -v grep | grep LISTENER
  oracle 13524     1   0   Apr 30 ?           0:21 /u01/app/oracle/product/10.2.0/db_1/bin/tnslsnr LISTENER_TST-RAC1 -inherit

oracle$ pargs -e 13524 | grep -w PATH
envp[7]: PATH=/u01/app/oracle/product/10.2.0/db_1/bin:/usr/bin:/usr/sbin:/usr/bin


Oracle 10g java process environment (Unix level) connected as user@tns from remote client:

select oscmd('/usr/bin/env') from dual;

PATH is empty --> PATH=  

PATH is different in all cases. I'm still wondering how could this happen.

I've tried to log on as local user (first case on your list), but no luck -> PATH is empty there as well.

I agree, the best is to implement fully qualified access to the commands in the scripts. My only excuse is that I've inherited these environments with hundreds of shell and perl scripts at the beginning of the migration project...

Any thoughts?

Thanks!

Tom Kyte
May 10, 2010 - 7:19 pm UTC

The bottom line - the only thing *repeat: the ONLY THING* you need to take away from this is.....


Never rely on defaults
Do not rely on the path
Use explicit paths - be precise, specific
Set your own path if need be, but if you want to write secure code, you will not rely on the PATH ever - even if YOU set it.


You know that

a) the path can be different
b) the path will be different
c) that it is by design that this is "so"

so, there you go - the path is outside of your control, always has been, always will be.

You have some P1 bugs to fix.

...

Oracle 9i java process environment (Unix level) connected as user@tns from remote client:

.......

how did you arrive at that conclusion? That path looks a lot like the listeners path - doesn't it. It looks like the path the listener decided to let the child process inherit - a setting you do not have control over.

Runtime.getRuntime doesn't pass client NLS_LANG on SUN Solaris

Luiz Noronha, June 04, 2010 - 8:02 am UTC

Hi Tom,

I'm calling the following code as most DBAs here do and my profile sets the NLS_LANG to PORTUGUESE_BRAZIL.WE8ISO8859P1. 

When I execute it I pass the string:
 /ora10g/product/10.2.0/bin/sqlldr sati_loader/xxxx@SATPT1 control='/satwork_01/SATI_PRD/SATI_INTERFACENAOSAP/TXT/tmp/lfnfsc_mr20100514.ctl' log='/satwork_01/SATI_PRD/SATI_INTERFACENAOSAP/TXT/tmp/lfnfsc_mr20100514.log' bad='/satwork_01/SATI_PRD/SATI_INTERFACENAOSAP/TXT/lfnfsc_mr20100514.bad' errors=1000000

Everything goes fine except from the accentuation that goes all wrong to the tables. Santo André for instance is inserted as Santp Andr¿.

I'm presuming that the child process doesn't pass the client's canfiguration on.  

Would you help me?

Thanks you.

public class jOSExec extends Object
{
  public static int Run(String args) throws Exception
  { Runtime rt = Runtime.getRuntime();
    int     rc = -1;
    String strexec[] = new String[3];
    if (args == null) {
        System.err.println("Syntax error - Usage: Run <OS command>");
        rc = -1; }



    else {
        try {

            Process p = rt.exec(args);

            int bufSize = 4096;
            BufferedInputStream bis = new BufferedInputStream(p.getInputStream(), bufSize);
            int len;
            byte buffer[] = new byte[bufSize];

            // Echo back what the program spit out
            while ((len = bis.read(buffer, 0, bufSize)) != -1)
               System.out.write(buffer, 0, len);
               rc = p.waitFor();
           }
        catch (IOException e) {
            System.err.println("Command " + args + " not found");
            throw e;
            }

        catch (Exception e) {
            e.printStackTrace();
            System.err.println( e);
            throw e;
            }
            
            }

    return rc;
    }
}

Tom Kyte
June 09, 2010 - 7:18 am UTC

why not replace /ora10g/product/10.2.0/bin/sqlldr with /path/to/my/100%/assured/to/be/correct/as/far/as/environments/go/script

? Calling a binary directly is asking for trouble - you want to make sure the environment is 100% what you think it should be, could be, will be. You have no control over it any other way.



And bigger question for you - why isn't this just:

insert into my_table select * from external_table;


why are you using this legacy, 1990's approach? If you used just sql, you'd be able to catch and handle all errors, have less code, run faster, run safer (in fact I can only think of POSITIVE things here)

You should not be using sqlldr at all - use an external table. Even if you are loading into a remote database (not clear here), just use an external table and a database link. No more passwords passed around (you are as insecure as you can be, I can see your password if I can ps your system)

sudo with RHEL5 and 11g

C, September 28, 2010 - 5:09 am UTC

Hi Tom. I use a java stored procedure to call a shell script which collects various data files and burns the data to a CD so the customer can backup the necessary data easily.

The initial environment was Solaris 8 and 10g. When we moved to RHEL4, the scripts required some minor changes including the need to perform sudo to burn the CD (the java stored procedure would return an error when executing cdrecord as anyone other than root even though the script would run properly if called from a shell of the user--I chalked it up to a peculiarity of the system).

Now with a move to RHEL5 with 11g, sudo does not execute properly. I believe I have all the permissions correctly set for the JVM and filesystem. I modified the script to only perform another executable within the same directory:
/usr/bin/apropos cdrecord
echo $?

the command returns the proper results:
cdrecord (1) - record audio or data Compact Disks or Digital Versatile Disks from a master
cdrecord (rpm) - A command line CD/DVD recording program.
0

However, if I change the script to perform:
/usr/bin/sudo -l
echo $?

it returns only the following:
1

If I run the script in the user shell, it returns the proper response:
User xyz may run the following commands on this host:
(root) NOPASSWD: /usr/bin/cdrecord
0

The file permissions on the executables are standard:
---s--x--x 2 root root 150960 Apr 14 2009 /usr/bin/sudo
-rwxr-xr-x 1 root root 1786 Jul 13 2006 /usr/bin/apropos

Other executables such as ping (which has the sticky bit set as well) work as I expect. Is there something different about executing sudo within the script as apposed to other executables with RHEL5 and 11g? Any ideas why one executable will work and another will not? Am I missing something? Any help would be greatly appreciated.

Thank you.
-C
Tom Kyte
September 28, 2010 - 8:38 am UTC

... (the java stored procedure would return an error when executing cdrecord
as anyone other than root even though the script would run properly if called
from a shell of the user--I chalked it up to a peculiarity of the system). ...

you shouldn't - the script is running "as oracle" - it is likely the oracle software account (the account the database is running as) did not have the permissions necessary to burn. You should not use root, that is pretty "powerful"


The environment the script is in when you run it from the java stored procedure - it is in the environment of the server - not your user account.


I would start by having the script print out as much information about the environment as possible - id, env, etc - and replicating that environment and testing there (not just in any old user account)


get far far far away from sudo in this context and fix the original issue - the access to the cd.

sudo with RHEL5 and 11g

C, September 28, 2010 - 9:33 am UTC

Hello Tom. Thank you for the response. I'm sorry, I wasn't clear about the user. It is not any user on the system. The system configuration has the listener execute as a different OS user than oracle. I noticed in Solaris the script executed as oracle, whereas in Linux, it executes as the listener account. Actually upon further review, in Linux, whoami and id shows the listener account, but the USER and LOGNAME environment variables show oracle. Is there a way for the java stored procedure to execute as oracle (which would be shown by id)?

I will continue to try to replicate the exact same environment in a shell and the java stored procedure call.

Thank you very much.
-C
Tom Kyte
September 28, 2010 - 10:52 am UTC

You do not want the OS executable to execute as Oracle - what you have is *perfect* security wise - absolutely PERFECT.

Now, just get the user that runs the listener the minimal set of privileges necessary to do what you want - and then you are set.

do not use root.
do not get this to use the oracle OS account.
use a minimally priveleged OS account as you are - and give it just the smallest amount of rights to do what you need.

sql trace in java program

KG, March 04, 2011 - 10:35 am UTC

Hi Tom
Please let me know ,how to enable sql_Trace from java program?


Tom Kyte
March 04, 2011 - 11:34 am UTC

just execute this plsql block:

begin dbms_monitor.session_trace_enable( waits => true, binds => true ); end;



or use a statement to execute alter session ....

Doubt about java procedure

Sergio Coutinho, July 10, 2011 - 12:15 am UTC

Hi Tom,

Following the examples of this forum, I developed a java prodedure to remove files from an especific directory of the OS file system (Unix Solaris).

I assign permissions (dbms_java.grant_permission) to a specific directory that already had files. I could successfully remove some of these files.

However, I realized that new files added to the directory are not removed by the java procedure. No error occurs in executing the java procedure and I'm sure there is no OS file permission problem with the new file stored in the OS.

Could tell me what am I doing wrong? Did need - for example - to reassign permissions (ms_java. grant_permission) every time i add new files in this directory?

Best regards,

Sergio
Tom Kyte
July 12, 2011 - 7:15 am UTC

no example, nothing to see, therefore - no real comment.


Probably, the new files were created with a different default umask applied to them and the user the java stored procedure runs as isn't allowed to erase those files. Since we don't know what api you used to erase files, how you handled (or not) errors - we cannot comment.

If you code is more than 50 lines, it is too long, make your example TINY, SHORT, and reproducible. Tell us exactly what to do to reproduce your issue and make your code TINY TINY TINY (to erase a bunch of files in a directory should be tiny - don't need any real error handling or anything - just let all exceptions propagate up - that'll probably show you what the error is in the first place)

Java Error

A reader, July 15, 2011 - 6:02 pm UTC

Tom:

I want to test your java routine to run unix ZIP command for HTML files that get generated
using UTL_FILE (9i) and then download the zip file to user using PL/SQL

Do you know what is the issue here? Do i need to be a diff user to grant access to my own oracle acount.

tipsadmin@TIPS9i> begin
2 dbms_java.grant_permission
3 ('TIPSADMIN',
4 'java.io.FilePermission',
5 '/usr/bin/ls',
6 'execute');
7
8 dbms_java.grant_permission
9 ('TIPSADMIN',
10 'java.lang.RuntimePermission',
11 '*',
12 'writeFileDescriptor' );
13 end;
14 /
begin
*
ERROR at line 1:
ORA-29532: Java call terminated by uncaught Java exception:
java.lang.SecurityException: policy table update SYS:java.io.FilePermission, /usr/bin/ls
ORA-06512: at "SYS.DBMS_JAVA", line 0
ORA-06512: at line 2


Tom Kyte
July 18, 2011 - 10:16 am UTC

have your DBA run that, you are not privileged enough to make that grant.

java

A reader, July 18, 2011 - 10:54 am UTC

Tom:

ok, thanks but let me confirm something bfore I ask him.

Would the above statement exacly allows me to run the ZIP or any other unix command or do I need to change it somehow to specify the unix directory where I will need the ZIP command to run?

What oracle privs you need to run the above? I have another instance with DBA privs and still would not run.
Tom Kyte
July 18, 2011 - 11:32 am UTC

the above would let you run /usr/bin/ls

You are not granting anything on ZIP, you would need privileges for that too.

see:

http://docs.oracle.com/docs/cd/E11882_01/java.112/e10588/chten.htm

for security relating to java in the database.

DBMS_Scheduler Example

David Aldridge, July 28, 2011 - 3:07 am UTC

Here's a quick example of the sort of code that lets you use DBMS_Scheduler for executing external procedures.

BEGIN
dbms_scheduler.create_job(
job_name => 'ZIP_FILE_JOB',
job_type => 'EXECUTABLE' ,
job_action => '/usr/bin/zip',
number_of_arguments => 2 ,
start_date => NULL ,
repeat_interval => NULL ,
end_date => NULL ,
enabled => TRUE ,
auto_drop => FALSE,
comments => NULL);
END;
/


create or replace procedure zip_file(
zip_file_name varchar2,
source_file_name varchar2,
use_current_session boolean default true)
Is
Begin

dbms_scheduler.set_job_argument_value(
job_name => 'ZIP_FILE_JOB',
argument_position => 1,
argument_value => zip_file.zip_file_name);

dbms_scheduler.set_job_argument_value(
job_name => 'ZIP_FILE_JOB',
argument_position => 2,
argument_value => zip_file.source_file_name);

dbms_scheduler.run_job(
job_name => 'ZIP_FILE_JOB',
use_current_session => zip_file.use_current_session);

end zip_file;
/

java

sam, August 18, 2011 - 8:59 am UTC

Tom:

There is one database where the java stuff works fine.
Unfortunately that is not the database I need to run the ZIp from.

What grants does the oracle account need to run the O/S command using java? Is it

JAVAUSERPRIV
JAVASYSPRIV
JAVA_ADMIN
call dbms_java.gratn_permission
etc.

I was trying to find out from the database where everything works fine using
select * from user_role_privs;
select * from user_sys_privs

but I could find anything.


Tom Kyte
August 23, 2011 - 2:55 am UTC

ctl-f on this page for dbms_java.grant_permission

complete and full and working example is there with the minimum privileges you need

java

A reader, August 23, 2011 - 8:03 am UTC

<<have your DBA run that, you are not privileged enough to make that grant. >>


1) If DBA did a grant execute on DBMS_JAVA to SCOTT, would i be able to run all those commands myself?

or what ROLES or PRIVILEGE I need so i can run this myself as "SCOTT".

Would the role "JAVASYSPRIV" allow that.



begin
2 dbms_java.grant_permission
3 ('SCOTT',
4 'java.io.FilePermission',
5 '/usr/bin/zip',
6 'execute');
7
8 dbms_java.grant_permission
9 ('SCOTT',
10 'java.lang.RuntimePermission',
11 '*',
12 'writeFileDescriptor' );
13 end;
14 /
Tom Kyte
August 30, 2011 - 3:13 pm UTC

1) no, you cannot grant yourself something like that - you'd have to be using an account with the privileges to grant the necessary stuff.

Think about this:

you can run the grant command right? (you can run dbms_java)

but you cannot grant yourself just anything you want using grant, can you. That would be an OBVIOUS problem.


think about this.

Do NOT use the extremely deprecated and way far overprivileged javasyspriv. Have the dba grant you just what you need. Security counts.

ZIP files

A reader, September 20, 2011 - 9:37 pm UTC

Tom:

I have an HTML web form (pl/sql & mod_plsql) where users can enter a search criteria, hit "find" and the system will search the ORDERS table (oracle 9i) and list a webpage with all the orders that were found. The user should be able to hit "Zip & Download" button which will dump each ORDER HTML page to a directory on the server, then ZIP all the files together and download ONE zip file to the user client machine. The download can be using a direct link to the server or using mod_plsql.

I am using the above java stored procedure to call the UNIX zip command described in this link. so i cant use a table design solution where files are uploaded to a table and download from a table.

http://www.ehow.com/how_5056873_create-zip-file-unix.html


How would you best design this in terms of implementing concurrency controls in case "john" logs in and do a search/download and "mike" logs in and does another search/download.

Would you create one /tmp/ directory to dump all the files for all users and then ZIP all those order files into a unique zip filename? or would you use one directory per user /tmp/john/, /tmp/mike/ and clean up the directory each time they press the button. We only have one DB account. These are application user accounts stored in a table.

Can I also use the same zip file name or it has to be somehow unique.

Would you also call a direct link to the ZIP file bypassing mod_plsql so user can save the ZIP file to his PC? I think if i want to use mod_plsql I would need to upload this ZIP file from filesystem to a table first.

Can you advise on the best way to implement this.

Thanks,
Tom Kyte
September 21, 2011 - 9:31 am UTC

I probably would not create many files - but rather one file with an HTML list at the top that #linked to itself to get to each order. That way - just one file to deal with on the client (I'd be annoyed if you sent me X files - with possibly meaningless names - rather than a single file with links in it to see each order - where each link had a nice pretty descriptive name).

You would write that file out to the file system (you figure out the naming - I would probably incorporate a sequence in it) - the directory you write it to would either have to be a directory mapped in the webserver (so you can get files from there) or to a directory that is mapped inside the database as a DIRECTORY object - so you can BFILE the file and download it using mod_plsql. the latter would be more secure (if you put the zips into a mapped directory for the webserver, I could possibly guess file names and see other order files I should not be able to see)

then you can zip it - to the same name.zip or name.gz - which ever.

And then either redirect to the file using owa_util.redirect_url or file/download it using mod_plsql

OK

Daniel, October 07, 2011 - 6:18 am UTC

Hi Tom,
I was trying to create a java program in PL/SQL but I faced some issues which bewilder me.
Can you please take a look at it?

SQL> create or replace and compile java source   named "Testjava"
  2  as
  3  import java.lang.*;
  4  public class Testjava{
  5   public static String ret_greet(String [] argcs){
  6    return "Hello World";
  7  };
  8* }
SQL> /

Java created.

SQL> create or replace function f_java
  2  return varchar2
  3  as language java
  4  name 'Testjava.ret_greet(java.lang.String)';
  5  /

Warning: Function created with compilation errors.

SQL> show err
Errors for FUNCTION F_JAVA:

LINE/COL
--------------------------------------------------------------------------------
ERROR
--------------------------------------------------------------------------------
0/0
PL/SQL: Compilation unit analysis terminated

4/1
PLS-00311: the declaration of "Testjava.ret_greet(java.lang.String)" is incomple
te or malformed

Tom Kyte
October 07, 2011 - 1:56 pm UTC

you are creating a function, but you are not defining the return value.

search for:

function run_cmd

to see an example function stub for a java FUNCTION.

scp is not working through PL/SQL

Liviu, October 13, 2011 - 12:20 am UTC

Hi Tom,

I've read the previous discussions about starting external comands from pldql package. In my case I need to use scp to copy files between database hosts.
In my case, the java code is standard (see below) and it's working with any other host command except scp or ssh.
When I run scp command with oracle user in Bash, everithing works fine. (ssh is configured password less with key exchange). When I run from plsql I get return code 1 and nothing else.
Can you help me with an ideea.
Thanks,

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED "joCmd" AS

import java.io.*;
import java.lang.*;

public class joCmd extends Object
{
public static int execute(String args, int wait , int verbose )
{
int status = -1;
Runtime rt = Runtime.getRuntime();

try
{
String line;
Process p = rt.exec(args);
BufferedReader input = new BufferedReader (new InputStreamReader(p.getInputStream()));

if(verbose==1)
{
while ((line = input.readLine()) != null) {
System.out.println(line);
}
}

if(wait==1)
status = p.waitFor();
else
status = 0;

input.close();
}

catch (Exception e)
{
e.printStackTrace();
return status;
}
finally
{
if(verbose==1)
System.out.println("Status:"+status);
return status;
}
}
}


Tom Kyte
October 13, 2011 - 7:31 am UTC

In your script that is running scp that you are calling from plsql, put in copious debug - capture all output (stdout and stderr) so you can see what it happening.

Error on running to command

Archana, February 17, 2012 - 12:12 am UTC

Hi Tom

Im on linux and 11g.


I get this error below on running ls -l command.

Error starting at line 1 in command:
begin rc('ls -l') ; end;
Error report:
ORA-00932: inconsistent datatypes: expected a Java type at argument position 2 to which some Oracle value can be converted got something else

I copied exactly same what you have mentioned for myuser.
Not sure if something needs to be changed

Geeting error when calling the plsql procedure

Leontin, October 19, 2012 - 9:26 am UTC

Hi Tom,

I followed your steps but I am getting this when running the plsql procedure. Please help.
Thanks,
Leontin


SQL> exec leontin_rc('/usr/bin/ps -ef');
BEGIN leontin_rc('/usr/bin/ps -ef'); END;

*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected a Java type at argument position 2
to which some Oracle value can be converted got something else

Tom Kyte
October 23, 2012 - 11:25 am UTC

you changed something, and yet you don't show your work :(

sorry is all I can say therefore, I have no idea what you modified to break the working example.

Fixed ~ ORA-00932: inconsistent datatypes: expected a Java type at argument position 2

Shri Gupta, December 13, 2012 - 3:55 am UTC

Hello Tom,

I am working on 11g & Linux; copy pasted the exact code and got the below error

"ORA-00932: inconsistent datatypes: expected a Java type at argument position 2 to which some Oracle value can be converted got something else"

Modified the script as below
1. public static int RunThis(String[] args)
Changed to --> public static int RunThis(java.lang.String args)
2. Process p = rt.exec(args[0]);
Changed to --> Process p = rt.exec(args);
3. 'Util.RunThis(java.lang.String[])
Changed to --> 'Util.RunThis(java.lang.String)

Hope this helps.

Regards
Shri

SFTP shell script not working from PL/SQL

Bala, May 13, 2013 - 11:07 am UTC

Hi Tom,

I have used the code you have given to call the OS commands from PL/SQL. I made one shell script to transfer files from DB server to another server using FTP. I can be able to call that script from PL/SQL using "rc" procedure given by you. The same script I have modified to transfer the files using SFTP. Script is working well in Linux server, but the same script is not working when its called from PL/SQL. I am not able to understand the behaivour of this. Can you pls shed light on this problem.
Tom Kyte
May 13, 2013 - 1:13 pm UTC

you know that when it runs from plsql, it is running in an environment inherited ffrom the server process, it is running with the OS identity of the server process, in short - it is running in an entirely different environment from the one you are using at the command line.


start with debugging 101 techniques. In the script - dump out the id, uname and environment to a file in temp. Run the script with -vx or some other switches (debug mode) and redirect the output to that file in temp.

Now you'll have a file in temp that shows the environment you have, what identity you are running as and any errors encountered in the running of your script. this will be very illuminating - you won't even have to post that output, you'll be able to see what's going on straight off yourself.

Executing shell script

Vijay, May 13, 2013 - 5:16 pm UTC

Hi Tom,

I am trying to run a shell script using specified code.

Under SYS user :
=================
BEGIN
  DBMS_JAVA.GRANT_PERMISSION ( 'RDM_OWNER', 'java.io.FilePermission', '/usr/bin/sh', 'execute' );
  DBMS_JAVA.GRANT_PERMISSION ( 'RDM_OWNER', 'java.io.FilePermission', '/usr/bin/ps', 'execute' );
  DBMS_JAVA.GRANT_PERMISSION ( 'RDM_OWNER', 'java.lang.RuntimePermission', '*', 'writeFileDescriptor' );
  DBMS_JAVA.GRANT_PERMISSION ( 'RDM_OWNER', 'java.io.FilePermission', '/nas/aaa/devuser/*', 'execute' );
  DBMS_JAVA.GRANT_PERMISSION ( 'RDM_OWNER', 'java.io.FilePermission', '/nas/aaa/devuser/script/*', 'execute' );
END;
/ 

PL/SQL procedure successfully completed.



I have one ksh file under path file /nas/aaa/devuser/script/helloworld.ksh

when i am trying execute that file getting return code 1 always.

created below procdure
--------------------------
create or replace
PROCEDURE RC(
    p_cmd IN VARCHAR2)
AS
  x NUMBER;
BEGIN
  x := run_cmd(p_cmd);
  dbms_output.put_line(x);
EXCEPTION
WHEN OTHERS THEN
  dbms_output.put_line(sqlerrm);
END;



SQL> exec RC('/usr/bin/sh /nas/aaa/devuser/espresso/helloworld.ksh');
1

PL/SQL procedure successfully completed.

please suggest what more permission required. 'devuser' is a user mounted on same host where oracle installed.

Thanks
Vijay

Tom Kyte
May 13, 2013 - 5:28 pm UTC

oh - do not give access to /usr/bin/sh!!!!! that would let you run *anything*.

just run the script you want. (and why would you use sh to run a ksh???)

Executing shell script from oracle

Vijay, May 14, 2013 - 5:18 am UTC

Hi Tom ,
I Have given following permission as u suggested.

GRANT DEV_OWNER SYS java.io.FilePermission  /nas/aaa/devuser/*       execute ENABLED 118
GRANT DEV_OWNER SYS java.io.FilePermission  /nas/aaa/devuser/script/*     execute ENABLED 119
GRANT DEV_OWNER SYS java.io.FilePermission  /nas/aaa/devuser/script/helloworld.ksh  execute ENABLED 120
GRANT DEV_OWNER SYS java.io.FilePermission  /usr/bin/ps         execute ENABLED 115
GRANT DEV_OWNER SYS java.io.FilePermission  /usr/bin/sh         execute ENABLED 117
GRANT DEV_OWNER SYS java.lang.RuntimePermission *        writeFileDescriptor ENABLED 116



-- And when i am trying to execute following getting error like below.


SQL> set serveroutput on size 1000000
SQL> exec dbms_java.set_output(1000000)

PL/SQL procedure successfully completed.

SQL> exec RC('/nas/aaa/devuser/script/helloworld.ksh');
java.io.IOException: /nas/aaa/devuser/script/helloworld.ksh not found
        at java.lang.OracleProcess.create(Native Method)
        at java.lang.OracleProcess.construct(OracleProcess.java:111)
        at java.lang.OracleProcess.<init>(OracleProcess.java:41)
        at java.lang.OracleProcess.start(OracleProcess.java:381)
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:483)
        at java.lang.Runtime.exec(Runtime.java:591)
        at java.lang.Runtime.exec(Runtime.java:429)
        at java.lang.Runtime.exec(Runtime.java:326)
        at Util.RunThis(Util:14)
-1

PL/SQL procedure successfully completed.




-- "devuser" is a user mounted on same host where oracle installed.
-- "devuser" required password to switch into.Is this a reason my program is not able to reach that ksh.



please suggest how to reach ksh which is kept inside password enabled user ie. devuser in my example.

Thanks,
Vijay
<b></b><b></b>

Tom Kyte
May 14, 2013 - 12:29 pm UTC

you'll have to make it so the user that runs the dedicated server - what process id that process runs as - has read and execute on the directory and execute on the script. standard OS stuff.

it doesn't have to do with devuser needing a password, it has to do with the fact that the process owner the dedicated server is running under cannot 'see' that file.

Michael Kutz, May 14, 2013 - 1:50 pm UTC

If you are on 10g+, why not use DBMS_SCHEDULER instead?


Tom Kyte
May 14, 2013 - 5:12 pm UTC

that is an option maybe, however the same exact problems will exist as far as permissions and visibility go.

the issue with dbms_scheduler is that if you need to run this script from a procedure and then process the output - using the scheduler can really complicate your logic. If all you want to do is "run script, get output" and not "run this script on a recurring basis in the background" - the scheduler doesn't make it easy.

but yes, the scheduler can be used without having to install java code.

ZERO SIZE FILE OUTPUT

Mina, December 10, 2013 - 12:19 pm UTC

dear tom,

i have used this code to execute a .sh file that encrypts a file and places it in a folder, the code completes successfully but the output is one file with 0 size. When i run that script from UNIX it runs correctly and i have a usable output file.

can you please help me??

the used java code:

CREATE OR REPLACE AND RESOLVE JAVA SOURCE NAMED APPS."RuntimeDemo" AS
public class RuntimeDemo {
public static int shell() {
Runtime rt = Runtime.getRuntime();
int rc = -2;
try
{
Process p = rt.exec("sh /home/oracle/script_payment/newprogram.sh");

rc = p.waitFor();
return rc;
}
catch (Exception e)
{
e.printStackTrace();
System.err.println(e.getMessage());
rc = -1;
return rc;
}
}
}

create or replace
function APPS.XX_SHELL_EXECUTE return number
as
language java
name 'RuntimeDemo.shell() return integer';


declare
v_grantee constant varchar2(30) := 'APPS';
begin
dbms_java.grant_permission
(v_grantee,
'java.io.FilePermission',
'/usr/bin/sh',
'execute');
dbms_java.grant_permission
(v_grantee,
'java.lang.RuntimePermission',
'*',
'writeFileDescriptor' );
dbms_java.grant_permission
(v_grantee,
'java.lang.RuntimePermission',
'*',
'readFileDescriptor' );
end;

the used newprogram.sh file:
#!/bin/sh

echo 'Printing parameters....'

echo '1:'$1

echo 'Finished printing parameters.'

Filename=$1

echo $Filename

#DAY=`/bin/date +%d%m%Y`

#fileReferenceNumber=$(($2 + 1))

#DestinationFile=$1 #'HDF''1501'$DAY'.P00'$fileReferenceNumber

echo $DesinationFile

iconv -f utf-8 -t asmo-708 /oracledb/proddb/bank_files/$Filename > /oracledb/proddb/bank_files/out/$Filename

echo "Convert with iconv completed here"
echo $DesinationFile

#iconv -f text -t asmo-708 /oracledb/proddb/bank_files/$Filename > /home/oracle/script_payment/out/$DestinationFile

GPGFILE=$Filename'.gpg'

#gpg --recipient user@example.com --encrypt /home/oracle/out_anb/$DestinationFile

#echo $DestinationFile > /home/oracle/out/upload_file.txt

if test -f /oracledb/proddb/bank_files/out/$GPGFILE
then
echo 'File already exist.'
exit 0
fi

gpg --recipient user@example.com --encrypt /oracledb/proddb/bank_files/out/$Filename

#echo $Filename'.gpg' > /home/oracle/script_payment/out/upload_file.txt
echo $Filename'.gpg' > /oracledb/proddb/bank_files/out/upload_file.txt

/home/oracle/script_payment/uploadsftp1.sh

echo 'File uploaded SFTP Folder'


can be used to run host command on Linux server??

Fabrizio Delli Priscoli, January 02, 2014 - 2:27 pm UTC

Hi. I read this article and it was very interesting.
Can I use this example to run a host command on a Linux Server??
I explain my scenario: I have an oracle form application on server1 and I want to use code in this article to run a sql file that is on the same server (Linux) of the DB; this server is different from server1.

So what I want is to make possible from form application to write a command like this:

@/mydirectory/myfile.sql param1 param2

and so run myfile.sql that is located on linux server.
Hi followed all step, I have created all the code provided, but when I run the command

exec rc('@/mydirectory/myfile.sql');

I receive this error:

*
ERROR at line 1:
ORA-00932: inconsistent datatypes: expected a Java type at argument position 2
to which some Oracle value can be converted got something else

So, where am I wrong??

Thanks for collaboration,
Fabrizio


Package java source

bakunian, June 05, 2014 - 7:17 pm UTC

Tom,

Is there a way to make Java source part of PL/SQL package body in 11gR2? Similar to following:

create or replace package body java_pkg as
JAVA SOURCE NAMED "WriteThis" AS
import java.io.FileWriter;
import java.io.IOException;
....

Thank you.

Dos2unix command

satish, September 04, 2014 - 7:50 am UTC

Hi Tom,

I need execute dos2unix command in remote unix machine from local system on some files which are in "/ftp/abc/def" path . so can you please give how do we need to call to RC function ?

running from the forms 11g

Srinivas, November 04, 2014 - 4:57 pm UTC

Hi tom,
We ahve a existing procedure to run the oscommand from forms 11g, using pl/sql procedure and java class.

declare
n number;
begin
n := Oscommand('cmd.exe /c E:\batch\file1.bat');
-
-
end;

this os command use the java class OSCommand.Run

my question is, where the command will execute, is it in db server or application server or in local.

we don't have any E:\batch\file1.bat path in local machine or in server. db server is unix server.

As per my knowledge the cmd.exe will call on db server, but db server is unix server.

Is there any way to set the machine name to run the os commands.

But and if I need a smbclient?

Vinicius Pacheco, November 01, 2019 - 6:41 pm UTC

Hi, Tom.

I've used your code to solve this situation: I need to send ZPLII files to a zebra printer from a dbms_scheduler job.

The database server is a Unix machine. It's a Oracle Database 11g Release 11.2.0.4.0 - 64bit Production

The printer is a network printer wich the print server is a Windows NT.

I gave the grants:
dbms_java.grant_permission ('WIS','java.io.FilePermission','/usr/bin/ps','execute');
dbms_java.grant_permission ('WIS','java.io.FilePermission','/usr/bin/ls','execute');
dbms_java.grant_permission ('WIS','java.io.FilePermission','/usr/bin/smbclient','execute');
dbms_java.grant_permission ('WIS','java.lang.RuntimePermission','*','writeFileDescriptor');

If I run your RC procedure to do a 'ps -ef' it works perfectly:
SQL> set define off
SQL> set lines 200
SQL> set serveroutput on size 1000000
SQL> exec dbms_java.set_output(1000000)

PL/SQL procedure successfully completed.

SQL> declare
2 cmd varchar2(2000);
3 begin
4 cmd := 'ls -la /home/oracle/oradata/zpl';
5 dbms_output.put_line(cmd);
6 rc(cmd);
7 end;
8 /

ls -la /home/oracle/oradata/zpl
total 72
drwxr-xr-x. 2 oracle oracle 45056 Oct 31 11:36 .
drwxr-xr-x. 7 oracle oracle 4096 Jul 25 10:40 ..
-rw-r--r-- 1 oracle oracle 1153 Oct 29 18:45 et.txt
-rw-r--r--. 1 oracle oracle 101 Oct 29 2014 e.txt
-rw-r--r--. 1 oracle oracle 18 Aug 28 13:47 nomeimpr.doc
-rw-r--r-- 1 oracle oracle 30 Aug 27 18:03 nomeimpr.doc.bk
-rw-r--r--. 1 oracle oracle 172 Dec 10 2010 proc-impr-etiq.sh
-rw-r--r-- 1 oracle oracle 1153 Aug 28 14:35 usada_para_testes.txt
X = 0

PL/SQL procedure successfully completed.

SQL>


But if I use it to call a smclient, it doesn't (the "xxxxxx" is only to hide actual users and paswords):
SQL> set define off
SQL> set lines 200
SQL> set serveroutput on size 1000000
SQL> exec dbms_java.set_output(1000000)

PL/SQL procedure successfully completed.

SQL> declare
2 cmd varchar2(2000);
3 begin
4 cmd := 'smbclient -U ''xxxxxx\xxxxxx%xxxxxx'' //serverps02/zebra_teste -c ''print /home/oracle/oradata/zpl/et.txt'' ';
5 dbms_output.put_line(cmd);
6 rc(cmd);
7 end;
8 /
smbclient -U 'xxxxxx\xxxxxx%xxxxxx' //serverps02/zebra_teste -c 'print /home/oracle/oradata/zpl/et.txt'
session setup failed: NT_STATUS_LOGON_FAILURE
X = 1

PL/SQL procedure successfully completed.


Of course, I've tested the smbclient command from bash to be sure it's correct:
smbclient -U 'xxxxxx\xxxxxx%xxxxxx' //serverps02/zebra_teste -c 'print /home/oracle/oradata/zpl/et.txt'
Domain=[xxxxxx] OS=[Windows Server 2012 Datacenter 9200] Server=[Windows Server 2012 Datacenter 6.2]
putting file /home/oracle/oradata/zpl/et.txt as et.txt-4931 (28.9 kb/s) (average 28.9 kb/s)

There is any aditional grant needed to run a smbclient instead a ps -ef?

Thanks a lot for all the knollege sharing on your site!

Re: But and if I need a smbclient?

Vinicius Pacheco, November 06, 2019 - 6:07 pm UTC

Thanks a lot for your reply.

But I think I didn't understand your sugestion. Or you didn't understand my question. First one has bigger chances... :-)

From the links you posted and other reads, I understand that external tables are usefull to "import" to oracle some "outside" information...

But it is not what I'm trying to do. The information is already in the database. I just need to print some labels based on it, regardless a user take an action to this.

So there is a job that time to time seeks my tables for some condition. When it occurs, It's created a file (via utl_file) with the ZPLII commands. Untill here I got dthe code working.

But after creating the files, I need to send then to the printer. This is where I try to use java: just to do a print command that I can't do from the database.

I can't figure how to use external tables to print.

On the other hand, I didn't knew external tables and when I needed somethig like that I used to read files using utl_file. External tables seems more easy to do. So, thanks for the information, but, seems that isn't what I need.
Connor McDonald
November 07, 2019 - 3:13 am UTC

"But I think I didn't understand your sugestion".... that's still my fault - I need to explain better.

In (almost) any situation where you need to run a host command (any host command) from within the database, an external table can pretty much do that job now.

Obviously that is not what external tables were really designed for, but I find it a very easy and powerful mechanism to use because of the preprocessor option.

Let's say I needed to secure copy (scp) a file from a call *inside* the database. Then my preprocessor script could be something like:

/bin/scp $* remote_server:/tmp
echo DONE


The filename from the external table is passed into that preprocesor script and then you can do whatever you like with it.

So whilst it LOOKS like I did:

SQL> select output from my_external_table;

OUTPUT
--------
DONE


I have actually run the scp command due to the preprocessor script.

So you would put your smb calls (and anything you like) into your script, and then by *querying* the external table, you will run the host commands you desire.

Complilation errors for java source

Karim, January 29, 2020 - 4:24 pm UTC

HI Tom,

How can i fix the error of the function getTotalSpace() of the package
java.io.File showing that this function is not exist (im using oracle database 11g R2 , plsqldevelopr tool)
the error is :
Error: cannot find symbol
Text: s=d.getTotalSpace();

Example of procedure plsql :

create or replace and compile java source named "usbv" as
import java.io.File;
public class usbv {
public static String list_usbv () {
String n=null;
Long s;
File[] drives = File.listRoots();
if ((drives != null) &&(drives.length) > 0) {
for (File d : drives) {
if (d.canWrite()==true) {
try {
s=d.getTotalSpace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if(s>0){
if (n==null)
n=""+d;
else
n=n+" "+d;
}
else
n=" ";
}
}
}
return n;
}
}

Thank you.

Connor McDonald
January 30, 2020 - 9:02 am UTC

See my previous review - I suggest moving to an external table or scheduler approach

add library java to oracle

karim, January 29, 2020 - 5:43 pm UTC

Hy Tom,

How can i add the library usb4java.jar to oracle database 11g.

Thank you.



More to Explore

PL/SQL demos

Check out more PL/SQL tutorials on our LiveSQL tool.

PL/SQL docs

PL/SQL reference manual from the Oracle documentation library