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