[#5960] [#7095] Add Settings.inListPadBase and use it in diagnostic

- [#5960] Add diagnostic to detect duplicate IN lists of different degree
- [#7095] Add Settings.inListPadBase
This commit is contained in:
lukaseder 2018-01-24 23:07:36 +01:00
parent b2e4cadf8a
commit af2e6acf6a
4 changed files with 62 additions and 10 deletions

View File

@ -102,6 +102,8 @@ public class Settings
protected Boolean debugInfoOnStackTrace = true;
@XmlElement(defaultValue = "false")
protected Boolean inListPadding = false;
@XmlElement(defaultValue = "2")
protected Integer inListPadBase = 2;
@XmlElement(defaultValue = ";")
protected String delimiter = ";";
@XmlElement(defaultValue = "LOG_DEBUG")
@ -871,7 +873,7 @@ public class Settings
}
/**
* [#5600] Whether IN lists in IN predicates should be padded to powers of 2.
* [#5600] Whether IN lists in IN predicates should be padded to powers of inListPadBase (default 2).
*
* @return
* possible object is
@ -894,6 +896,30 @@ public class Settings
this.inListPadding = value;
}
/**
* [#7095] The base to use to calculate the powers of when applying in list padding.
*
* @return
* possible object is
* {@link Integer }
*
*/
public Integer getInListPadBase() {
return inListPadBase;
}
/**
* Sets the value of the inListPadBase property.
*
* @param value
* allowed object is
* {@link Integer }
*
*/
public void setInListPadBase(Integer value) {
this.inListPadBase = value;
}
/**
* [#5826] The delimiter character to be used to delimit statements in batches.
*
@ -1121,6 +1147,11 @@ public class Settings
return this;
}
public Settings withInListPadBase(Integer value) {
setInListPadBase(value);
return this;
}
public Settings withDelimiter(String value) {
setDelimiter(value);
return this;

View File

@ -66,7 +66,7 @@ final class DiagnosticsConnection extends DefaultConnection {
static final Map<String, Set<String>> DUPLICATE_SQL = Collections.synchronizedMap(new LRU());
final Configuration configuration;
final RenderContext forceIndexed;
final RenderContext duplicates;
final Parser parser;
final DiagnosticsListeners listeners;
@ -75,7 +75,16 @@ final class DiagnosticsConnection extends DefaultConnection {
super(configuration.connectionProvider().acquire());
this.configuration = configuration;
this.forceIndexed = configuration.derive(SettingsTools.clone(configuration.settings()).withParamType(FORCE_INDEXED)).dsl().renderContext();
this.duplicates = configuration.derive(
SettingsTools.clone(configuration.settings())
// Forcing all inline parameters to be indexed helps find opportunities to use bind variables
.withParamType(FORCE_INDEXED)
// Padding IN lists shows duplicates that arise from arbitrary-length dynamic IN lists
.withInListPadding(true)
.withInListPadBase(16)
).dsl().renderContext();
this.parser = configuration.dsl().parser();
this.listeners = DiagnosticsListeners.get(configuration);
}
@ -145,7 +154,6 @@ final class DiagnosticsConnection extends DefaultConnection {
configuration.connectionProvider().release(getDelegate());
}
@SuppressWarnings("deprecation")
final String parse(String sql) {
Queries queries;
@ -156,7 +164,7 @@ final class DiagnosticsConnection extends DefaultConnection {
return sql;
}
String normalised = forceIndexed.render(queries);
String normalised = duplicates.render(queries);
List<String> duplicates = null;
synchronized (DUPLICATE_SQL) {

View File

@ -39,6 +39,12 @@
package org.jooq.impl;
import static java.lang.Boolean.TRUE;
import static java.lang.Math.ceil;
import static java.lang.Math.log;
import static java.lang.Math.max;
import static java.lang.Math.min;
import static java.lang.Math.pow;
import static java.lang.Math.round;
import static org.jooq.Clause.CONDITION;
import static org.jooq.Clause.CONDITION_IN;
import static org.jooq.Clause.CONDITION_NOT_IN;
@ -52,6 +58,7 @@ import static org.jooq.impl.DSL.falseCondition;
import static org.jooq.impl.DSL.trueCondition;
import static org.jooq.impl.Keywords.K_AND;
import static org.jooq.impl.Keywords.K_OR;
import static org.jooq.tools.StringUtils.defaultIfNull;
import java.util.AbstractList;
import java.util.Arrays;
@ -156,7 +163,8 @@ final class InCondition<T> extends AbstractCondition {
return ctx.paramType() == INDEXED && TRUE.equals(ctx.settings().isInListPadding())
? new PaddedList<Field<?>>(list, REQUIRES_IN_LIMIT.contains(ctx.family())
? IN_LIMIT
: Integer.MAX_VALUE)
: Integer.MAX_VALUE,
defaultIfNull(ctx.settings().getInListPadBase(), 2))
: list;
}
@ -196,11 +204,12 @@ final class InCondition<T> extends AbstractCondition {
private final int realSize;
private final int padSize;
PaddedList(List<T> delegate, int maxPadding) {
PaddedList(List<T> delegate, int maxPadding, int padBase) {
int b = max(2, padBase);
this.delegate = delegate;
this.realSize = delegate.size();
int r = Integer.highestOneBit(realSize);
this.padSize = Math.min(maxPadding, r == realSize ? realSize : r << 1);
this.padSize = min(maxPadding, (int) round(pow(b, ceil(log(realSize) / log(b)))));
}
@Override

View File

@ -172,7 +172,11 @@ jOOQ queries, for which no specific fetchSize value was specified.]]></jxb:javad
</element>
<element name="inListPadding" type="boolean" minOccurs="0" maxOccurs="1" default="false">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#5600] Whether IN lists in IN predicates should be padded to powers of 2.]]></jxb:javadoc></jxb:property></appinfo></annotation>
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#5600] Whether IN lists in IN predicates should be padded to powers of inListPadBase (default 2).]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="inListPadBase" type="int" minOccurs="0" maxOccurs="1" default="2">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[[#7095] The base to use to calculate the powers of when applying in list padding.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="delimiter" type="string" minOccurs="0" maxOccurs="1" default=";">