DB2 7.2 Java UDF 不在 Classpath 中
Posted
技术标签:
【中文标题】DB2 7.2 Java UDF 不在 Classpath 中【英文标题】:DB2 7.2 Java UDF not in Classpath 【发布时间】:2021-09-13 07:50:06 【问题描述】:我创建了一个 Java 类,在 Java 中实现了 Levenshtein 距离算法,以便在 DB2 UDF 中使用它。
显然,在DB2下,注册java UDF有两种方式,一种是复制QIBM/UserData/OS400/SQLLib/Function下的.class文件,另一种是复制一个JAR,然后使用SQLJ.INSTALL_JAR。
现在,我的 Java 源代码如下所示:
package FUNCTIONS;
public class LEVENSHTEIN
public static int levenshteinDistance (String lhs, String rhs)
int len0 = lhs.length() + 1;
int len1 = rhs.length() + 1;
// the array of distances
int[] cost = new int[len0];
int[] newcost = new int[len0];
// initial cost of skipping prefix in String s0
for (int i = 0; i < len0; i++) cost[i] = i;
// dynamically computing the array of distances
// transformation cost for each letter in s1
for (int j = 1; j < len1; j++)
// initial cost of skipping prefix in String s1
newcost[0] = j;
// transformation cost for each letter in s0
for(int i = 1; i < len0; i++)
// matching current letters in both strings
int match = (lhs.charAt(i - 1) == rhs.charAt(j - 1)) ? 0 : 1;
// computing cost for each transformation
int cost_replace = cost[i - 1] + match;
int cost_insert = cost[i] + 1;
int cost_delete = newcost[i - 1] + 1;
// keep minimum cost
newcost[i] = Math.min(Math.min(cost_insert, cost_delete), cost_replace);
// swap cost/newcost arrays
int[] swap = cost; cost = newcost; newcost = swap;
// the distance is the cost for transforming all letters in both strings
return cost[len0 - 1];
在我读过的最新文档中,它说它必须尊重包结构,所以我复制了 QIBM/UserData/OS400/SQLLib/Function/FUNCTIONS 下的 LEVENSHTEIN.class。也尝试在Function下复制它,以防我误解。
还创建了一个 JAR 并像这样注册它
CALL SQLJ.INSTALL_JAR('file:/QIBM/UserData/OS400/SQLLib/Function/testMain.jar','JARFUNCTIONS',0);
我尝试注册 UDF 的方式:
CREATE OR REPLACE FUNCTION DEBUG.LV(
LHS VARCHAR(255) ,
RHS VARCHAR(255) )
RETURNS INTEGER
LANGUAGE JAVA
SPECIFIC DEBUG.LV
NOT DETERMINISTIC
READS SQL DATA
CALLED ON NULL INPUT
EXTERNAL NAME 'JARFUNCTIONS:FUNCTIONS.LEVENSHTEIN.levenshteinDistance'
PARAMETER STYLE JAVA ;
CREATE OR REPLACE FUNCTION DEBUG.LEVENSHTEIN(
LHS VARCHAR(255) ,
RHS VARCHAR(255) )
RETURNS INTEGER
LANGUAGE JAVA
SPECIFIC DEBUG.LEVENSHTEIN
NOT DETERMINISTIC
READS SQL DATA
CALLED ON NULL INPUT
EXTERNAL NAME 'FUNCTIONS.LEVENSHTEIN.levenshteinDistance'
PARAMETER STYLE JAVA ;
CREATE OR REPLACE FUNCTION DEBUG.LEVENSHTEIN(
LHS VARCHAR(255) ,
RHS VARCHAR(255) )
RETURNS INTEGER
LANGUAGE JAVA
SPECIFIC DEBUG.LEVENSHTEIN
NOT DETERMINISTIC
READS SQL DATA
CALLED ON NULL INPUT
EXTERNAL NAME 'LEVENSHTEIN.levenshteinDistance'
PARAMETER STYLE JAVA ;
所有这些都告诉我它在类路径下找不到类,并确保 .class 编译文件在 /QIBM/UserData/OS400/SQLLib/Function 下,并且它实现了必要的接口并且是公开。
根据我的阅读,使用 JAVA 样式参数,我不必扩展 UDF。另外,我的 db2_classes 中的 UDF 是一个类而不是一个接口,所以我必须扩展它而不是实现它。也试过这样做,没有任何变化。
也看到了这种声明风格,所以也尝试了这个:
CREATE OR REPLACE FUNCTION DEBUG.LEVENSHTEIN(
LHS VARCHAR(255) ,
RHS VARCHAR(255) )
RETURNS INTEGER
LANGUAGE JAVA
SPECIFIC DEBUG.LEVENSHTEIN
NOT DETERMINISTIC
READS SQL DATA
CALLED ON NULL INPUT
EXTERNAL NAME 'LEVENSHTEIN!levenshteinDistance'
PARAMETER STYLE JAVA ;
这个告诉我,名称 LEVENSHTEIN 无法从外部名称 LEVENSHTEIN!levenshteinDistance 中识别出来,并且外部名称必须是 package.subpackage.class.method
我在数据库的安全管理员下,理论上我可以创建文件和文件夹(我在 /Function 下创建了一个文件夹,它确实被创建了)
我浏览了十几本红皮书和参考资料,尝试了不同的东西,以至于我什至不记得我尝试过的所有东西。
非常感谢任何帮助。 谢谢
稍后编辑:还尝试使用空构造函数,还扩展 UDF 并使用调用 super() 的构造函数。到目前为止,没有运气
【问题讨论】:
您在各个步骤中遇到哪些错误? @ThorbjørnRavnAndersen 我发布的那些,在复制和声明 UDF 时都没有错误。唯一的错误是在调用 UDF 时出现“未在类路径中找到”或“无法识别” 你在select * from sysibm.SYSJARCONTENTS where JAR_ID = 'JARFUNCTIONS'
找到你的班级吗?
@nfgl 我知道,我可以在那里看到 FUNCTIONS.LEVENSHTEIN,但是在它说类源的地方我得到了一个“-”。不知道这样好不好。
这只是意味着NULL
,我让你的函数在这里工作,并且得到了NULL。您是否尝试使用 select java_home from qsys2.JVM_INFO ji where job_name = QSYS2.job_name
指示的 JRE 从 SQL 外部的可调用类中使用该方法?
【参考方案1】:
错误的 java 方法声明。您忘记了 static
修饰符。参考Java user-defined scalar functions话题。
Java 参数样式
Java 参数样式是SQLJ Part 1 指定的样式: SQL 例程 标准。编写 Java UDF 时,请使用以下内容 约定。
Java 方法必须是公共静态方法。 Java 方法必须返回与 SQL 兼容的类型。返回值是方法的结果。 Java 方法的参数必须是 SQL 兼容类型。 Java 方法可以测试允许空值的 Java 类型的 SQL NULL。
【讨论】:
刚把它改成static int并重新注册它,同样的错误,你是对的,我把它删了也试过了,忘了放回去 在类/jar重新部署后尝试CALL SQLJ.REFRESH_CLASSES ()
。
我做了,删除了调用 SQLJ.REPLACE_JAR 的函数,然后使用 SQLJ.REFRESH_CLASSES() 重新创建了函数,使用 CALL SQLJ.REPLACE_JAR('file:/QIBM/UserData/OS400/ SQLLib/Function/testMain.jar','JARFUNCTIONS');和外部名称 'JARFUNCTIONS:FUNCTIONS.LEVENSHTEIN.levenshteinDistance' 仍然收到错误说无法加载 Java 类 FUNCTIONS/LEVENSHTEIN 错误代码 1 - 在 CLASSPATH 中找不到类
你真的看到CALL SQLJ.xxx_JAR (...)
之后的/QIBM/UserData/OS400/SQLLib/Function/jar/YOUR_SCHEMA/JARFUNCTIONS.jar
文件(YOUR_SCHEMA
特定于你的环境)吗?你怎么称呼这个DEBUG.LEVENSHTEIN
函数?
是的,我可以看到那里的JAR,所以它似乎被注册了。还在 SYSIBM.ROUTINES 中检查了完整的外部名称,它确实包括我的用户 ANDREI.JARFUNCTIONS:FUNCTIONS.LEVENSHTEIN.levenshteinDistance 我定义了两个 UDF,一个带有 JAR,一个带有 CLASS,我以相同的方式调用两者,都尝试了SELECT DEBUG.LEVENSHTEIN('kitten','sitting') FROM MAESTROS.ARTICULO 仅获取前 1 行;并且以防万一 SELECT DEBUG.LEVENSHTEIN(VARCHAR('kitten'),VARCHAR('sitting')) FROM MAESTROS.ARTICULO FETCH FIRST 1 ROWS ONLY;以上是关于DB2 7.2 Java UDF 不在 Classpath 中的主要内容,如果未能解决你的问题,请参考以下文章
如何在 DB2 LUW 中的存储过程或 UDF 中“选择”?