H2 DBMap到IBM DB2数据库UDF以查找缺少的函数:条带

uplii1fm  于 2022-11-07  发布在  DB2
关注(0)|答案(1)|浏览(193)

我正在尝试为一个大型代码库设置一个单元测试环境。对于这些单元测试,我使用H2数据库而不是IBM DB2数据库,后者在生产中使用,并且我已经实现了一些UDF来将IBM DB2相关函数Map到H2数据库。关于项目的更多详细信息:

  • Java 8 JDK 321 64位
  • db2 12,数据序列号12015
  • H2版本2.1.212,其中〈模式=DB2;默认空排序=高;

我正在尝试实现IBM Db2函数:strip()Reference Doc - IBM。此函数作为包含以下子句的更大select语句的一部分调用:STRIP(T2.ITEM_TYPE_NAME_GER,B,' ')。虽然我可以将第一个和最后一个输入参数Map到一个Java函数,并在H2中将此函数作为ALIAS调用,但我无法将第二个参数以正确的方式解释为String或Expression。JDBC/H2引擎总是尝试将其Map到一个表列:

org.h2.jdbc.JdbcSQLSyntaxErrorException: Feld "B" nicht gefunden
    Column "B" not found; SQL statement:
    SELECT T1.ITEM_TYPE_KEY,T1.SUPER_ITM_TYPE_KEY,T2.ITM_TYPE_KEY_TRANS,T2.ITEM_TYPE_NAME,T2.COMPLEX_FLAG,T2.ITEM_CATEGORY,T2.HEADER_FLAG,T2.HEADER_NO ,T2.LEVEL_NO,strip(T2.ITEM_TYPE_NAME_GER, B, ' ') ,T2.LEVEL1_DISPLAY FROM      public.AA752T      T1,   public.AA743T            T2 WHERE          T1.ITEM_TYPE_KEY NOT IN ('F4CO', 'F4CB', 'F4RB', 'F4SO', 'F4SB', 'F4RO') AND T1.ITEM_TYPE_KEY = T2.ITEM_TYPE_KEY ORDER BY T2.HEADER_NO,T2.HEADER_FLAG DESC,T2.LEVEL_NO,T1.SUPER_ITM_TYPE_KEY,T2.LEVEL_PRIORITY [42122-212]
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:502)
        at org.h2.message.DbException.getJdbcSQLException(DbException.java:477)
        at org.h2.message.DbException.get(DbException.java:223)
        at org.h2.message.DbException.get(DbException.java:199)
        at org.h2.expression.ExpressionColumn.getColumnException(ExpressionColumn.java:244)
        at org.h2.expression.ExpressionColumn.optimizeOther(ExpressionColumn.java:226)
        at org.h2.expression.ExpressionColumn.optimize(ExpressionColumn.java:213)
        at org.h2.expression.function.JavaFunction.optimize(JavaFunction.java:59)
        at org.h2.command.query.Select.prepareExpressions(Select.java:1170)
        at org.h2.command.query.Query.prepare(Query.java:218)
        at org.h2.command.Parser.prepareCommand(Parser.java:574)
        at org.h2.engine.SessionLocal.prepareLocal(SessionLocal.java:631)
        at org.h2.engine.SessionLocal.prepareCommand(SessionLocal.java:554)
        at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1116)
        at org.h2.jdbc.JdbcPreparedStatement.(JdbcPreparedStatement.java:92)
        at org.h2.jdbc.JdbcConnection.prepareStatement(JdbcConnection.java:288)
        at com.db.cib.gbd.gps.pbs.pricing.StaticItemDetails.retriveItemDisplayDetails(StaticItemDetails.java:920)

这是我的Java UDF:

public static String strip(String s, Expression loc, String trimConstant) {

    if (loc.toLowerCase() == "b" || loc.toLowerCase() == "both") {
        s = s.replaceAll("^[" + trimConstant + "]+|[ \t]+$", "");
    } else if (loc.toLowerCase() == "l" || loc.toLowerCase() == "leading") {
        s = s.replaceAll("^[" + trimConstant + "]+", "");
    } else if (loc.toLowerCase() == "t" || loc.toLowerCase() == "trailing") {
        s = s.replaceAll("[" + trimConstant + "]+$", "");
    }
    return s;
}

是否有可能以正确的方式获得列的Map,或者您是否可以建议一个可用作UDF别名的SQL函数(如何使用?)或解决此错误的方法?要避免此问题:我无法更改现有的sql语句。我必须为此函数找到别名。

xqkwcwgp

xqkwcwgp1#

在H2中不可能创建带有特殊参数的用户定义函数,在所有或几乎所有其他数据库系统中也是如此。用户定义函数只接受普通的逗号分隔的参数,参数中包含文字或表达式。
(You也不能将参数声明为org.h2.expression.Expression。)
此处正确的解决方案是使用SQL标准中的TRIM函数:
https://h2database.com/html/functions.html#trim
https://www.ibm.com/docs/en/db2-for-zos/11?topic=functions-trim

TRIM(BOTH ' ' FROM T2.ITEM_TYPE_NAME_GER)

请注意,首字母缩略词BLT是DB2特定的扩展,在H2中只能使用标准的BOTHLEADINGTRAILING
如果你不能改变你的查询,你只能修改H2的源代码,并编译它自己的版本,支持STRIP。但实际上你可能会立即遇到一些其他的问题。当你想一次使用多个数据库系统时,你需要意识到它们彼此之间有很大的不同。H2为其他系统提供了兼容模式。但即使在这些模式中,兼容性也非常有限,这意味着您需要避免使用供应商特定的函数和其他语法元素,并且在某些情况下,可能需要为不同的系统使用不同的SQL。
您还可以尝试创建具有某些值的常量BBOTHLLEADINGTTRAILING

CREATE CONSTANT B VALUE 1;
CREATE CONSTANT BOTH VALUE 1;
CREATE CONSTANT L VALUE 2;
…

并创建一个具有三个参数的函数,第二个参数的类型将是int(或者其他,如果您决定选择其他数据类型的值)。但是常量的名称可能会与列名冲突,因此这种解决方法远非完美,在某些查询中可能根本不起作用。

相关问题