H2数据库映射到IBM DB2数据库UDF,用于缺失的功能:STRIP



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

  • Java 8 JDK 321 64 Bit
  • db2 12, DSN 12015
  • H2 version 2.1.212 with

    我正在尝试实现IBM Db2函数:strip() Reference Doc - IBM。这个函数是作为一个更大的select语句的一部分使用子句调用的:STRIP(T2)。Item_type_name_ger, b, ' ')。虽然我可以第一个和最后一个输入参数映射到一个Java函数和调用这个函数作为一个别名H2,我没能弄到第二参数以正确的方式解析为一个字符串或表达式。JDBC/H2引擎总是尝试将其映射到表列:

    
    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;
    }
    

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

不可能在H2中创建带有特殊参数的用户定义函数,而且很可能在所有或几乎所有其他数据库系统中都是如此。用户定义的函数只接受普通的逗号分隔参数与文字或表达式。

(也不能将参数声明为org.h2.expression.Expression)

正确的解决方案是使用SQL标准中的TRIM函数:

https://h2database.com/html/functions.html修剪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。


您也可以尝试创建常数B,BOTH,L,LEADING,TTRAILING与一些值

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

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