diff --git a/jOOQ-test/src/org/jooq/test/_/listeners/PrettyPrinter.java b/jOOQ-test/src/org/jooq/test/_/listeners/PrettyPrinter.java
index 67d966625a..4d48e428ac 100644
--- a/jOOQ-test/src/org/jooq/test/_/listeners/PrettyPrinter.java
+++ b/jOOQ-test/src/org/jooq/test/_/listeners/PrettyPrinter.java
@@ -43,6 +43,7 @@ import org.jooq.DSLContext;
import org.jooq.ExecuteContext;
import org.jooq.conf.SettingsTools;
import org.jooq.impl.DSL;
+import org.jooq.impl.DefaultConfiguration;
import org.jooq.impl.DefaultExecuteListener;
import org.jooq.tools.StringUtils;
@@ -67,13 +68,20 @@ public class PrettyPrinter extends DefaultExecuteListener {
public void renderEnd(ExecuteContext ctx) {
// Create a new factory for logging rendering purposes
- // This factory doesn't need a connection, only the SQLDialect...
- DSLContext pretty = DSL.using(ctx.configuration().dialect(),
+ DSLContext pretty = DSL.using(new DefaultConfiguration()
- // ... and the flag for pretty-printing
- SettingsTools.clone(ctx.configuration().settings()).withRenderFormatted(true));
+ // This factory doesn't need a connection, only the SQLDialect...
+ .set(ctx.configuration().dialect())
- DSLContext normal = DSL.using(ctx.configuration().dialect());
+ // ... and the flag for pretty-printing
+ .set(SettingsTools.clone(ctx.configuration().settings()).withRenderFormatted(true))
+
+ // ... and visit listener providers for potential SQL transformations
+ .set(ctx.configuration().visitListenerProviders()));
+
+ DSLContext normal = DSL.using(new DefaultConfiguration()
+ .set(ctx.configuration().dialect())
+ .set(ctx.configuration().visitListenerProviders()));
String n = "" + count.incrementAndGet();
diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/VisitListenerTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/VisitListenerTests.java
index cc45c8cd51..7f98ecb365 100644
--- a/jOOQ-test/src/org/jooq/test/_/testcases/VisitListenerTests.java
+++ b/jOOQ-test/src/org/jooq/test/_/testcases/VisitListenerTests.java
@@ -35,13 +35,20 @@
*/
package org.jooq.test._.testcases;
-import static java.lang.Boolean.TRUE;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.SELECT;
import static org.jooq.Clause.SELECT_WHERE;
import static org.jooq.impl.DSL.inline;
+import static org.jooq.impl.DSL.select;
+import static org.jooq.impl.DSL.selectFrom;
+import static org.jooq.impl.DSL.selectOne;
import static org.junit.Assert.assertEquals;
import java.sql.Date;
+import java.util.EnumSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
import org.jooq.Clause;
import org.jooq.Condition;
@@ -90,7 +97,7 @@ extends BaseTest result1 =
- create(new OnlyAuthorIDEq1VisitListener())
+ create(new OnlyAuthorIDEqual1())
.select(TBook_ID())
.from(TBook())
.orderBy(TBook_ID())
@@ -101,7 +108,7 @@ extends BaseTest result2 =
- create(new OnlyAuthorIDEq1VisitListener())
+ create(new OnlyAuthorIDEqual1())
.select(TBook_ID())
.from(TBook())
.where(TBook_ID().in(BOOK_IDS))
@@ -113,7 +120,7 @@ extends BaseTest result3 =
- create(new OnlyAuthorIDEq1VisitListener())
+ create(new OnlyAuthorIDEqual1())
.select(TBook_ID())
.from(TBook().join(TAuthor())
.on(TBook_AUTHOR_ID().eq(TAuthor_ID())))
@@ -122,9 +129,105 @@ extends BaseTest result4 =
+ create(new OnlyAuthorIDEqual1())
+ .select(TAuthor_ID())
+ .from(TAuthor())
+ .where(TAuthor_ID().eq(1))
+ .union(
+ select(TAuthor_ID())
+ .from(TAuthor())
+ .where(TAuthor_ID().ne(1)))
+ .union(
+ select(TAuthor_ID())
+ .from(TAuthor()))
+ .fetch();
+
+ assertEquals(1, result4.size());
+ assertEquals(1, (int) result4.getValue(0, TAuthor_ID()));
+
+ // Use nested selects
+ Result> result5 =
+ create(new OnlyAuthorIDEqual1())
+ .select(inline(1).as("value"))
+ .where(inline(2).in(select(TAuthor_ID()).from(TAuthor()).where(TAuthor_ID().eq(2))))
+ .union(
+ select(inline(2))
+ .whereExists(selectOne().from(TAuthor()).where(TAuthor_ID().eq(2))))
+ .union(
+ select(inline(3))
+ .from(selectFrom(TAuthor()).where(TAuthor_ID().eq(2))))
+ .fetch();
+
+ assertEquals(0, result5.size());
}
- private class OnlyAuthorIDEq1VisitListener extends DefaultVisitListener {
+ private enum Key {
+ NESTING_LEVEL,
+ SUBSELECT_VALUES
+ }
+
+ private enum Value {
+ SUBSELECT_SELECTS_FROM_AUTHOR,
+ SUBSELECT_SELECTS_FROM_BOOK,
+ SUBSELECT_HAS_WHERE_CLAUSE_PREDICATES
+ }
+
+ /**
+ * This sample visit listener restricts T_AUTHOR.ID = 1 and T_BOOK.AUTHOR_ID
+ * = 1.
+ */
+ private class OnlyAuthorIDEqual1 extends DefaultVisitListener {
+
+ private int nestingLevel(VisitContext context, int increase) {
+ Integer level = (Integer) context.data(Key.NESTING_LEVEL);
+ if (level == null) {
+ level = 0;
+ }
+
+ if (increase == -1)
+ subselectValueMap(context).remove(level);
+
+ level += increase;
+
+ if (increase != 0)
+ context.data(Key.NESTING_LEVEL, level);
+ if (increase == 1)
+ subselectValueMap(context).put(level, EnumSet.noneOf(Value.class));
+
+ return level;
+ }
+
+ @SuppressWarnings("unchecked")
+ private Map> subselectValueMap(VisitContext context) {
+ Map> data = (Map>) context.data(Key.SUBSELECT_VALUES);
+ if (data == null) {
+ data = new HashMap>();
+ context.data(Key.SUBSELECT_VALUES, data);
+ }
+ return data;
+ }
+
+ private EnumSet subselectValues(VisitContext context) {
+ return subselectValueMap(context).get(nestingLevel(context, 0));
+ }
+
+ private List subselectClauses(VisitContext context) {
+ List result = asList(context.clauses());
+ return result.subList(result.lastIndexOf(SELECT), result.size() - 1);
+ }
+
+ @Override
+ public void clauseStart(VisitContext context) {
+ if (context.renderContext() == null)
+ return;
+
+ if (context.clause() == SELECT) {
+ nestingLevel(context, 1);
+ }
+ }
@Override
public void clauseEnd(VisitContext context) {
@@ -132,13 +235,14 @@ extends BaseTest