diff --git a/jOOQ/src/main/java/org/jooq/DiagnosticsListener.java b/jOOQ/src/main/java/org/jooq/DiagnosticsListener.java index 849c939d81..2d393bfba3 100644 --- a/jOOQ/src/main/java/org/jooq/DiagnosticsListener.java +++ b/jOOQ/src/main/java/org/jooq/DiagnosticsListener.java @@ -209,6 +209,30 @@ public interface DiagnosticsListener { + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 9cbfec68c3..c32506e408 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -130,6 +130,8 @@ public class Settings protected Boolean diagnosticsUnnecessaryWasNullCall = true; @XmlElement(defaultValue = "true") protected Boolean diagnosticsTrivialCondition = true; + @XmlElement(defaultValue = "true") + protected Boolean diagnosticsNullCondition = true; @XmlElement(defaultValue = "false") protected Boolean transformPatterns = false; @XmlElement(defaultValue = "true") @@ -1435,6 +1437,35 @@ public class Settings this.diagnosticsTrivialCondition = value; } + /** + * Whether to run the {@link org.jooq.DiagnosticsListener#nullConditoin(org.jooq.DiagnosticsContext) diagnostic. + *

+ * Diagnostics are turned off if no {@link org.jooq.Configuration#diagnosticsListenerProviders()} are configured. + * Once configured, this diagnostic is turned on by default. + *

+ * This feature is available in the commercial distribution only. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isDiagnosticsNullCondition() { + return diagnosticsNullCondition; + } + + /** + * Sets the value of the diagnosticsNullCondition property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setDiagnosticsNullCondition(Boolean value) { + this.diagnosticsNullCondition = value; + } + /** * Transform various syntax patterns to better versions, if possible. *

@@ -4818,6 +4849,11 @@ public class Settings return this; } + public Settings withDiagnosticsNullCondition(Boolean value) { + setDiagnosticsNullCondition(value); + return this; + } + public Settings withTransformPatterns(Boolean value) { setTransformPatterns(value); return this; @@ -5854,6 +5890,7 @@ public class Settings builder.append("diagnosticsTooManyRowsFetched", diagnosticsTooManyRowsFetched); builder.append("diagnosticsUnnecessaryWasNullCall", diagnosticsUnnecessaryWasNullCall); builder.append("diagnosticsTrivialCondition", diagnosticsTrivialCondition); + builder.append("diagnosticsNullCondition", diagnosticsNullCondition); builder.append("transformPatterns", transformPatterns); builder.append("transformPatternsLogging", transformPatternsLogging); builder.append("transformPatternsTrim", transformPatternsTrim); @@ -6367,6 +6404,15 @@ public class Settings return false; } } + if (diagnosticsNullCondition == null) { + if (other.diagnosticsNullCondition!= null) { + return false; + } + } else { + if (!diagnosticsNullCondition.equals(other.diagnosticsNullCondition)) { + return false; + } + } if (transformPatterns == null) { if (other.transformPatterns!= null) { return false; @@ -7602,6 +7648,7 @@ public class Settings result = ((prime*result)+((diagnosticsTooManyRowsFetched == null)? 0 :diagnosticsTooManyRowsFetched.hashCode())); result = ((prime*result)+((diagnosticsUnnecessaryWasNullCall == null)? 0 :diagnosticsUnnecessaryWasNullCall.hashCode())); result = ((prime*result)+((diagnosticsTrivialCondition == null)? 0 :diagnosticsTrivialCondition.hashCode())); + result = ((prime*result)+((diagnosticsNullCondition == null)? 0 :diagnosticsNullCondition.hashCode())); result = ((prime*result)+((transformPatterns == null)? 0 :transformPatterns.hashCode())); result = ((prime*result)+((transformPatternsLogging == null)? 0 :transformPatternsLogging.hashCode())); result = ((prime*result)+((transformPatternsTrim == null)? 0 :transformPatternsTrim.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/DiagnosticsConnection.java b/jOOQ/src/main/java/org/jooq/impl/DiagnosticsConnection.java index 700fd396d9..68cfe416e9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DiagnosticsConnection.java +++ b/jOOQ/src/main/java/org/jooq/impl/DiagnosticsConnection.java @@ -38,6 +38,7 @@ package org.jooq.impl; import static java.lang.Boolean.FALSE; +import static java.util.Collections.synchronizedMap; // ... import static org.jooq.conf.ParamType.FORCE_INDEXED; @@ -46,20 +47,22 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.function.Predicate; import java.util.Set; +import java.util.function.Predicate; +import org.jooq.Condition; import org.jooq.Configuration; import org.jooq.Parser; +// ... import org.jooq.Queries; import org.jooq.QueryPart; import org.jooq.RenderContext; +// ... import org.jooq.conf.Settings; import org.jooq.impl.QOM.Eq; import org.jooq.tools.jdbc.DefaultConnection; @@ -73,7 +76,6 @@ final class DiagnosticsConnection extends DefaultConnection { static final int LRU_SIZE_GLOBAL = 50000; static final int LRU_SIZE_LOCAL = 500; static final int DUP_SIZE = 500; - static final Map> DUPLICATE_SQL = Collections.synchronizedMap(new LRU<>(LRU_SIZE_GLOBAL)); final Map> repeatedSQL = new LRU<>(LRU_SIZE_LOCAL); final Configuration configuration; @@ -168,13 +170,27 @@ final class DiagnosticsConnection extends DefaultConnection { return !FALSE.equals(test.test(configuration.settings())); } + @SuppressWarnings("unchecked") + final Map> duplicateSql() { + return (Map>) configuration.data().computeIfAbsent( + "org.jooq.diagnostics.duplicate-sql", + k -> synchronizedMap(new LRU<>(LRU_SIZE_GLOBAL)) + ); + } + final String parse(String sql) { Queries queries = null; + Queries transformed = null; String normalised; try { - queries = parser.parse(sql); - normalised = normalisingRenderer.render(queries); + + // [#14137] TODO: Avoid unnecessary work, depending on the Settings + transformed = queries = parser.parse(sql); + + + + normalised = normalisingRenderer.render(transformed); } catch (ParserException exception) { normalised = sql; @@ -186,10 +202,7 @@ final class DiagnosticsConnection extends DefaultConnection { try { if (check(Settings::isDiagnosticsDuplicateStatements)) { - Set duplicates = null; - synchronized (DUPLICATE_SQL) { - duplicates = duplicates(DUPLICATE_SQL, sql, normalised); - } + Set duplicates = duplicates(duplicateSql(), sql, normalised); if (duplicates != null) listeners.duplicateStatements(new DefaultDiagnosticsContext( @@ -223,6 +236,11 @@ final class DiagnosticsConnection extends DefaultConnection { + + + + + @@ -244,16 +262,25 @@ final class DiagnosticsConnection extends DefaultConnection { return sql; } - private Set duplicates(Map> map, String sql, String normalised) { - Set v = map.computeIfAbsent(normalised, k -> new HashSet<>()); - if (v.size() >= DUP_SIZE || (v.add(sql) && v.size() > 1)) - return v; - else - return null; + + + + + + + private final Set duplicates(Map> map, String sql, String normalised) { + synchronized (map) { + Set v = map.computeIfAbsent(normalised, k -> new HashSet<>()); + + if (v.size() >= DUP_SIZE || (v.add(sql) && v.size() > 1)) + return v; + else + return null; + } } - private List repetitions(Map> map, String sql, String normalised) { + private final List repetitions(Map> map, String sql, String normalised) { List v = map.computeIfAbsent(normalised, k -> new ArrayList<>()); if (v.size() >= DUP_SIZE || (v.add(sql) && v.size() > 1)) @@ -263,7 +290,7 @@ final class DiagnosticsConnection extends DefaultConnection { } // See https://stackoverflow.com/a/1953516/521799 - static class LRU extends LinkedHashMap { + static final class LRU extends LinkedHashMap { private final int size; LRU(int size) { diff --git a/jOOQ/src/main/java/org/jooq/impl/DiagnosticsListeners.java b/jOOQ/src/main/java/org/jooq/impl/DiagnosticsListeners.java index bb7407b1ff..648f5ea96c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DiagnosticsListeners.java +++ b/jOOQ/src/main/java/org/jooq/impl/DiagnosticsListeners.java @@ -120,6 +120,13 @@ final class DiagnosticsListeners implements DiagnosticsListener { + + + + + + + @Override public final void exception(DiagnosticsContext ctx) { for (DiagnosticsListener listener : listeners) diff --git a/jOOQ/src/main/java/org/jooq/impl/Patterns.java b/jOOQ/src/main/java/org/jooq/impl/Patterns.java index 72afcade8c..0f93ff8833 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Patterns.java +++ b/jOOQ/src/main/java/org/jooq/impl/Patterns.java @@ -1683,6 +1683,9 @@ package org.jooq.impl; + + + diff --git a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd index f4c4582e93..b2981403b9 100644 --- a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd +++ b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd @@ -330,6 +330,15 @@ Once configured, this diagnostic is turned on by default. This feature is available in the commercial distribution only.]]> + + +Diagnostics are turned off if no {@link org.jooq.Configuration#diagnosticsListenerProviders()} are configured. +Once configured, this diagnostic is turned on by default. +

+This feature is available in the commercial distribution only.]]> + +