[#798] Oracle IN (...) with more than 1000 arguments won't work

This commit is contained in:
Lukas Eder 2011-08-21 10:40:25 +00:00
parent 7c858fa402
commit a35e9466ed
2 changed files with 82 additions and 1 deletions

View File

@ -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<Integer> 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 {
// ---------------------------------------------------------------------

View File

@ -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<T> extends AbstractCondition {
private static final long serialVersionUID = -1653924248576930761L;
private static final int IN_LIMIT = 1000;
private final Field<T> field;
private final Field<?>[] values;
@ -79,13 +81,52 @@ class InCondition<T> extends AbstractCondition {
@Override
public final void toSQL(RenderContext context) {
List<Field<?>> 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 <code>IN</code> clause's values
*/
private void toSQLSubValues(RenderContext context, List<Field<?>> 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);