UDF on DB2 invoked in a trigger - java

In my application, I need a Java process to run by a trigger-- whenever a change has been made to field dateLastChanged of TrackTable, that process should fire.
I followed through these steps for this:
1.) compiled the following code:
public class UDFClass {
public static int udf(String coCode, String tNo) {
int result = 1;
String command = "<the java command here>"; // line-K
try {
Runtime.getRuntime().exec(command);
} catch (IOException e) {
result = 0;
}
return result;
}
}
2.) put UDFClass.class under sqllib/function directory of the DB2 installation
3.) ran the following function on db2. It ran successfully:
create or replace function theresUpdate(cocode varchar(4), tnumber varchar(20))
returns integer
external name 'UDFClass.udf'
language Java
parameter style Java
not deterministic
no sql
external action
4) successfully ran the following trigger on DB2:
create or replace trigger notify
after update of dateLastChanged
or insert
on TrackTable
REFERENCING new as newRow
for each row
not secured
begin
update performanceParams set thevalue = theresUpdate(newRow.cocode, newRow.tnumber) where thekey = 'theDate';
end
To test, i update TrackTable as follows:
update TrackTable set dateLastChanged = dateLastChanged + 10 where tNumber = ‘21123’
this update query runs successfully without the trigger in (4) above. However, with this trigger, i get the following error:
An error occurred in a triggered SQL statement in trigger "LTR.NOTIFY".  Information returned for the error includes SQLCODE "-4301", SQLSTATE "58004" and message tokens "1".. SQLCODE=-723, SQLSTATE=09000, DRIVER=4.18.60
This page indicates that it’s a Java related error. However, the command in line-K of the Java code in (1) is running all fine when I invoke it from the Linux command line.
I tried some other variations of the function in (3)-- deterministic rather than not deterministic, not fenced.
I’m using DB2 version 10.5.
Please help!

Related

DB2 external java jar file stored procedure error

I have been trying to call a java jar file from DB2 stored procedure as external jar.
Below is my external jar file code.
package connection;
public class Connect {
static Connection con = null;
static Statement stmt = null;
public static void main(String[] args) throws SQLException {
javastp("v1");
}
public static void javastp( String name) throws SQLException{
try {
con = DriverManager.getConnection( "jdbc:default:connection" );
stmt = con.createStatement();
stmt.executeUpdate("INSERT INTO SCHEMA_NAME.TEST(NAME, FLAG) VALUES ('"+name+"',true) ");
}catch (Exception e) {
// ...
}finally {
//Close open resources
if (stmt != null) stmt.close();
if (con != null) con.close();
}
}
}
i install it using below command in db2 server
db2 call sqlj.install_jar('file:E:/jarpath../jarname.jar','jarname',0);
Below is the stored procedure for DB2 external jar.
CREATE OR REPLACE PROCEDURE SCHEMA_NAME.PROC6()
LANGUAGE java
PARAMETER STYLE java
FENCED
EXTERNAL NAME 'jarname:connection.Connect.main'
The stored procedure executes successfully without errors.
But when i try to call the stored procedure using below,
CALL SCHEMA_NAME.PROC6()
i get the below error
SQL Error [38503]: A stored procedure process has been terminated abnormally. Routine name: "SCHEMA_NAME.PROC6". Specific name: "SQL201016144125554".. SQLCODE=-1131, SQLSTATE=38503, DRIVER=4.8.86
The java jar works fine when executed directly in the command prompt and the records are being inserted into the table, but i cant seem to figure out why the external stored procedure gives me error when i try to call it that way.
Can somebody here please help me out as am stuck on this since a very long time and i have no background of DB2.
the db2level command gives the below output:
DB21085I This instance or install (instance name, where applicable: "DB2")
uses "64" bits and DB2 code release "SQL10058" with level identifier
"0609010E".
Informational tokens are "DB2 v10.5.800.381", "s160901", "IP24000", and Fix
Pack "8".
Product is installed at "C:\PROGRA~1\IBM\SQLLIB" with DB2 Copy Name "DB2COPY1".
Linux Suse db2 version 11.1.2
Database server = DB2/LINUXX8664 11.1.2
The log is as below:
2020-10-20-09.24.56.746633+330 I4952989679E1230 LEVEL: Error
PID : 31693 TID : 140179352315648 PROC : db2sysc 0
INSTANCE: NODE : 000 DB :
APPHDL : APPID:
AUTHID : HOSTNAME:
EDUID : 2768 EDUNAME: db2agent () 0
FUNCTION: DB2 UDB, routine_infrastructure, sqlerWaitForFencedInvocation, probe:12115
MESSAGE : ZRC=0xFFFFFB38=-1224
SQL1224N The database manager is not able to accept new requests,
has terminated all requests in progress, or has terminated the
specified request because of an error or a forced interrupt.
Error SQL1131N has the following description
The DB2 architecture is designed so that applications run in a different address space than the database server. Running applications in a different address space prevents application programming errors from overwriting database manager internal buffers or files, and prevents application errors from crashing the database manager. The fenced mode process (db2fmp) is responsible for executing fenced stored procedures and user-defined functions in a different address space than the database server.
This message is returned when the db2fmp process terminates abnormally while running the named routine. The db2fmp process could have terminated abnormally for many reasons, including the following reasons:
There was a coding error, such as division by zero or an out-of-bounds pointer reference, in the implementation of the stored procedure or user-defined function that the db2fmp process was executing.
Another process terminated the db2fmp process using a signal, such as the termination signal SIGTERM.
SQLJ.INSTALL_JAR failed while installing a Java routine because the fenced user does not have permission to create or write to the necessary directories on the server.
Db2 is unforgiving when you make mistakes with external non-SQL code, in this case, it just throws an exception and expects you to sort it out.
Only use java for Db2 stored procedures when there is a compelling reason to NOT use SQL PL procedures.
You have these mistakes
You cannot use a main() for a Db2 java stored procedure entry point
The stored procedure entry point should be in your case the javastp() method
The EXTERNAL NAME clause in the DDL must not reference main() but should use javastp instead
The parameters in the create procedure line must match those of the method
in number and type and sequence. (In your case that is (IN name varchar(255) or similar).

JNA native code sometimes fails with error code 127: "The specified procedure could not be found"

I'm using JNA to call native code. This works most of the time but sometimes I'm getting the following exception:
java.lang.IllegalStateException: 127: The specified procedure could not be found.
Usually this exception happens the first time this is called if at all. If the call succeeded, all following calls will succeed as well as long as the Java program runs.
My code looks like the following for instance:
boolean succeeded = MY_KERNEL_32.DebugSetProcessKillOnExit(false);
if (!succeeded)
{
checkForKernelError();
}
checkForKernelError() is defined as follows:
private static void checkForKernelError()
{
int lastErrorCode = MY_KERNEL_32.GetLastError();
if (lastErrorCode != 0)
{
String lastErrorMessage = formatMessage(lastErrorCode);
String errorMessage = lastErrorCode + ": " + lastErrorMessage;
throw new IllegalStateException(errorMessage);
}
}
The idea is to call a Windows API native code in combination with some other process running on Windows and always assert that it succeeded afterwards. But why do I sometimes get The specified procedure could not be found when the native function never changes and should always be found. What could be the problem here and how can it be fixed so it consistently works like it should?

Oracle - Calling .bat file (which calls to an R file) from inside a Java stored procedure

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

How to pass configurations from hive script to UDF

In pig, you can pass a configuration from your pig script to pig UDF via UDFContext. For example,
// in pig script
SET my.conf dummy-conf
// in UDF java code
Configuration conf = UDFContext.getUDFContext().getJobConf();
String myConf = conf.get("my.conf");
So, is there a similar way to pass configuration from a hive script to a hive UDF? For example, if I have set MY_CONF='foobar' in a hive script, how can I retrieve that in a java UDF, which needs to consume the value of MY_CONF?
Instead of extending UDF class, you can try subclassing GenericUDF. This class has the following method you can override:
/**
* Additionally setup GenericUDF with MapredContext before initializing.
* This is only called in runtime of MapRedTask.
*
* #param context context
*/
public void configure(MapredContext context) {
}
MapredContext has a method just like UDFContext from Pig to retrieve the Job configuration. So you could just do the following:
#Override
public void configure(MapredContext context) {
Configuration conf = context.getJobConf();
}
As of hive 1.2 there are 2 approaches.
1. Overriding configure method from GenericUDF
#Override
public void configure(MapredContext context) {
super.configure(context);
someProp = context.getJobConf().get(HIVE_PROPERTY_NAME);
}
Above(1) won't work in all the cases. Works only in MapredContext.
Every query has to be force map/reduce jobs, to do that set
set hive.fetch.task.conversion=minimal/none;
set hive.optimize.constant.propagation=false;
.
with above properties set, you will hit major performance problems, especially for smaller queries.
2. Using SessionState
SessionState ss = SessionState.get();
if (ss != null) {
this.hiveConf = ss.getConf();
someProp = this.hiveConf.get(HIVE_PROPERTY_NAME);
LOG.info("Got someProp: " + someProp);
}
Go to hive command line
hive> set MY_CONF='foobar';
your variable should be listed when hitting the command
hive> set;
Now, consider you have below
Jar: MyUDF.jar
UDF calss: MySampleUDF.java which accepts a String value.
Table: employee
hive> ADD JAR /MyUDF.jar
hive> CREATE TEMPORARY FUNCTION testUDF AS 'youpackage.MySampleUDF';
hive> SELECT testUDF(${MY_CONF}) from employee;
there are lots of example, shared , so you can find all required details over google :).
A Small Example which was describe in shared link:
hive> ADD JAR assembled.jar;
hive> create temporary function hello as 'com.test.example.UDFExample';
hive> select hello(firstname) from people limit 10;
Please check link for reference which I normally Used to:
Link1
Link2

Mongodb: db.printShardingStatus() / sh.status() call in Java (and JavaScript)

I need to get a list of chunks after sharding inside my Java code. My code is simple and looks like this:
Mongo m = new Mongo( "localhost" , 27017 );
DB db = m.getDB( "admin" );
Object cr = db.eval("db.printShardingStatus()", 1);
A call of eval() returns an error:
Exception in thread "main" com.mongodb.CommandResult$CommandFailure: command failed [$eval]: { "serverUsed" : "localhost/127.0.0.1:27017" , "errno" : -3.0 , "errmsg" : "invoke failed: JS Error: ReferenceError: printShardingStatus is not defined src/mongo/shell/db.js:891" , "ok" : 0.0}
at com.mongodb.CommandResult.getException(CommandResult.java:88)
at com.mongodb.CommandResult.throwOnError(CommandResult.java:134)
at com.mongodb.DB.eval(DB.java:340)
at org.sm.mongodb.MongoTest.main(MongoTest.java:35)
And, really, if we look into the code of db.js, in line 891 there is a call to a method printShardingStatus() that is not defined inside a file. Inside of sh.status() method in utils_sh.js file, there is even a comment:
// TODO: move the actual commadn here
Important to mention, when I run these commands in mongo command line, everything works properly!
My questions are:
Is there any other possibility of getting a full sharding status within Java code? (eg. with DB.command() method)
If not, any other suggestions how to avoid my problem?
Many of the shell's helper functions are not available for server-side code execution. In the case of printShardingStatus(), it makes sense because there isn't a console to use for printing output and you'd rather have a string returned. Thankfully, you should be able to pull up the source of the shell function and reimplement it in your application (e.g. concatenating a returned string instead of printing directly).
$ mongo
MongoDB shell version: 2.2.0
connecting to: test
> db.printShardingStatus
function (verbose) {
printShardingStatus(this.getSiblingDB("config"), verbose);
}
So, let's look at the printShardingStatus() function...
> printShardingStatus
function (configDB, verbose) {
if (configDB === undefined) {
configDB = db.getSisterDB("config");
}
var version = configDB.getCollection("version").findOne();
// ...
}
Before turning all of the output statements into string concatenation, you'd want to make sure the other DB methods are all available to you. Performance-wise, I think the best option is to port the innards of this function to Java and avoid server-side JS evaluation altogether. If you dive deeper into the printShardingStatus() function, you'll see it's just issuing find() on the config database along with some group() queries.
If you do want to stick with evaluating JS and would rather not keep this code within your Java application, you can also look into storing JS functions server-side.
Have you deployed a shard cluster properly?
If so, you could connect to a mongo database that has sharding enabled.
Try calling the method db.printShardingStatus() with a that database within the mongo shell and see what happens.
Apparently the Javascript function 'printShardingStatus' is only available for the mongo shell and not for execution with server commands, to see the code start mongo.exe and type only 'printShardingStatus' and press enter.
In this case writing an extension method would be the best for solving this...
Javascript way of printing output of MongoDB query to a file
1] create a javascript file
test.js
cursor = db.printShardingStatus();
while(cursor.hasNext()){
printjson(cursor.next());
}
2] run
mongo admin --quiet test.js > output.txt

Categories

Resources