diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index cdc5c7021e..65ea75b8f6 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -61,6 +61,7 @@ import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; @@ -2042,6 +2043,45 @@ public abstract class jOOQAbstractTest< } } + @Test + public void testLargeINCondition() throws Exception { + Field count = create().count(); + assertEquals(1, (int) create().select(count) + .from(TBook()) + .where(TBook_ID().in(Collections.nCopies(999, 1))) + .fetchOne(count)); + + switch (getDialect()) { + case SQLITE: + log.info("SKIPPING", "SQLite can't handle more than 999 variables"); + break; + + default: + assertEquals(1, (int) create().select(count) + .from(TBook()) + .where(TBook_ID().in(Collections.nCopies(1000, 1))) + .fetchOne(count)); + + assertEquals(1, (int) create().select(count) + .from(TBook()) + .where(TBook_ID().in(Collections.nCopies(1001, 1))) + .fetchOne(count)); + + // SQL Server's is at 2100... + assertEquals(1, (int) create().select(count) + .from(TBook()) + .where(TBook_ID().in(Collections.nCopies(2222, 1))) + .fetchOne(count)); + + assertEquals(3, (int) create().select(count) + .from(TBook()) + .where(TBook_ID().notIn(Collections.nCopies(2050, 1))) + .fetchOne(count)); + + break; + } + } + @Test public void testSubSelect() throws Exception { // --------------------------------------------------------------------- diff --git a/jOOQ/src/main/java/org/jooq/impl/InCondition.java b/jOOQ/src/main/java/org/jooq/impl/InCondition.java index 7dccaf9251..c5ee077826 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/InCondition.java @@ -38,6 +38,7 @@ package org.jooq.impl; import java.sql.SQLException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import org.jooq.Attachable; @@ -51,6 +52,7 @@ import org.jooq.RenderContext; class InCondition extends AbstractCondition { private static final long serialVersionUID = -1653924248576930761L; + private static final int IN_LIMIT = 1000; private final Field field; private final Field[] values; @@ -79,13 +81,52 @@ class InCondition extends AbstractCondition { @Override public final void toSQL(RenderContext context) { + List> list = Arrays.asList(values); + + if (list.size() > IN_LIMIT) { + // [#798] Oracle and some other dialects can only hold 1000 values + // in an IN (...) clause + switch (context.getDialect()) { + case ORACLE: + case INGRES: + case SQLSERVER: { + context.sql("("); + + for (int i = 0; i < list.size(); i += IN_LIMIT) { + if (i > 0) { + context.sql(" or "); + } + + toSQLSubValues(context, list.subList(i, Math.min(i + IN_LIMIT, list.size()))); + } + + context.sql(")"); + break; + } + + // Most dialects can handle larger lists + default: { + toSQLSubValues(context, list); + break; + } + } + } + else { + toSQLSubValues(context, list); + } + } + + /** + * Render the SQL for a sub-set of the IN clause's values + */ + private void toSQLSubValues(RenderContext context, List> subValues) { context.sql(field) .sql(" ") .sql(operator.toSQL()) .sql(" ("); String separator = ""; - for (Field value : values) { + for (Field value : subValues) { context.sql(separator); context.sql(value);