I am wondering if using loadjava to load the Java package called JSch.jar in an Oracle database and then loading another .java file, that utilizes the JSch package to connect over SSH, would be able to be executed within an Oracle database through a function or procedure.
I ask this before trying because I need to reach out to a DBA to try and load everything. I want to make sure it is doable because I am not very skilled in java as of yet and wouldn't know if something was impossible or if it just needs fixed.
Thanks.
Yes
Use something like:
loadjava -user USERNAME/PASSWORD#SID JSch.jar
Then create a static class method which uses the classes loaded from the Jar file:
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED MyJavaSource AS
import org.millea9805.jsch.JSchSomething;
public class MyClass {
public static String function_name()
{
JSchSomething.doSomething();
return "Something";
}
}
/
Then you can create a PL/SQL wrapper around the static Java method:
CREATE OR REPLACE FUNCTION DO_SOMETHING()
RETURN VARCHAR2
AS LANGUAGE JAVA
NAME 'MyClass.function_name() return java.lang.String';
/
A more detailed example using the XZ library to unzip BLOBs is here.
Assuming I want to trace method calls in all the classes in packages com.abc and com.def
I put the following in my tracing script:
#OnMethod(clazz = "/com\\.(abc|def)\\..*/", method = "/.*/")
ran the script, but the output only contained method calls in com.abc package.
I changed the above line to:
#OnMethod(clazz = "/com\\.def\\..*/", method = "/.*/")
and ran the script again. The output contained method calls in com.def package.
So what's wrong with the part "(abc|def)"?
I've tried to find some information under the following link:
https://github.com/btraceio/btrace/wiki/BTrace-Annotations
The description is very abstract:
/regex/ is a standard regular expression used to identify the class
names
Does it support OR-relation?
I'm currently using Oracle 12c Standard Edition.
I have created a Java class and compiled it using the JDK 6 (because Oracle 12c has default support for JDK 6). The class goes as following:
import java.io.File;
import java.io.IOException;
public class Run_Batch
{
public static void main(String[] args) throws InterruptedException, IOException
{
Runtime.getRuntime().exec("cmd /c start execute_r.bat", null, new File("C:/Users/Admin/workspace/"));
}
}
My goal is to create a Java stored procedure, which I can call through Oracle using PL/SQL. The Java stored procedure would call the main() method from the Run_Batch class, spawn a new OS process (presumably) and run the execute_r.bat batch file found in the C:/Users/Admin/workspace directory. After that, the .bat file would run a .R file, which would create a new table inside the Oracle database, using the ROracle library.
The code for the .bat file goes as follows:
path
Rscript run_signal.R
pause
exit
Both the .bat and the .R files are found inside of the C:/Users/Admin/workspace directory.
The code for the .R file is:
library(ROracle)
drv <- dbDriver("Oracle")
host <- "win-2h3vud23lai"
port <- 1521
sid <- "oracle"
connect.string <- paste(
"(DESCRIPTION=",
"(ADDRESS=(PROTOCOL=tcp)(HOST=", host, ")(PORT=", port, "))",
"(CONNECT_DATA=(SID=", sid, ")))", sep = "")
con <- dbConnect(drv, username = "C##USER",
password = "password",dbname=connect.string)
createTable <- "CREATE TABLE IRIS_TABLE (time_stamp VARCHAR2(55),
category VARCHAR2(15), type VARCHAR2(55),
servername VARCHAR2(15), code VARCHAR2(15), msg VARCHAR2(255))"
I've followed the small Oracle tutorial on Java stored procedure and I have already compiled my Run_Batch.java file using javac and loaded the Java file into the database using:
loadjava -user C##USER/password Run_Batch.class
After that, I have entered SQLPLUS.exe and I have created both a package and a package body:
CREATE OR REPLACE PACKAGE run_r_package AS
PROCEDURE run_test_batch ( ARGUMENTS VARCHAR2 )
END;
CREATE OR REPLACE PACKAGE BODY run_r_package AS
PROCEDURE run_test_batch( ARGUMENTS VARCHAR2)
AS LANGUAGE JAVA
NAME 'Run_Batch.main(java.lang.String[])';
END;
I have created the package with the package body successfully.
However, I'm not able to run the Java stored procedure nor to call the run_r_batch() procedure. Whenever I try to do so I get errors to undefined classes, undefined errors or weird exception names.
I haven't been able to make the Oracle documentation (found here: https://docs.oracle.com/database/121/JJDEV/chseven.htm#JJDEV13283) to work.
Using the sqlplus, if I do:
CALL run_test_batch('123');
I get the following error:
ORA-06576: not a valid function or procedure name
if, instead of using CALL, I use EXECUTE, as follows:
EXECUTE run_test_batch('123');
I get the following error:
ORA-06550: line 1, column 7
PLS-00201: the identifier 'run_test_batch' must be declared
ORA-06550: line 1, column 7
PL/SQL: statement ignored.
If I use SQL Developer instead of SQLPLUS, after I connect to my user C##USER with my password, I try to run the procedure using the following code:
BEGIN
run_r_package.run_test_batch('');
END;
the first time I got the message:
Execution terminated due to unresolved exception:
ORA-29532: java call terminated by uncaught java exception: java.lang.ExceptionInInitializerError
ORA-06512: in "C##USER.RUN_R_PACKAGE", line 2
But now, when I tried to run the code again I get a different message:
ORA-29532: java call terminated by uncaught java exception: java.lang.NoClassDefFoundError
ORA-06512: in "C##USER.RUN_R_PACKAGE", line 2
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
EDIT
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
I tried to refine my class and run a simple Windows command as suggested in the comments.
The new Java file goes as follows:
import java.io.File;
import java.io.IOException;
public class Run_Batch
{
public static void proc() throws InterruptedException, IOException
{
Runtime.getRuntime().exec("cmd /c cmd.exe", null, null);
}
}
My package creation code has been modified as following:
CREATE OR REPLACE PACKAGE run_r_package AS
PROCEDURE run_test_batch
END;
CREATE OR REPLACE PACKAGE BODY run_r_package AS
PROCEDURE run_test_batch
AS LANGUAGE JAVA
NAME 'Run_Batch.proc()';
END;
If I use botch CALL or EXECUTE in sqlplus.exe I get the same error saying run_test_batch must be declared.
If I try to call the procedure via SQL Developer like this:
BEGIN
run_r_package.run_test_batch;
END;
I get the errors:
ORA-29531: no method proc in class Run_Batch
ORA-06512: en "C##USER.RUN_R_PACKAGE", line 2
ORA-06512: en line 2
While the referenced question is similar it speaks to putting the source code into the database not the class, also I would like to use the TOAD utilities to accomplish this.
So as proof of concept I have been attempting to load a java class into an Oracle 12c Database and access it via an Oracle function.
I opened Eclipse and created new project Hello with class Hello:
public class Hello {
public static String world()
{
return "Hello world";
}
}
I compiled it and now on my client I have
C:\Users\me\workspaces\Hello\bin\Hello.class
I opened up TOAD for an oracle 12c database, then I went to utilities / Java Manager and loaded my class:
TOAD says it successfully loaded. However, I'm not sure if it did.
Next, I went into the TOAD editor and created a function:
CREATE OR REPLACE function "DIR\KBD0010".helloworld RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'Hello.world () return java.lang.string';
Then I attempted to select it with a sql query:
select helloworld()
from dual;
And then I am getting:
ORA-29540: class Hello does not exist
I have loaded a Java class into Oracle using the loadjava utility.
This class has some system.out.println messages.
When I execute a method from this class I want to see the the sysout messages.
Where can I find these messages?
System.out and System.err writes to the current trace files.
You can enable output to SQL*Plus or similar with
set serveroutput on size 10000
exec dbms_java.set_output(10000)
See the Java Developer's Guide here.
That said, you should ask yourself, what do I want to log, that my client would not like to see returned in the interface to my procedure?. The answer to that is usually nothing.
I have been able to set up http://www.slf4j.org/ with a JDBC database appender (I am unsure of the specifics).
An Oracle article provides some useful information.
Quote:
Your class:
public class SimpleJava {
public void main(String[] args) {
System.out.println("Here we are");
}
}
Now, compile and load your class:
C:\oracle9i\bin>javac SimpleJava.java
C:\oracle9i\bin>loadjava -user scott/tiger SimpleJava.class
From SQL*Plus, create the PL/SQL wrapper to invoke the newly loaded Java class:
SQL> create or replace procedure call_simplejava
2 as language java
3 name 'SimpleJava.showMessage()';
4 /
Execute the code from SQL*Plus:
SQL> set serveroutput on;
SQL> call dbms_java.set_output(50);
Call completed.
SQL> execute call_simplejava;
Here we are