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 中的主要内容,如果未能解决你的问题,请参考以下文章

从外部 UDF 调用 db2ReadLog

DB2 UDF 异常处理

如何在 DB2 LUW 中的存储过程或 UDF 中“选择”?

如何显示 DB2 SQL UDF 的源代码

iSeries DB2 SQL - 使用 CASE 语句更新 UDF 中的变量

spark UDF Java 错误:方法 col([class java.util.ArrayList]) 不存在