From a1cf3910066697f4a2eb7a17d7fa75250dca0103 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 12 Feb 2024 17:53:26 +0100 Subject: [PATCH] [jOOQ/jOOQ#16270] Refactor QualifiedName to improve performance --- .../main/java/org/jooq/impl/AbstractName.java | 13 +- jOOQ/src/main/java/org/jooq/impl/DSL.java | 62 ++++-- .../java/org/jooq/impl/QualifiedName.java | 189 ++++++------------ .../java/org/jooq/impl/UnqualifiedName.java | 6 +- 4 files changed, 120 insertions(+), 150 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractName.java b/jOOQ/src/main/java/org/jooq/impl/AbstractName.java index 69410b3241..c69ba7c89b 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractName.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractName.java @@ -75,15 +75,12 @@ implements public final Name append(Name name) { if (empty()) return name; - else if (name.empty()) + else if (name == null || name.empty()) return this; - - Name[] p1 = parts(); - Name[] p2 = name.parts(); - Name[] array = new Name[p1.length + p2.length]; - System.arraycopy(p1, 0, array, 0, p1.length); - System.arraycopy(p2, 0, array, p1.length, p2.length); - return new QualifiedName(array); + else if (name instanceof UnqualifiedName last) + return new QualifiedName(this, last); + else + return append(name.qualifier()).append(name.unqualifiedName()); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 8081e8776f..7237f90c86 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -12975,10 +12975,15 @@ public class DSL { @NotNull @Support public static Name name(String... qualifiedName) { - if (qualifiedName == null || qualifiedName.length != 1) - return new QualifiedName(qualifiedName); - else - return new UnqualifiedName(qualifiedName[0]); + if (Tools.isEmpty(qualifiedName)) + return new UnqualifiedName(null); + + Name result = new UnqualifiedName(qualifiedName[0]); + + for (int i = 1; i < qualifiedName.length; i++) + result = result.append(new UnqualifiedName(qualifiedName[i])); + + return result; } /** @@ -13011,7 +13016,15 @@ public class DSL { @NotNull @Support public static Name name(Name... nameParts) { - return new QualifiedName(nameParts); + if (Tools.isEmpty(nameParts)) + return new UnqualifiedName(null); + + Name result = nameParts[0] != null ? nameParts[0] : new UnqualifiedName(null); + + for (int i = 1; i < nameParts.length; i++) + result = result.append(nameParts[i]); + + return result; } /** @@ -13076,10 +13089,15 @@ public class DSL { @NotNull @Support public static Name quotedName(String... qualifiedName) { - if (qualifiedName == null || qualifiedName.length != 1) - return new QualifiedName(qualifiedName, Quoted.QUOTED); - else - return new UnqualifiedName(qualifiedName[0], Quoted.QUOTED); + if (Tools.isEmpty(qualifiedName)) + return new UnqualifiedName(null); + + Name result = new UnqualifiedName(qualifiedName[0], Quoted.QUOTED); + + for (int i = 1; i < qualifiedName.length; i++) + result = result.append(new UnqualifiedName(qualifiedName[i], Quoted.QUOTED)); + + return result; } /** @@ -13131,10 +13149,15 @@ public class DSL { @NotNull @Support public static Name unquotedName(String... qualifiedName) { - if (qualifiedName == null || qualifiedName.length != 1) - return new QualifiedName(qualifiedName, Quoted.UNQUOTED); - else - return new UnqualifiedName(qualifiedName[0], Quoted.UNQUOTED); + if (Tools.isEmpty(qualifiedName)) + return new UnqualifiedName(null); + + Name result = new UnqualifiedName(qualifiedName[0], Quoted.UNQUOTED); + + for (int i = 1; i < qualifiedName.length; i++) + result = result.append(new UnqualifiedName(qualifiedName[i], Quoted.UNQUOTED)); + + return result; } /** @@ -13185,10 +13208,15 @@ public class DSL { @NotNull @Support public static Name systemName(String... qualifiedName) { - if (qualifiedName == null || qualifiedName.length != 1) - return new QualifiedName(qualifiedName, Quoted.SYSTEM); - else - return new UnqualifiedName(qualifiedName[0], Quoted.SYSTEM); + if (Tools.isEmpty(qualifiedName)) + return new UnqualifiedName(null); + + Name result = new UnqualifiedName(qualifiedName[0], Quoted.SYSTEM); + + for (int i = 1; i < qualifiedName.length; i++) + result = result.append(new UnqualifiedName(qualifiedName[i], Quoted.SYSTEM)); + + return result; } /** diff --git a/jOOQ/src/main/java/org/jooq/impl/QualifiedName.java b/jOOQ/src/main/java/org/jooq/impl/QualifiedName.java index 7bdbf33200..d49a764694 100644 --- a/jOOQ/src/main/java/org/jooq/impl/QualifiedName.java +++ b/jOOQ/src/main/java/org/jooq/impl/QualifiedName.java @@ -37,16 +37,15 @@ */ package org.jooq.impl; -import static org.jooq.Name.Quoted.DEFAULT; import static org.jooq.Name.Quoted.MIXED; // ... -import static org.jooq.impl.Tools.allMatch; -import static org.jooq.impl.Tools.map; +import static org.jooq.impl.Tools.EMPTY_NAME; +import static org.jooq.impl.Tools.EMPTY_STRING; import static org.jooq.impl.Tools.stringLiteral; import org.jooq.Context; import org.jooq.Name; -import org.jooq.tools.StringUtils; +// ... /** * The default implementation for a qualified SQL identifier. @@ -55,93 +54,27 @@ import org.jooq.tools.StringUtils; */ final class QualifiedName extends AbstractName { - private final UnqualifiedName[] qualifiedName; + final Name qualifier; + final UnqualifiedName last; - QualifiedName(String[] qualifiedName) { - this(qualifiedName, DEFAULT); + QualifiedName(Name qualifier, UnqualifiedName last) { + this.qualifier = qualifier; + this.last = last; } - QualifiedName(String[] qualifiedName, Quoted quoted) { - this(names(qualifiedName, quoted)); - } - QualifiedName(Name[] qualifiedName) { - this(last(nonEmpty(qualifiedName))); - } - private QualifiedName(UnqualifiedName[] qualifiedName) { - this.qualifiedName = qualifiedName; - } - private static final UnqualifiedName[] names(String[] qualifiedName, Quoted quoted) { - return map(nonEmpty(qualifiedName), s -> new UnqualifiedName(s, quoted), UnqualifiedName[]::new); - } - private static final UnqualifiedName[] last(Name[] qualifiedName) { - if (qualifiedName instanceof UnqualifiedName[] u) - return u; - UnqualifiedName[] result = new UnqualifiedName[qualifiedName.length]; - for (int i = 0; i < qualifiedName.length; i++) - if (qualifiedName[i] instanceof QualifiedName q) { - result[i] = q.qualifiedName[q.qualifiedName.length - 1]; - } - else if (qualifiedName[i] instanceof UnqualifiedName u) - result[i] = u; - else - result[i] = new UnqualifiedName(qualifiedName[i].last()); - return result; - } - private static final String[] nonEmpty(String[] qualifiedName) { - String[] result; - int nulls = 0; - for (String name : qualifiedName) - if (StringUtils.isEmpty(name)) - nulls++; - if (nulls > 0) { - result = new String[qualifiedName.length - nulls]; - for (int i = qualifiedName.length - 1; i >= 0; i--) - if (StringUtils.isEmpty(qualifiedName[i])) - nulls--; - else - result[i - nulls] = qualifiedName[i]; - } - else { - result = qualifiedName; - } - return result; - } - private static final Name[] nonEmpty(Name[] names) { - Name[] result; - int nulls = 0; - - for (Name name : names) - if (name == null || name.equals(NO_NAME)) - nulls++; - - if (nulls > 0) { - result = new Name[names.length - nulls]; - - for (int i = names.length - 1; i >= 0; i--) - if (names[i] == null || names[i].equals(NO_NAME)) - nulls--; - else - result[i - nulls] = names[i]; - } - else { - result = names; - } - - return result; - } @Override public final void accept(Context ctx) { @@ -159,97 +92,108 @@ final class QualifiedName extends AbstractName { - // [#3437] Fully qualify this field only if allowed in the current context - if (ctx.qualify()) { - String separator = ""; - - for (UnqualifiedName name : qualifiedName) { - ctx.sql(separator).visit(name); - separator = "."; - } - } - else { - ctx.visit(qualifiedName[qualifiedName.length - 1]); - } + if (ctx.qualify() && qualifier != null) + ctx.visit(qualifier).sql('.').visit(last); + else + ctx.visit(last); } @Override public final String first() { - return qualifiedName.length > 0 ? qualifiedName[0].last() : null; + return qualifier != null ? qualifier.first() : last.name; } @Override public final String last() { - return qualifiedName.length > 0 ? qualifiedName[qualifiedName.length - 1].last() : null; + return last.name; } @Override public final boolean empty() { - return allMatch(qualifiedName, n -> n.empty()); + return last.empty(); } @Override public final boolean qualified() { - return qualifiedName.length > 1; + return qualifier != null; } @Override public final boolean qualifierQualified() { - return qualifiedName.length > 2; + return qualifier != null && qualifier.qualified(); } @Override public final Name qualifier() { - if (qualifiedName.length <= 1) - return null; - if (qualifiedName.length == 2) - return qualifiedName[0]; - - UnqualifiedName[] qualifier = new UnqualifiedName[qualifiedName.length - 1]; - System.arraycopy(qualifiedName, 0, qualifier, 0, qualifier.length); - return new QualifiedName(qualifier); + return qualifier; } @Override public final Name unqualifiedName() { - if (qualifiedName.length == 0) - return this; - else - return qualifiedName[qualifiedName.length - 1]; + return last; } @Override public final Quoted quoted() { - Quoted result = null; - - for (UnqualifiedName name : qualifiedName) - if (result == null) - result = name.quoted(); - else if (result != name.quoted()) - return MIXED; - - return result == null ? DEFAULT : result; + Quoted result = qualifier != null ? qualifier.quoted() : null; + return result == null || result == last.quoted() ? last.quoted() : MIXED; } @Override public final Name quotedName() { - return new QualifiedName(map(qualifiedName, n -> n.quotedName(), Name[]::new)); + return qualifier.quotedName().append(last.quotedName()); } @Override public final Name unquotedName() { - return new QualifiedName(map(qualifiedName, n -> n.unquotedName(), Name[]::new)); + return qualifier.unquotedName().append(last.unquotedName()); } @Override public final String[] getName() { - return map(qualifiedName, n -> n.last(), String[]::new); + if (empty()) + return EMPTY_STRING; + + int i = 1; + Name q = qualifier; + while (q != null) { + q = q.qualifier(); + i++; + } + + String[] name = new String[i]; + name[--i] = last.name; + q = qualifier; + while (q != null) { + name[--i] = q.last(); + q = q.qualifier(); + } + + return name; } @Override public final Name[] parts() { - return qualifiedName.clone(); + if (empty()) + return EMPTY_NAME; + + int i = 1; + Name q = qualifier; + while (q != null) { + q = q.qualifier(); + i++; + } + + Name[] parts = new Name[i]; + parts[--i] = last; + q = qualifier; + while (q != null) { + parts[--i] = q.unqualifiedName(); + q = q.qualifier(); + } + + return parts; } // ------------------------------------------------------------------------ @@ -266,13 +210,12 @@ final class QualifiedName extends AbstractName { if (hash == null) { int h = 1; - for (int i = 0; i < qualifiedName.length; i++) { - UnqualifiedName n = qualifiedName[i]; + h = 31 * h + hashCode0(last); - if (n.name == null) - h = 31 * h + 0; - else - h = 31 * h + hashCode0(n); + Name q = qualifier; + while (q != null) { + h = 31 * h + hashCode0(q.unqualifiedName()); + q = q.qualifier(); } hash = h; diff --git a/jOOQ/src/main/java/org/jooq/impl/UnqualifiedName.java b/jOOQ/src/main/java/org/jooq/impl/UnqualifiedName.java index ea9870810c..905f7e9b3f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/UnqualifiedName.java +++ b/jOOQ/src/main/java/org/jooq/impl/UnqualifiedName.java @@ -42,6 +42,8 @@ import static org.jooq.Name.Quoted.QUOTED; import static org.jooq.Name.Quoted.SYSTEM; import static org.jooq.Name.Quoted.UNQUOTED; // ... +import static org.jooq.impl.Tools.EMPTY_NAME; +import static org.jooq.impl.Tools.EMPTY_STRING; import static org.jooq.impl.Tools.stringLiteral; import java.util.Arrays; @@ -155,12 +157,12 @@ final class UnqualifiedName extends AbstractName { @Override public final String[] getName() { - return new String[] { name }; + return empty() ? EMPTY_STRING : new String[] { name }; } @Override public final Name[] parts() { - return new Name[] { this }; + return empty() ? EMPTY_NAME : new Name[] { this }; } // ------------------------------------------------------------------------