diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java index 6adc08b04c..f731ceb212 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java @@ -105,8 +105,8 @@ import org.jooq.conf.RenderImplicitJoinType; import org.jooq.conf.Settings; import org.jooq.conf.SettingsTools; import org.jooq.conf.StatementType; +import org.jooq.impl.QOM.UEmpty; import org.jooq.impl.Tools.DataKey; -import org.jooq.impl.Tools.ScopeStackPart; /** @@ -233,7 +233,14 @@ abstract class AbstractContext> extends AbstractScope imple ? CastMode.NEVER : CastMode.DEFAULT; this.languageContext = LanguageContext.QUERY; - this.scopeStack = new ScopeStack(ScopeStackElement::new); + this.scopeStack = new ScopeStack((k, v) -> { + if (k == DataKeyScopeStackPart.INSTANCE) + return new DataKeyScopeStackElement(k, v); + else if (k == ScopeDefinerScopeStackPart.INSTANCE) + return new ScopeDefinerScopeStackElement(k, v); + else + return new DefaultScopeStackElement(k, v); + }); } // ------------------------------------------------------------------------ @@ -824,17 +831,17 @@ abstract class AbstractContext> extends AbstractScope imple @Override public final C scopeStart(QueryPart part) { scopeStack.scopeStart(); - ScopeStackElement e = scopeStack.getOrCreate(ScopeStackPart.INSTANCE); - e.scopeDefiner = part; + if (part != null) + ((ScopeDefinerScopeStackElement) scopeStack.getOrCreate(ScopeDefinerScopeStackPart.INSTANCE)).scopeDefiner = part; scopeStart0(); - resetDataKeys(e); + resetDataKeys((DataKeyScopeStackElement) scopeStack.getOrCreate(DataKeyScopeStackPart.INSTANCE)); return (C) this; } @Override public final QueryPart scopePart() { - ScopeStackElement e = scopeStack.get(ScopeStackPart.INSTANCE); + ScopeDefinerScopeStackElement e = ((ScopeDefinerScopeStackElement) scopeStack.get(ScopeDefinerScopeStackPart.INSTANCE)); return e != null ? e.scopeDefiner : null; } @@ -886,7 +893,7 @@ abstract class AbstractContext> extends AbstractScope imple @Override public final C scopeEnd() { - restoreDataKeys(scopeStack.getOrCreate(ScopeStackPart.INSTANCE)); + restoreDataKeys((DataKeyScopeStackElement) scopeStack.getOrCreate(DataKeyScopeStackPart.INSTANCE)); scopeEnd0(); scopeStack.scopeEnd(); @@ -899,7 +906,7 @@ abstract class AbstractContext> extends AbstractScope imple void scopeMarkEnd0(@SuppressWarnings("unused") QueryPart part) {} void scopeEnd0() {} - final void resetDataKeys(ScopeStackElement e) { + final void resetDataKeys(DataKeyScopeStackElement e) { for (int i = 0; i < DATAKEY_RESET_IN_SUBQUERY_SCOPE.length; i++) { DataKey key = DATAKEY_RESET_IN_SUBQUERY_SCOPE[i]; @@ -908,7 +915,7 @@ abstract class AbstractContext> extends AbstractScope imple } } - final void restoreDataKeys(ScopeStackElement e) { + final void restoreDataKeys(DataKeyScopeStackElement e) { for (int i = 0; i < DATAKEY_RESET_IN_SUBQUERY_SCOPE.length; i++) { DataKey key = DATAKEY_RESET_IN_SUBQUERY_SCOPE[i]; @@ -1302,22 +1309,83 @@ abstract class AbstractContext> extends AbstractScope imple } } - static class ScopeStackElement { + abstract static class ScopeStackElement { final int scopeLevel; final QueryPart part; - QueryPart scopeDefiner; QueryPart mapped; int[] positions; int bindIndex; int indent; JoinNode joinNode; - List restoreDataKeys; ScopeStackElement(QueryPart part, int scopeLevel) { this.part = part; this.mapped = part; this.scopeLevel = scopeLevel; } + } + + static abstract class AbstractScopeStackPart extends AbstractQueryPart implements UEmpty { + + @Override + public final void accept(Context ctx) {} + + @Override + public boolean equals(Object that) { + return this == that; + } + + @Override + public int hashCode() { + return 0; + } + + @Override + public String toString() { + return getClass().getSimpleName(); + } + } + + static final class DataKeyScopeStackPart extends AbstractScopeStackPart { + static final DataKeyScopeStackPart INSTANCE = new DataKeyScopeStackPart(); + private DataKeyScopeStackPart() {} + } + + static final class ScopeDefinerScopeStackPart extends AbstractScopeStackPart { + static final ScopeDefinerScopeStackPart INSTANCE = new ScopeDefinerScopeStackPart(); + private ScopeDefinerScopeStackPart() {} + } + + static final class DataKeyScopeStackElement extends ScopeStackElement { + List restoreDataKeys; + + DataKeyScopeStackElement(QueryPart part, int scopeLevel) { + super(part, scopeLevel); + } + + @Override + public String toString() { + return "RestoreDataKeys [" + restoreDataKeys + "]"; + } + } + + static final class ScopeDefinerScopeStackElement extends ScopeStackElement { + QueryPart scopeDefiner; + + ScopeDefinerScopeStackElement(QueryPart part, int scopeLevel) { + super(part, scopeLevel); + } + + @Override + public String toString() { + return "" + scopeDefiner; + } + } + + static final class DefaultScopeStackElement extends ScopeStackElement { + DefaultScopeStackElement(QueryPart part, int scopeLevel) { + super(part, scopeLevel); + } @Override public String toString() { @@ -1326,15 +1394,10 @@ abstract class AbstractContext> extends AbstractScope imple if (positions != null) sb.append(Arrays.toString(positions)); - if (part instanceof ScopeStackPart) { - sb.append(scopeDefiner); - } - else { - sb.append(part); + sb.append(part); - if (mapped != null) - sb.append(" (" + mapped + ")"); - } + if (mapped != null) + sb.append(" (" + mapped + ")"); return sb.toString(); } diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultPolicyProvider.java b/jOOQ/src/main/java/org/jooq/impl/DefaultPolicyProvider.java index 1891fef607..6e4c7e6117 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultPolicyProvider.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultPolicyProvider.java @@ -86,6 +86,11 @@ package org.jooq.impl; + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 1244d20e88..94369fbaba 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -2335,7 +2335,8 @@ final class SelectQueryImpl extends AbstractResultQuery imp '(', alternativeFields != null ? alternativeFields : getSelect(), derivedTableRequired(context, this), - unionParensRequired = unionOpNesting || unionParensRequired(context) + unionParensRequired = unionOpNesting || unionParensRequired(context), + null ); } } @@ -2678,7 +2679,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp // SET operations like UNION, EXCEPT, INTERSECT // -------------------------------------------- if (unionOpSize > 0) { - unionParenthesis(context, ')', null, derivedTableRequired(context, this), unionParensRequired); + unionParenthesis(context, ')', null, derivedTableRequired(context, this), unionParensRequired, null); for (int i = 0; i < unionOpSize; i++) { CombineOperator op = unionOp.get(i); @@ -2695,14 +2696,14 @@ final class SelectQueryImpl extends AbstractResultQuery imp else context.formatSeparator(); - unionParenthesis(context, '(', other.getSelect(), derivedTableRequired, otherUnionParensRequired); + unionParenthesis(context, '(', other.getSelect(), derivedTableRequired, otherUnionParensRequired, other); context.visit(other); - unionParenthesis(context, ')', null, derivedTableRequired, otherUnionParensRequired); + unionParenthesis(context, ')', null, derivedTableRequired, otherUnionParensRequired, null); } // [#1658] Close parentheses opened previously if (i < unionOpSize - 1) - unionParenthesis(context, ')', null, derivedTableRequired(context, this), unionParensRequired); + unionParenthesis(context, ')', null, derivedTableRequired(context, this), unionParensRequired, null); switch (unionOp.get(i)) { case EXCEPT: context.end(SELECT_EXCEPT); break; @@ -3563,10 +3564,11 @@ final class SelectQueryImpl extends AbstractResultQuery imp char parenthesis, List> fields, boolean derivedTableRequired, - boolean parensRequired + boolean parensRequired, + QueryPart subquery ) { if ('(' == parenthesis) - ((AbstractContext) ctx).subquery0(true, true, null); + ((AbstractContext) ctx).subquery0(true, true, subquery); else if (')' == parenthesis) ((AbstractContext) ctx).subquery0(false, true, null); diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 418cb68309..1631b3544c 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -421,31 +421,6 @@ final class Tools { // Some constants for use with Context.data() // ------------------------------------------------------------------------ - static final class ScopeStackPart extends AbstractQueryPart implements UEmpty { - - static final ScopeStackPart INSTANCE = new ScopeStackPart(); - - private ScopeStackPart() {} - - @Override - public final void accept(Context ctx) {} - - @Override - public boolean equals(Object that) { - return this == that; - } - - @Override - public int hashCode() { - return 0; - } - - @Override - public String toString() { - return "SCOPE_STACK_PART"; - } - } - /** * A common super types for {@link BooleanDataKey}, {@link SimpleDataKey} and {@link ExtendedDataKey} */