In a project I have inherited, there is a prepared statement defined as:
<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>
This SQL statements works fine at runtime, with a Sybase ASE
database.
But the JUnit that executes it (as part of the build), keeps failing with
java.sql.SQLSyntaxErrorException: type not found or user lacks privilege: FILE_DATA_SHORT
I tracked this error to the CASE THEN convert statement:
CASE WHEN file_data_long is null THEN convert (image, file_data_short) ELSE file_data_long END AS fileData
That is, the following prepared statement, does NOT produce said error:
<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>
Suspecting this may have to do with convert
, I came across this SO answer which suggests that to run HSQLDB with the a non-HSQLDB dialect one must first enable that syntax compatibility mode on HSQLDB.
A similar hint was found in this SO answer.
With that I have been able to find Sybase specific directive in the hsqldb.org doc:
"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"
Well, I did just that, adding sql.syntax_mss=true
to the project's HSDLDB properties:
HSQLDB(org.hsqldb.jdbc.JDBCDriver.class, org.hsqldb.jdbc.JDBCDataSource.class, "jdbc:hsqldb:mem:mymemdb;sql.syntax_mss=true", new TestMapperHsqlDB(), true)
But that didn't help: I am still getting that dreaded exception when running the JUnit test (only then. That query runs fine at runtime or from DBeaver).
Any idea what else I could be missing in attempting to make this work for both runtime (Sybase/ASE) and JUnit (HSDLDB)?
Answering my own question, for the benefit of others who may be perplexed by a similar encounter:
After attempting the syntax/dialect modifier (see OP), I found this list of HSQLDB built it in functions, where the 'image' is not a supported type by HSQLDB, so convert
has no chance of succeeding...
That prompted me to look for a solution/workaround where the SQL itself would be slightly different based on the database on which it is running:
<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>
And this -- works like a charm.