Sybase ASE 到 HSQLDB JUnit java.sql.SQLSyntaxErrorException: 找不到类型或用户缺少权限

Sybase ASE to HSQLDB JUnit java.sql.SQLSyntaxErrorException: type not found or user lacks privilege

在我继承的一个项目中,有一个prepared statement定义为:

<select id="GET_FILE_BY_FILE_ID" parameterType="long" resultType="com.employer.my.File" statementType="PREPARED">
  SELECT  
    file_id fileId,
    file_name name,
    file_type type,
    CASE WHEN file_data_long is null THEN convert (image, file_data_short) ELSE file_data_long END AS fileData
    FROM FILES_TABLE
    WHERE file_id = #{id}
</select>

此 SQL 语句在 运行 时使用 Sybase ASE 数据库运行良好。

但是执行它的 JUnit(作为构建的一部分)一直失败

java.sql.SQLSyntaxErrorException: type not found or user lacks privilege: FILE_DATA_SHORT

我将此错误跟踪到 CASE THEN 转换语句:

    CASE WHEN file_data_long is null THEN convert (image, file_data_short) ELSE file_data_long END AS fileData

也就是说,以下准备好的语句不会产生上述错误:

<select id="GET_FILE_BY_FILE_ID" parameterType="long" resultType="com.employer.my.File" statementType="PREPARED">
  SELECT  
    file_id fileId,
    file_name name,
    file_type type,
    file_data_short fileData
    FROM FILES_TABLE
    WHERE file_id = #{id}
</select>

怀疑这可能与 convert 有关,我发现 这表明 运行 HSQLDB 与非 HSQLDB 方言必须首先在 HSQLDB 上启用该语法兼容模式。

this SO answer 中发现了类似的提示。

这样我就可以在 the hsqldb.org doc:

中找到特定于 Sybase 的指令

"Use SET DATABASE SQL SYNTAX MSS TRUE or the equivalent URL property sql.syntax_mss=true to enable support for the CONVERT(<type definition>, <expression) function with switched order of arguments"

好吧,我就是这样做的,将 sql.syntax_mss=true 添加到项目的 HSDLDB 属性中:

HSQLDB(org.hsqldb.jdbc.JDBCDriver.class, org.hsqldb.jdbc.JDBCDataSource.class, "jdbc:hsqldb:mem:mymemdb;sql.syntax_mss=true", new TestMapperHsqlDB(), true)

但这并没有帮助:当 运行 进行 JUnit 测试时,我仍然遇到那个可怕的异常(只有那时。那个查询 运行 在 运行 时间或来自 DBeaver)。

想知道我在尝试使这项工作同时适用于 运行time (Sybase/ASE) 和 JUnit (HSDLDB) 时还可能遗漏什么吗?

回答我自己的问题,以造福于可能因类似遭遇而感到困惑的其他人:

在尝试使用 syntax/dialect 修饰符(参见 OP)后,我发现 this list of HSQLDB built it in functions,其中 'image' 不是 HSQLDB 支持的类型,因此 convert没有机会成功...

这促使我寻找 solution/workaround,其中 SQL 本身会根据其所在的数据库略有不同 运行:

<select id="GET_FILE_BY_FILE_ID" parameterType="long" resultType="com.employer.my.File" statementType="PREPARED">
  SELECT  
    file_id fileId,
    file_name name,
    file_type type,
    <if test="_databaseId == 'SYBASE'">
      CASE WHEN file_data_long is null THEN convert (image, file_data_short) ELSE file_data_long END AS fileData
    </if>  
    <if test="_databaseId == 'HSQLDB'">
        CASE WHEN FFT.file_data_long is null  THEN FFT.file_data_short  ELSE FFT.file_data_long  END AS fileData
    </if>
    FROM FILES_TABLE FFT
    WHERE file_id = #{id}
</select>

这 -- 很有魅力。