DSL.using(...).selectFrom(TABLE).where(TABLE.COLUMN.in(getRange(1, 2002))).fetch();
getRange(from, to) is a helper method that creates a sequence of integers within the given range.
If I execute this query against an SQL Server database using the jTDS JDBC Driver I will get an exception that looks like this (I simplified the generated SQL for the sake of brevity):
Exception in thread "main" org.jooq.exception.DataAccessException: SQL [select ... from [database].[dbo].[table] where ([database].[dbo].[table].[id] in (?, ?, ?, ...) or [database].[dbo].[table].[id] in (?, ?, ?, ...) or [database].[dbo].[table].[id] in (?, ?)) -- SQL rendered with a free trial version of jOOQ 3.9.1]; Prepared or callable statement has more than 2000 parameter markers.
at org.jooq_3.9.1.SQLSERVER2014.debug(Unknown Source)
at org.jooq.impl.Tools.translate(Tools.java:1983)
at org.jooq.impl.DefaultExecuteContext.sqlException(DefaultExecuteContext.java:676)
at org.jooq.impl.AbstractQuery.execute(AbstractQuery.java:363)
at org.jooq.impl.AbstractResultQuery.fetch(AbstractResultQuery.java:315)
at org.jooq.impl.SelectImpl.fetch(SelectImpl.java:2708)
...
Caused by: java.sql.SQLException: Prepared or callable statement has more than 2000 parameter markers.
at net.sourceforge.jtds.jdbc.SQLParser.parse(SQLParser.java:1254)
...
I faced the same problem in Hibernate and solved it by rewriting the Criteria prior execution, so that this technical detail must not be considered by any developer who creates the query.
In the end the query rewriting algorithm scans the query for in() clauses and replaces the large number of parameters by a subquery (something like select id from temp where correlationId = ...). The subquery uses a so called correlation id for grouping the parameters of the
in() clauses. This peace of code is very sophisticated and it requires an intimate understanding of the Criteria-API and uses reflection. It takes me quite a while to make this stable and to ensure that any kind query (even with nested sub queries) can be transformed correctly.
So I wonder if jOOQ has a built-in solution for this database specific problem.
Or am I forced to reinvent the wheel, hence migrate the algorithm to the API of jOOQ?
Kind regards,
Marcus
--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
//
// Impose a reasonable maximum limit on the number of parameters
// unless the connection is sending statements unprepared (i.e. by
// building a plain query) and this is not a procedure call.
//
if (params != null && params.size() > 255
&& connection.getPrepareSql() != TdsCore.UNPREPARED
&& procName != null) {
int limit = 255; // SQL 6.5 and Sybase < 12.50
if (connection.getServerType() == Driver.SYBASE) {
if (connection.getDatabaseMajorVersion() > 12 ||
connection.getDatabaseMajorVersion() == 12 &&
connection.getDatabaseMinorVersion() >= 50) {
limit = 2000; // Actually 2048 but allow some head room
}
} else {
if (connection.getDatabaseMajorVersion() == 7) {
limit = 1000; // Actually 1024
} else
if (connection.getDatabaseMajorVersion() > 7) {
limit = 2000; // Actually 2100
}
}
if (params.size() > limit) {
throw new SQLException(
Messages.get("error.parsesql.toomanyparams",
Integer.toString(limit)),
"22025");
}
}
HTH, Marcus
SELECT *FROM tableWHERE id IN (SELECT * FROM unnest_tvp(?))
--
DSL.using(DataSource.get(), SQLDialect.SQLSERVER2014)
What am I missing here?
Cheers,
Marcus
List<Integer> ids = ...ids.stream().map(DSL::inline).toArray(new Field[0]));
--
Your suggestion is quite interesting. Is that something the developer writing the SQL must be aware of or is jOOQ smart enough to apply this pattern if the target database is SQL Server (of a version that supports it) and the SQL contains large sets of parameters (as in my example)?