diff --git a/jOOQ/src/main/java/org/jooq/Clause.java b/jOOQ/src/main/java/org/jooq/Clause.java
new file mode 100644
index 0000000000..6dc1f382c6
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/Clause.java
@@ -0,0 +1,252 @@
+/**
+ * Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
+ * All rights reserved.
+ *
+ * This software is licensed to you under the Apache License, Version 2.0
+ * (the "License"); You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name "jOOQ" nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jooq;
+
+/**
+ * TODO [#2667]
+ */
+public enum Clause {
+
+ /**
+ * A placeholder clause for cases where the behaviour was not yet specified.
+ * This will not go public, and is meant to be a placeholder during
+ * development.
+ */
+ @Deprecated
+ DUMMY,
+
+ // -------------------------------------------------------------------------
+ // Clauses used in a any type of statement to model catalog references
+ // -------------------------------------------------------------------------
+
+ CATALOG,
+
+ // -------------------------------------------------------------------------
+ // Clauses used in a any type of statement to model schema references
+ // -------------------------------------------------------------------------
+
+ SCHEMA,
+
+ // -------------------------------------------------------------------------
+ // Clauses used in a any type of statement to model table references
+ // -------------------------------------------------------------------------
+
+ /**
+ * A complete table reference.
+ *
+ * This "clause" surrounds a complete table reference as it can be encountered
+ * in
+ *
+ * {@link #SELECT_FROM}
+ * {@link #INSERT_INSERT_INTO}
+ * {@link #UPDATE_UPDATE}
+ * {@link #DELETE_DELETE}
+ * {@link #MERGE_MERGE_INTO}
+ * {@link #TRUNCATE_TRUNCATE}
+ *
+ */
+ TABLE,
+
+ /**
+ *
+ */
+ TABLE_JOIN,
+ TABLE_JOIN_INNER,
+ TABLE_JOIN_CROSS,
+ TABLE_JOIN_NATURAL,
+ TABLE_JOIN_OUTER_LEFT,
+ TABLE_JOIN_OUTER_RIGHT,
+ TABLE_JOIN_OUTER_FULL,
+ TABLE_JOIN_NATURAL_OUTER_LEFT,
+ TABLE_JOIN_NATURAL_OUTER_RIGHT,
+ TABLE_JOIN_ON,
+ TABLE_JOIN_USING,
+ TABLE_JOIN_PARTITION_BY,
+
+ TABLE_FLASHBACK,
+ TABLE_PIVOT,
+
+ // -------------------------------------------------------------------------
+ // Clauses used in a any type of statement to model column references
+ // -------------------------------------------------------------------------
+
+ FIELD,
+ FIELD_CASE,
+ FIELD_ROW,
+
+ // -------------------------------------------------------------------------
+ // Clauses used in a any type of statement to model condition references
+ // -------------------------------------------------------------------------
+
+ CONDITION,
+
+ CONDITION_NULL,
+ CONDITION_NULL_NOT,
+ // TODO: Should operators be distinguished?
+ // - LIKE predicate
+ // - Subselect predicates
+ // - RVE predicates
+ // - Quantified predicates
+ CONDITION_COMPARISON,
+ CONDITION_BETWEEN,
+ CONDITION_DISTINCT,
+ CONDITION_DISTINCT_NOT,
+ CONDITION_OVERLAPS,
+
+ CONDITION_AND,
+ CONDITION_OR,
+ CONDITION_NOT,
+
+ CONDITION_IN,
+ CONDITION_IN_NOT,
+ CONDITION_EXISTS,
+ CONDITION_EXISTS_NOT,
+
+ // -------------------------------------------------------------------------
+ // Clauses that are used in a SELECT statement
+ // -------------------------------------------------------------------------
+
+ /**
+ * A complete SELECT statement or a subselect.
+ *
+ * This "clause" surrounds a complete SELECT statement, a
+ * subselect, or a set operation, such as
+ *
+ * {@link #SELECT_UNION}
+ * {@link #SELECT_UNION_ALL}
+ * {@link #SELECT_INTERSECT}
+ * {@link #SELECT_EXCEPT}
+ *
+ */
+ SELECT,
+
+ /**
+ * A UNION set operation.
+ *
+ * This clause surrounds two or more subselects (see {@link #SELECT})
+ * concatenating them using a UNION set operation.
+ */
+ SELECT_UNION,
+
+ /**
+ * A UNION ALL set operation.
+ *
+ * This clause surrounds two or more subselects (see {@link #SELECT})
+ * concatenating them using a UNION ALL set operation.
+ */
+ SELECT_UNION_ALL,
+
+ /**
+ * A INTERSECT set operation.
+ *
+ * This clause surrounds two or more subselects (see {@link #SELECT})
+ * concatenating them using a INTERSECT set operation.
+ */
+ SELECT_INTERSECT,
+
+ /**
+ * A EXCEPT set operation.
+ *
+ * This clause surrounds two or more subselects (see {@link #SELECT})
+ * concatenating them using a EXCEPT set operation.
+ */
+ SELECT_EXCEPT,
+
+ /**
+ * A SELECT clause within a {@link #SELECT} statement or
+ * subselect.
+ *
+ * This clause surrounds
+ *
+ * the SELECT keyword
+ * Oracle style hints
+ * the T-SQL style TOP .. START AT clause
+ * the select field list
+ *
+ */
+ SELECT_SELECT,
+
+ /**
+ * A FROM clause within a {@link #SELECT} statement or
+ * subselect.
+ *
+ * This clause surrounds
+ *
+ * the FROM keyword
+ * the table reference list
+ *
+ *
+ * See {@link #TABLE} and related clauses for possible table references.
+ *
+ * @see #TABLE
+ */
+ SELECT_FROM,
+ SELECT_WHERE,
+ SELECT_START_WITH,
+ SELECT_CONNECT_BY,
+ SELECT_GROUP_BY,
+ SELECT_HAVING,
+ SELECT_ORDER_BY,
+
+
+
+ INSERT,
+ INSERT_INSERT_INTO,
+ INSERT_RETURNING,
+
+
+
+ UPDATE,
+ UPDATE_UPDATE,
+ UPDATE_SET,
+ UPDATE_SET_ASSIGNMENT,
+ UPDATE_WHERE,
+ UPDATE_RETURNING,
+
+
+ DELETE,
+ DELETE_DELETE,
+ DELETE_WHERE,
+
+
+ MERGE,
+ MERGE_MERGE_INTO,
+
+
+
+ TRUNCATE,
+ TRUNCATE_TRUNCATE,
+}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/Configuration.java b/jOOQ/src/main/java/org/jooq/Configuration.java
index 9bb4287c24..ae516cb2e9 100644
--- a/jOOQ/src/main/java/org/jooq/Configuration.java
+++ b/jOOQ/src/main/java/org/jooq/Configuration.java
@@ -194,6 +194,11 @@ public interface Configuration extends Serializable {
*/
ExecuteListenerProvider[] executeListenerProviders();
+ /**
+ * TODO [#2667]
+ */
+ VisitListenerProvider[] visitListenerProviders();
+
/**
* Retrieve the configured schema mapping.
*
@@ -264,6 +269,18 @@ public interface Configuration extends Serializable {
*/
Configuration set(ExecuteListenerProvider... newExecuteListenerProviders);
+ /**
+ * Change this configuration to hold a new visit listener providers.
+ *
+ * This method is not thread-safe and should not be used in globally
+ * available Configuration objects.
+ *
+ * @param newVisitListenerProviders The new visit listener providers to
+ * be contained in the changed configuration.
+ * @return The changed configuration.
+ */
+ Configuration set(VisitListenerProvider... newVisitListenerProviders);
+
/**
* Change this configuration to hold a new dialect.
*
@@ -340,6 +357,16 @@ public interface Configuration extends Serializable {
*/
Configuration derive(ExecuteListenerProvider... newExecuteListenerProviders);
+ /**
+ * Create a derived configuration from this one, with new visit listener
+ * providers.
+ *
+ * @param newVisitListenerProviders The new visit listener providers to
+ * be contained in the derived configuration.
+ * @return The derived configuration.
+ */
+ Configuration derive(VisitListenerProvider... newVisitListenerProviders);
+
/**
* Create a derived configuration from this one, with a new dialect.
*
diff --git a/jOOQ/src/main/java/org/jooq/Context.java b/jOOQ/src/main/java/org/jooq/Context.java
index 7a83e34131..3763c021f4 100644
--- a/jOOQ/src/main/java/org/jooq/Context.java
+++ b/jOOQ/src/main/java/org/jooq/Context.java
@@ -120,6 +120,15 @@ public interface Context> {
*/
C visit(QueryPart part) throws DataAccessException;
+ /**
+ * TODO [#2667]
+ *
+ * Properties of these methods:
+ * - A clause is always started / ended, even if it isn't rendered or if it's empty!
+ */
+ C start(Clause clause);
+ C end(Clause clause);
+
/**
* Whether the current context is rendering a SQL field declaration (e.g. a
* {@link Field} in the SELECT clause of the query).
diff --git a/jOOQ/src/main/java/org/jooq/QueryPartInternal.java b/jOOQ/src/main/java/org/jooq/QueryPartInternal.java
index 9ce41b4008..f521c5c9db 100644
--- a/jOOQ/src/main/java/org/jooq/QueryPartInternal.java
+++ b/jOOQ/src/main/java/org/jooq/QueryPartInternal.java
@@ -69,6 +69,21 @@ public interface QueryPartInternal extends QueryPart {
*/
void bind(BindContext ctx) throws DataAccessException;
+ /**
+ * The {@link Clause} that is represented by this query part.
+ *
+ * {@link QueryPart}s can specify a Clause for which an event
+ * will be emitted {@link Context#start(Clause) before} and
+ * {@link Context#end(Clause) after} visiting the the query part through
+ * {@link Context#visit(QueryPart)}
+ *
+ * This method is for JOOQ INTERNAL USE only. Do not reference directly
+ *
+ * @return The Clause represented by this query part or
+ * null if this query part does not represent a clause.
+ */
+ Clause clause();
+
/**
* Check whether this {@link QueryPart} is able to declare fields in a
* SELECT clause.
diff --git a/jOOQ/src/main/java/org/jooq/RecordListener.java b/jOOQ/src/main/java/org/jooq/RecordListener.java
index ed2e849463..f74cab20cf 100644
--- a/jOOQ/src/main/java/org/jooq/RecordListener.java
+++ b/jOOQ/src/main/java/org/jooq/RecordListener.java
@@ -35,6 +35,8 @@
*/
package org.jooq;
+import java.util.EventListener;
+
/**
* A listener for manipulation events on {@link UpdatableRecord}s.
*
@@ -52,7 +54,7 @@ package org.jooq;
*
* @author Lukas Eder
*/
-public interface RecordListener {
+public interface RecordListener extends EventListener {
/**
* Called before storing an UpdatableRecord.
diff --git a/jOOQ/src/main/java/org/jooq/RecordListenerProvider.java b/jOOQ/src/main/java/org/jooq/RecordListenerProvider.java
index c290fbebfb..d839832573 100644
--- a/jOOQ/src/main/java/org/jooq/RecordListenerProvider.java
+++ b/jOOQ/src/main/java/org/jooq/RecordListenerProvider.java
@@ -43,8 +43,8 @@ import org.jooq.impl.DefaultRecordListenerProvider;
* In order to facilitate the lifecycle management of
* RecordListener instances that are provided to a jOOQ
* {@link Configuration}, clients can implement this API. To jOOQ, it is thus
- * irrelevant, if execute listeners are stateful or stateless, local to a
- * single record or record manipulation, or global to an application.
+ * irrelevant, if execute listeners are stateful or stateless, local to a single
+ * record or record manipulation, or global to an application.
*
* @author Lukas Eder
* @see RecordListener
diff --git a/jOOQ/src/main/java/org/jooq/VisitContext.java b/jOOQ/src/main/java/org/jooq/VisitContext.java
new file mode 100644
index 0000000000..ab44546eb1
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/VisitContext.java
@@ -0,0 +1,128 @@
+/**
+ * Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
+ * All rights reserved.
+ *
+ * This software is licensed to you under the Apache License, Version 2.0
+ * (the "License"); You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name "jOOQ" nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jooq;
+
+import java.util.Map;
+
+/**
+ * A context object for {@link QueryPart} traversal passed to registered
+ * {@link VisitListener}'s.
+ *
+ * @author Lukas Eder
+ * @see VisitListener
+ */
+public interface VisitContext {
+
+ /**
+ * Get all custom data from this VisitContext.
+ *
+ * This corresponds to {@link Context#data()} returned from
+ * {@link #context()}.
+ *
+ * @return The custom data. This is never null
+ * @see VisitListener
+ */
+ Map data();
+
+ /**
+ * Get some custom data from this VisitContext.
+ *
+ * This corresponds to {@link Context#data(Object)} returned from
+ * {@link #context()}.
+ *
+ * @param key A key to identify the custom data
+ * @return The custom data or null if no such data is contained
+ * in this VisitListener
+ * @see VisitListener
+ */
+ Object data(Object key);
+
+ /**
+ * Set some custom data to this VisitContext.
+ *
+ * This corresponds to {@link Context#data(Object, Object)} returned from
+ * {@link #context()}.
+ *
+ * @param key A key to identify the custom data
+ * @param value The custom data or null to unset the custom
+ * data
+ * @return The previously set custom data or null if no data
+ * was previously set for the given key
+ * @see VisitContext
+ */
+ Object data(Object key, Object value);
+
+ /**
+ * The configuration wrapped by this context.
+ */
+ Configuration configuration();
+
+ /**
+ * The most recent clause that was encountered through
+ * {@link Context#start(Clause)}.
+ */
+ Clause clause();
+
+ /**
+ * All previous clauses.
+ *
+ * This returns all previous clauses that were encountered through
+ * {@link Context#start(Clause)} and that haven't been removed yet through
+ * {@link Context#end(Clause)}. In other words, VisitContext
+ * contains a stack of clauses.
+ */
+ Clause[] clauses();
+
+ /**
+ * The {@link QueryPart} that is being visited.
+ */
+ QueryPart visiting();
+
+ /**
+ * The underlying {@link RenderContext} or {@link BindContext} object.
+ */
+ Context> context();
+
+ /**
+ * The underlying {@link RenderContext} or null, if the underlying context is a {@link BindContext}.
+ */
+ RenderContext renderContext();
+
+ /**
+ * The underlying {@link BindContext} or null, if the underlying context is a {@link RenderContext}.
+ */
+ BindContext bindContext();
+}
diff --git a/jOOQ/src/main/java/org/jooq/VisitListener.java b/jOOQ/src/main/java/org/jooq/VisitListener.java
new file mode 100644
index 0000000000..6ba375f5f4
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/VisitListener.java
@@ -0,0 +1,111 @@
+/**
+ * Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
+ * All rights reserved.
+ *
+ * This software is licensed to you under the Apache License, Version 2.0
+ * (the "License"); You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name "jOOQ" nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jooq;
+
+import java.sql.PreparedStatement;
+import java.util.EventListener;
+
+/**
+ * A listener for {@link QueryPart} traversal events.
+ *
+ * Users may want to centrally inject custom behaviour when rendering their
+ * {@link QueryPart} objects or when binding values to {@link PreparedStatement}
+ * s. This service provider allows to hook in callback method implementations
+ * before or after these events:
+ *
+ * The visit of a {@link Clause}
+ * The visit of a {@link QueryPart}
+ *
+ *
+ * The following rules apply to visiting clauses and query parts:
+ *
+ * Clauses may "surround" a query part. See an example below.
+ * Not every query part is "surrounded" by a clause
+ *
+ *
+ * An example is given here:
+ * SELECT 1 FROM [A CROSS JOIN B]
+ *
+ * The above example will create the following set of events:
+ *
+ *
+ * {@link Clause#SELECT}
+ * +-{@link Clause#SELECT_SELECT}
+ * | +-{@link Clause#FIELD}
+ * | +-val(1)
+ * +-{@link Clause#SELECT_FROM}
+ * +-{@link Clause#TABLE_JOIN}
+ * +-{@link Clause#TABLE}
+ * | +-table("A")
+ * +-{@link Clause#TABLE_JOIN_CROSS}
+ * +-{@link Clause#TABLE}
+ * +-table("B")
+ *
+ *
+ * Whatever is not a {@link Clause} in the above example is a {@link QueryPart}.
+ *
+ * @author Lukas Eder
+ */
+public interface VisitListener extends EventListener {
+
+ /**
+ * Called before entering a {@link Clause}.
+ *
+ * @see Context#start(Clause)
+ */
+ void clauseStart(VisitContext context);
+
+ /**
+ * Called after leaving a {@link Clause}.
+ *
+ * @see Context#end(Clause)
+ */
+ void clauseEnd(VisitContext context);
+
+ /**
+ * Called before visiting a {@link QueryPart}.
+ *
+ * @see Context#visit(QueryPart)
+ */
+ void visitStart(VisitContext context);
+
+ /**
+ * Called after visiting a {@link QueryPart}.
+ *
+ * @see Context#visit(QueryPart)
+ */
+ void visitEnd(VisitContext context);
+}
diff --git a/jOOQ/src/main/java/org/jooq/VisitListenerProvider.java b/jOOQ/src/main/java/org/jooq/VisitListenerProvider.java
new file mode 100644
index 0000000000..223dcfee3b
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/VisitListenerProvider.java
@@ -0,0 +1,72 @@
+/**
+ * Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
+ * All rights reserved.
+ *
+ * This software is licensed to you under the Apache License, Version 2.0
+ * (the "License"); You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name "jOOQ" nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jooq;
+
+import org.jooq.impl.DefaultVisitListenerProvider;
+
+/**
+ * A provider for {@link VisitListener} instances.
+ *
+ * In order to facilitate the lifecycle management of VisitListener
+ * instances that are provided to a jOOQ {@link Configuration}, clients can
+ * implement this API. To jOOQ, it is thus irrelevant, if execute listeners are
+ * stateful or stateless, local to a single record or record manipulation, or
+ * global to an application.
+ *
+ * @author Lukas Eder
+ * @see VisitListener
+ * @see Configuration
+ */
+public interface VisitListenerProvider {
+
+ /**
+ * Provide a VisitListener instance.
+ *
+ * Implementations are free to choose whether this method returns new
+ * instances at every call or whether the same instance is returned
+ * repetitively.
+ *
+ * A VisitListener shall be provided exactly once per
+ * Context traversal, i.e. per RenderContext or
+ * BindContext.
+ *
+ * @return A VisitListener instance.
+ * @see VisitListener
+ * @see VisitContext
+ * @see DefaultVisitListenerProvider
+ */
+ VisitListener provide();
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java
index eed465cf16..df0ef2e9c0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractContext.java
@@ -35,13 +35,22 @@
*/
package org.jooq.impl;
+import java.util.ArrayDeque;
+import java.util.Deque;
import java.util.HashMap;
import java.util.Map;
+import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Context;
import org.jooq.QueryPart;
import org.jooq.QueryPartInternal;
+import org.jooq.RenderContext;
+import org.jooq.Table;
+import org.jooq.VisitContext;
+import org.jooq.VisitListener;
+import org.jooq.VisitListenerProvider;
/**
* @author Lukas Eder
@@ -49,16 +58,32 @@ import org.jooq.QueryPartInternal;
@SuppressWarnings("unchecked")
abstract class AbstractContext> implements Context {
- final Configuration configuration;
- final Map data;
- boolean declareFields;
- boolean declareTables;
- boolean subquery;
- int index;
+ final Configuration configuration;
+ final Map data;
+ final VisitListener[] visitListeners;
+
+ private final DefaultVisitContext visitContext;
+ private final Deque visitClauses;
+ private final Deque visitParts;
+
+ boolean declareFields;
+ boolean declareTables;
+ boolean subquery;
+ int index;
AbstractContext(Configuration configuration) {
+ VisitListenerProvider[] providers = configuration.visitListenerProviders();
+
this.configuration = configuration;
this.data = new HashMap();
+ this.visitListeners = new VisitListener[providers.length];
+ this.visitContext = new DefaultVisitContext();
+ this.visitClauses = new ArrayDeque();
+ this.visitParts = new ArrayDeque();
+
+ for (int i = 0; i < providers.length; i++) {
+ this.visitListeners[i] = providers[i].provide();
+ }
}
// ------------------------------------------------------------------------
@@ -85,9 +110,112 @@ abstract class AbstractContext> implements Context {
return data.put(key, value);
}
+ /**
+ * TODO [#2667] This is a draft implementation. The actual implementation
+ * may change
+ */
+ private class DefaultVisitContext implements VisitContext {
+
+ @Override
+ public final Map data() {
+ return AbstractContext.this.data();
+ }
+
+ @Override
+ public final Object data(Object key) {
+ return AbstractContext.this.data(key);
+ }
+
+ @Override
+ public final Object data(Object key, Object value) {
+ return AbstractContext.this.data(key, value);
+ }
+
+ @Override
+ public final Configuration configuration() {
+ return AbstractContext.this.configuration();
+ }
+
+ @Override
+ public final Clause clause() {
+ return visitClauses.peekLast();
+ }
+
+ @Override
+ public final Clause[] clauses() {
+ return visitClauses.toArray(new Clause[visitClauses.size()]);
+ }
+
+ @Override
+ public final QueryPart visiting() {
+ return visitParts.peekLast();
+ }
+
+ @Override
+ public final Context> context() {
+ return AbstractContext.this;
+ }
+
+ @Override
+ public final RenderContext renderContext() {
+ return (RenderContext) (AbstractContext.this instanceof RenderContext ? AbstractContext.this : null);
+ }
+
+ @Override
+ public final BindContext bindContext() {
+ return (BindContext) (AbstractContext.this instanceof BindContext ? AbstractContext.this : null);
+ }
+ }
+
+ @Override
+ public final C start(Clause clause) {
+ visitClauses.addLast(clause);
+
+ for (VisitListener listener : visitListeners) {
+ listener.clauseStart(visitContext);
+ }
+
+ return (C) this;
+ }
+
+ @Override
+ public final C end(Clause clause) {
+ for (VisitListener listener : visitListeners) {
+ listener.clauseEnd(visitContext);
+ }
+
+ if (visitClauses.removeLast() != clause)
+ throw new IllegalStateException("Mismatch between visited clauses!");
+
+ return (C) this;
+ }
+
+ private final void start(QueryPart part) {
+ visitParts.addLast(part);
+
+ for (VisitListener listener : visitListeners) {
+ listener.visitStart(visitContext);
+ }
+ }
+
+ private final void end(QueryPart part) {
+ for (VisitListener listener : visitListeners) {
+ listener.visitEnd(visitContext);
+ }
+
+ if (visitParts.removeLast() != part)
+ throw new RuntimeException("Mismatch between visited query parts");
+ }
+
@Override
public final C visit(QueryPart part) {
if (part != null) {
+ Clause clause = visitListeners.length > 0 ? clause(part) : null;
+
+ if (clause != null)
+ start(clause);
+
+ start(part);
QueryPartInternal internal = (QueryPartInternal) part;
// If this is supposed to be a declaration section and the part isn't
@@ -111,11 +239,39 @@ abstract class AbstractContext> implements Context {
else {
visit0(internal);
}
+
+ end(part);
+ if (clause != null)
+ end(clause);
}
return (C) this;
}
+ /**
+ * Emit a clause from a query part being visited.
+ *
+ * This method returns a clause to emit as a surrounding event before /
+ * after visiting a query part. This is needed for all reusable query parts,
+ * whose clause type is ambiguous at the container site. An example:
+ *
+ * SELECT * FROM [A CROSS JOIN B]
+ *
+ * The type of the above JoinTable modelling
+ * A CROSS JOIN B is not known to the surrounding
+ * SELECT statement, which only knows {@link Table} types. The
+ * {@link Clause#TABLE_JOIN} event that is required to be emitted around the
+ * {@link Context#visit(QueryPart)} event has to be issued here in
+ * AbstractContext.
+ */
+ private final Clause clause(QueryPart part) {
+ if (part instanceof QueryPartInternal) {
+ return ((QueryPartInternal) part).clause();
+ }
+
+ return null;
+ }
+
protected abstract void visit0(QueryPartInternal internal);
@Override
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractDelegatingQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractDelegatingQuery.java
index 144b4a43d6..7fef0a418f 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractDelegatingQuery.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractDelegatingQuery.java
@@ -40,9 +40,11 @@ import java.util.Map;
import org.jooq.AttachableInternal;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Param;
import org.jooq.Query;
+import org.jooq.QueryPartInternal;
import org.jooq.RenderContext;
import org.jooq.conf.ParamType;
@@ -95,6 +97,15 @@ abstract class AbstractDelegatingQuery extends AbstractQueryPar
context.visit(delegate);
}
+ @Override
+ public final Clause clause() {
+ if (delegate instanceof QueryPartInternal) {
+ return ((QueryPartInternal) delegate).clause();
+ }
+
+ return null;
+ }
+
@Override
public final String getSQL() {
return delegate.getSQL();
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
index 3040bf0053..04c5106614 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractField.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.Comparator.EQUALS;
import static org.jooq.Comparator.GREATER;
import static org.jooq.Comparator.GREATER_OR_EQUAL;
@@ -72,6 +73,7 @@ import org.jooq.BetweenAndStep;
import org.jooq.BindContext;
import org.jooq.CaseValueStep;
import org.jooq.CaseWhenStep;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Configuration;
@@ -119,6 +121,11 @@ abstract class AbstractField extends AbstractQueryPart implements Field {
@Override
public abstract void bind(BindContext context);
+ @Override
+ public /* non-final for now */ Clause clause() {
+ return DUMMY;
+ }
+
// ------------------------------------------------------------------------
// XXX: API
// ------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractFunction.java b/jOOQ/src/main/java/org/jooq/impl/AbstractFunction.java
index aaaef55fd6..9addece115 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractFunction.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractFunction.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.DataType;
import org.jooq.Field;
@@ -72,6 +75,11 @@ abstract class AbstractFunction extends AbstractField {
ctx.visit(getFunction0(ctx.configuration()));
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
final Field>[] getArguments() {
return arguments;
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
index 38022decad..e6bd65b5e0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLSERVER;
import static org.jooq.impl.DSL.function;
@@ -58,6 +59,7 @@ import org.jooq.AggregateFunction;
import org.jooq.ArrayRecord;
import org.jooq.AttachableInternal;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.DataType;
@@ -290,6 +292,11 @@ public abstract class AbstractRoutine extends AbstractQueryPart implements Ro
}
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
public final void bind(BindContext context) {
for (Parameter> parameter : getParameters()) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractStoreQuery.java b/jOOQ/src/main/java/org/jooq/impl/AbstractStoreQuery.java
index 3d5d79339c..f0efe207a0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/AbstractStoreQuery.java
+++ b/jOOQ/src/main/java/org/jooq/impl/AbstractStoreQuery.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.Utils.fieldArray;
import static org.jooq.util.sqlite.SQLiteDSL.rowid;
@@ -49,6 +50,7 @@ import java.util.List;
import java.util.Map;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.DSLContext;
import org.jooq.ExecuteContext;
@@ -83,7 +85,7 @@ abstract class AbstractStoreQuery extends AbstractQuery implem
super(configuration);
this.into = into;
- this.returning = new QueryPartList>();
+ this.returning = new QueryPartList>(DUMMY);
}
protected abstract Map, Field>> getValues();
@@ -147,14 +149,17 @@ abstract class AbstractStoreQuery extends AbstractQuery implem
return returned;
}
- final void toSQLReturning(RenderContext context) {
+ final void toSQLReturning(RenderContext context, Clause clause) {
if (!returning.isEmpty()) {
switch (context.configuration().dialect()) {
case FIREBIRD:
case POSTGRES:
context.formatSeparator()
- .keyword("returning ")
- .visit(returning);
+ .start(clause)
+ .keyword("returning")
+ .sql(" ")
+ .visit(returning)
+ .end(clause);
break;
default:
diff --git a/jOOQ/src/main/java/org/jooq/impl/Alias.java b/jOOQ/src/main/java/org/jooq/impl/Alias.java
index b3f4691c81..d283795a3e 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Alias.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Alias.java
@@ -37,6 +37,7 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.FIREBIRD;
@@ -55,6 +56,7 @@ import static org.jooq.impl.DSL.select;
import static org.jooq.impl.Utils.list;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.QueryPart;
import org.jooq.Record;
import org.jooq.RenderContext;
@@ -221,6 +223,11 @@ class Alias extends AbstractQueryPart {
}
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
public final boolean declaresFields() {
return true;
diff --git a/jOOQ/src/main/java/org/jooq/impl/ArrayTable.java b/jOOQ/src/main/java/org/jooq/impl/ArrayTable.java
index 5ac6e60ce7..e936369861 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ArrayTable.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ArrayTable.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.fieldByName;
import java.util.ArrayList;
@@ -42,6 +43,7 @@ import java.util.List;
import org.jooq.ArrayRecord;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.Param;
@@ -173,6 +175,11 @@ class ArrayTable extends AbstractTable {
ctx.visit(table(ctx.configuration()));
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final Table table(Configuration configuration) {
switch (configuration.dialect().family()) {
case ORACLE: {
@@ -296,6 +303,11 @@ class ArrayTable extends AbstractTable {
context.visit(array);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
final Fields fields0() {
return ArrayTable.this.fields0();
diff --git a/jOOQ/src/main/java/org/jooq/impl/ArrayTableSimulation.java b/jOOQ/src/main/java/org/jooq/impl/ArrayTableSimulation.java
index 62a72ca386..e7f3502851 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ArrayTableSimulation.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ArrayTableSimulation.java
@@ -35,12 +35,14 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.falseCondition;
import static org.jooq.impl.DSL.fieldByName;
import static org.jooq.impl.DSL.one;
import static org.jooq.impl.DSL.using;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.Record;
@@ -126,6 +128,11 @@ class ArrayTableSimulation extends AbstractTable {
ctx.visit(table(ctx.configuration()));
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
final Fields fields0() {
return field;
diff --git a/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java b/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java
index a51660a8aa..1256cd8143 100644
--- a/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java
@@ -37,6 +37,7 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.CONDITION_BETWEEN;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
@@ -53,6 +54,7 @@ import static org.jooq.impl.DSL.val;
import org.jooq.BetweenAndStep;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -106,6 +108,11 @@ class BetweenCondition extends AbstractCondition implements BetweenAndStep
delegate(ctx.configuration()).toSQL(ctx);
}
+ @Override
+ public final Clause clause() {
+ return CONDITION_BETWEEN;
+ }
+
private final QueryPartInternal delegate(Configuration configuration) {
if (symmetric && asList(ASE, CUBRID, DB2, DERBY, FIREBIRD, H2, MARIADB, MYSQL, ORACLE, SQLSERVER, SQLITE, SYBASE).contains(configuration.dialect().family())) {
if (not) {
@@ -142,5 +149,10 @@ class BetweenCondition extends AbstractCondition implements BetweenAndStep
public final void bind(BindContext context) {
context.visit(field).visit(minValue).visit(maxValue);
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_BETWEEN;
+ }
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java
index d1d233a463..b0d5193836 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java
@@ -35,11 +35,14 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import java.util.ArrayList;
import java.util.List;
import org.jooq.BindContext;
import org.jooq.CaseConditionStep;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -137,4 +140,9 @@ class CaseConditionStepImpl extends AbstractField implements CaseCondition
context.keyword("end")
.formatIndentLockEnd();
}
+
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/CatalogImpl.java b/jOOQ/src/main/java/org/jooq/impl/CatalogImpl.java
index 21e37b18ab..3bee3beba7 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CatalogImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CatalogImpl.java
@@ -35,11 +35,14 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.CATALOG;
+
import java.util.Collections;
import java.util.List;
import org.jooq.BindContext;
import org.jooq.Catalog;
+import org.jooq.Clause;
import org.jooq.RenderContext;
import org.jooq.Schema;
import org.jooq.tools.StringUtils;
@@ -78,6 +81,11 @@ public class CatalogImpl extends AbstractQueryPart implements Catalog {
context.literal(getName());
}
+ @Override
+ public final Clause clause() {
+ return CATALOG;
+ }
+
@Override
public final Schema getSchema(String name) {
for (Schema schema : getSchemas()) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java b/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java
index c2d9f05410..dcc25a34c8 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CombinedCondition.java
@@ -36,6 +36,9 @@
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_AND;
+import static org.jooq.Clause.CONDITION_OR;
+import static org.jooq.Operator.AND;
import static org.jooq.impl.DSL.trueCondition;
import static org.jooq.impl.Utils.visitAll;
@@ -44,6 +47,7 @@ import java.util.Collection;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Operator;
import org.jooq.RenderContext;
@@ -94,6 +98,11 @@ class CombinedCondition extends AbstractCondition {
}
}
+ @Override
+ public final Clause clause() {
+ return operator == AND ? CONDITION_AND : CONDITION_OR;
+ }
+
@Override
public final void bind(BindContext context) {
visitAll(context, conditions);
diff --git a/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java b/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java
index 455418f562..ed67513c4f 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java
@@ -37,6 +37,7 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.CONDITION_COMPARISON;
import static org.jooq.Comparator.LIKE;
import static org.jooq.Comparator.LIKE_IGNORE_CASE;
import static org.jooq.Comparator.NOT_LIKE;
@@ -47,6 +48,7 @@ import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.POSTGRES;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -127,4 +129,9 @@ class CompareCondition extends AbstractCondition {
.sql("'");
}
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/ConditionProviderImpl.java b/jOOQ/src/main/java/org/jooq/impl/ConditionProviderImpl.java
index 05437aa8ce..ba4a916d18 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ConditionProviderImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ConditionProviderImpl.java
@@ -42,6 +42,7 @@ import java.util.Arrays;
import java.util.Collection;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.ConditionProvider;
import org.jooq.Field;
@@ -121,6 +122,11 @@ class ConditionProviderImpl extends AbstractQueryPart implements ConditionProvid
context.visit(getWhere());
}
+ @Override
+ public final Clause clause() {
+ return null;
+ }
+
// -------------------------------------------------------------------------
// Condition API
// -------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/Contains.java b/jOOQ/src/main/java/org/jooq/impl/Contains.java
index 4804d11c52..5021c3b296 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Contains.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Contains.java
@@ -35,10 +35,12 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_COMPARISON;
import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.val;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -82,6 +84,11 @@ class Contains extends AbstractCondition {
context.visit(condition());
}
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
+
private final Condition condition() {
// [#1107] Some dialects support "contains" operations for ARRAYs
@@ -124,6 +131,11 @@ class Contains extends AbstractCondition {
context.visit(lhs).visit(rhs());
}
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
+
private final Field rhs() {
return (rhs == null) ? val(value, lhs) : rhs;
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/CustomCondition.java b/jOOQ/src/main/java/org/jooq/impl/CustomCondition.java
index 120777d6fd..c2c988eaa7 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CustomCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CustomCondition.java
@@ -36,6 +36,7 @@
package org.jooq.impl;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.RenderContext;
import org.jooq.exception.DataAccessException;
@@ -86,6 +87,20 @@ public abstract class CustomCondition extends AbstractCondition {
@Override
public abstract void bind(BindContext context) throws DataAccessException;
+ // -------------------------------------------------------------------------
+ // Implementation optional
+ // -------------------------------------------------------------------------
+
+ /**
+ * Subclasses may implement this method
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public Clause clause() {
+ return null;
+ }
+
// -------------------------------------------------------------------------
// No further overrides allowed
// -------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/CustomField.java b/jOOQ/src/main/java/org/jooq/impl/CustomField.java
index 7b0e1082c7..3a75518dfc 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CustomField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CustomField.java
@@ -36,6 +36,7 @@
package org.jooq.impl;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -88,9 +89,19 @@ public abstract class CustomField extends AbstractField {
public abstract void bind(BindContext context) throws DataAccessException;
// -------------------------------------------------------------------------
- // Further overrides allowed
+ // Implementation optional
// -------------------------------------------------------------------------
+ /**
+ * Subclasses may implement this method
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public Clause clause() {
+ return null;
+ }
+
// -------------------------------------------------------------------------
// No further overrides allowed
// -------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/CustomQueryPart.java b/jOOQ/src/main/java/org/jooq/impl/CustomQueryPart.java
index 3cb00b2a77..2de5c6f521 100644
--- a/jOOQ/src/main/java/org/jooq/impl/CustomQueryPart.java
+++ b/jOOQ/src/main/java/org/jooq/impl/CustomQueryPart.java
@@ -36,6 +36,7 @@
package org.jooq.impl;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.QueryPart;
import org.jooq.RenderContext;
import org.jooq.exception.DataAccessException;
@@ -97,6 +98,20 @@ public abstract class CustomQueryPart extends AbstractQueryPart {
@Override
public abstract void bind(BindContext context) throws DataAccessException;
+ // -------------------------------------------------------------------------
+ // Implementation optional
+ // -------------------------------------------------------------------------
+
+ /**
+ * Subclasses may implement this method
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public Clause clause() {
+ return null;
+ }
+
// -------------------------------------------------------------------------
// No further overrides allowed
// -------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java
index eb55965e89..5a1946fb02 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DSL.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
@@ -7766,7 +7767,7 @@ public class DSL {
WrappedList[] array = new WrappedList[fieldSets.length];
for (int i = 0; i < fieldSets.length; i++) {
- array[i] = new WrappedList(new QueryPartList>(fieldSets[i]));
+ array[i] = new WrappedList(new QueryPartList>(DUMMY, fieldSets[i]));
}
return new Function("grouping sets", SQLDataType.OTHER, array);
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
index fc8f2291ae..99a75c05fe 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultConfiguration.java
@@ -55,6 +55,7 @@ import org.jooq.RecordListenerProvider;
import org.jooq.RecordMapperProvider;
import org.jooq.SQLDialect;
import org.jooq.SchemaMapping;
+import org.jooq.VisitListenerProvider;
import org.jooq.conf.Settings;
import org.jooq.conf.SettingsTools;
@@ -84,6 +85,7 @@ public class DefaultConfiguration implements Configuration {
private transient RecordMapperProvider recordMapperProvider;
private transient RecordListenerProvider[] recordListenerProviders;
private transient ExecuteListenerProvider[] executeListenerProviders;
+ private transient VisitListenerProvider[] visitListenerProviders;
// Derived objects
private org.jooq.SchemaMapping mapping;
@@ -100,14 +102,29 @@ public class DefaultConfiguration implements Configuration {
* through the various derive() or set() methods.
*/
public DefaultConfiguration() {
+ this(SQL99);
+ }
+
+ /**
+ * Create a new "empty" configuration object given a {@link SQLDialect}.
+ *
+ * This can be used as is, as a "dummy" configuration object, or as a base
+ * implementation for creating more sophisticated "derived" configurations
+ * through the various derive() or set() methods.
+ *
+ * @param dialect The pre-existing {@link SQLDialect}.
+ */
+ DefaultConfiguration(SQLDialect dialect) {
this(
new NoConnectionProvider(),
new DefaultRecordMapperProvider(),
new RecordListenerProvider[0],
new ExecuteListenerProvider[0],
- SQL99,
+ new VisitListenerProvider[0],
+ dialect,
SettingsTools.defaultSettings(),
- null);
+ null
+ );
}
/**
@@ -124,6 +141,7 @@ public class DefaultConfiguration implements Configuration {
configuration.recordMapperProvider(),
configuration.recordListenerProviders(),
configuration.executeListenerProviders(),
+ configuration.visitListenerProviders(),
configuration.dialect(),
configuration.settings(),
configuration.data()
@@ -143,6 +161,7 @@ public class DefaultConfiguration implements Configuration {
RecordMapperProvider recordMapperProvider,
RecordListenerProvider[] recordListenerProviders,
ExecuteListenerProvider[] executeListenerProviders,
+ VisitListenerProvider[] visitListenerProviders,
SQLDialect dialect,
Settings settings,
Map data)
@@ -151,6 +170,7 @@ public class DefaultConfiguration implements Configuration {
set(recordMapperProvider);
set(recordListenerProviders);
set(executeListenerProviders);
+ set(visitListenerProviders);
set(dialect);
set(settings);
@@ -181,6 +201,7 @@ public class DefaultConfiguration implements Configuration {
recordMapperProvider,
recordListenerProviders,
executeListenerProviders,
+ visitListenerProviders,
dialect,
settings,
data
@@ -197,6 +218,7 @@ public class DefaultConfiguration implements Configuration {
newRecordMapperProvider,
recordListenerProviders,
executeListenerProviders,
+ visitListenerProviders,
dialect,
settings,
data
@@ -207,12 +229,13 @@ public class DefaultConfiguration implements Configuration {
* {@inheritDoc}
*/
@Override
- public Configuration derive(RecordListenerProvider... newRecordListenerProviders) {
+ public final Configuration derive(RecordListenerProvider... newRecordListenerProviders) {
return new DefaultConfiguration(
connectionProvider,
recordMapperProvider,
newRecordListenerProviders,
executeListenerProviders,
+ visitListenerProviders,
dialect,
settings,
data
@@ -229,6 +252,24 @@ public class DefaultConfiguration implements Configuration {
recordMapperProvider,
recordListenerProviders,
newExecuteListenerProviders,
+ visitListenerProviders,
+ dialect,
+ settings,
+ data
+ );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final Configuration derive(VisitListenerProvider... newVisitListenerProviders) {
+ return new DefaultConfiguration(
+ connectionProvider,
+ recordMapperProvider,
+ recordListenerProviders,
+ executeListenerProviders,
+ newVisitListenerProviders,
dialect,
settings,
data
@@ -245,6 +286,7 @@ public class DefaultConfiguration implements Configuration {
recordMapperProvider,
recordListenerProviders,
executeListenerProviders,
+ visitListenerProviders,
newDialect,
settings,
data
@@ -261,6 +303,7 @@ public class DefaultConfiguration implements Configuration {
recordMapperProvider,
recordListenerProviders,
executeListenerProviders,
+ visitListenerProviders,
dialect,
newSettings,
data
@@ -271,15 +314,6 @@ public class DefaultConfiguration implements Configuration {
// XXX: Changing configurations
// -------------------------------------------------------------------------
- /**
- * {@inheritDoc}
- */
- @Override
- public final Configuration set(SQLDialect newDialect) {
- this.dialect = newDialect;
- return this;
- }
-
/**
* {@inheritDoc}
*/
@@ -305,12 +339,11 @@ public class DefaultConfiguration implements Configuration {
* {@inheritDoc}
*/
@Override
- public final Configuration set(Settings newSettings) {
- this.settings = newSettings != null
- ? SettingsTools.clone(newSettings)
- : SettingsTools.defaultSettings();
+ public final Configuration set(RecordListenerProvider... newRecordListenerProviders) {
+ this.recordListenerProviders = newRecordListenerProviders != null
+ ? newRecordListenerProviders
+ : new RecordListenerProvider[0];
- this.mapping = new SchemaMapping(this);
return this;
}
@@ -330,26 +363,40 @@ public class DefaultConfiguration implements Configuration {
* {@inheritDoc}
*/
@Override
- public final Configuration set(RecordListenerProvider... newRecordListenerProviders) {
- this.recordListenerProviders = newRecordListenerProviders != null
- ? newRecordListenerProviders
- : new RecordListenerProvider[0];
+ public final Configuration set(VisitListenerProvider... newVisitListenerProviders) {
+ this.visitListenerProviders = newVisitListenerProviders != null
+ ? newVisitListenerProviders
+ : new VisitListenerProvider[0];
return this;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final Configuration set(SQLDialect newDialect) {
+ this.dialect = newDialect;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final Configuration set(Settings newSettings) {
+ this.settings = newSettings != null
+ ? SettingsTools.clone(newSettings)
+ : SettingsTools.defaultSettings();
+
+ this.mapping = new SchemaMapping(this);
+ return this;
+ }
+
// -------------------------------------------------------------------------
// XXX: Getters
// -------------------------------------------------------------------------
- /**
- * {@inheritDoc}
- */
- @Override
- public final SQLDialect dialect() {
- return dialect;
- }
-
/**
* {@inheritDoc}
*/
@@ -362,7 +409,7 @@ public class DefaultConfiguration implements Configuration {
* {@inheritDoc}
*/
@Override
- public RecordMapperProvider recordMapperProvider() {
+ public final RecordMapperProvider recordMapperProvider() {
return recordMapperProvider;
}
@@ -370,9 +417,32 @@ public class DefaultConfiguration implements Configuration {
* {@inheritDoc}
*/
@Override
- @Deprecated
- public final org.jooq.SchemaMapping schemaMapping() {
- return mapping;
+ public final RecordListenerProvider[] recordListenerProviders() {
+ return recordListenerProviders;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final ExecuteListenerProvider[] executeListenerProviders() {
+ return executeListenerProviders;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final VisitListenerProvider[] visitListenerProviders() {
+ return visitListenerProviders;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final SQLDialect dialect() {
+ return dialect;
}
/**
@@ -411,16 +481,9 @@ public class DefaultConfiguration implements Configuration {
* {@inheritDoc}
*/
@Override
- public final ExecuteListenerProvider[] executeListenerProviders() {
- return executeListenerProviders;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public RecordListenerProvider[] recordListenerProviders() {
- return recordListenerProviders;
+ @Deprecated
+ public final org.jooq.SchemaMapping schemaMapping() {
+ return mapping;
}
@Override
@@ -452,6 +515,7 @@ public class DefaultConfiguration implements Configuration {
oos.writeObject(cloneSerializables(executeListenerProviders));
oos.writeObject(cloneSerializables(recordListenerProviders));
+ oos.writeObject(cloneSerializables(visitListenerProviders));
}
private E[] cloneSerializables(E[] array) {
@@ -473,5 +537,6 @@ public class DefaultConfiguration implements Configuration {
recordMapperProvider = (RecordMapperProvider) ois.readObject();
executeListenerProviders = (ExecuteListenerProvider[]) ois.readObject();
recordListenerProviders = (RecordListenerProvider[]) ois.readObject();
+ visitListenerProviders = (VisitListenerProvider[]) ois.readObject();
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
index e69e65b9a9..cd7df82898 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java
@@ -202,7 +202,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
}
public DefaultDSLContext(SQLDialect dialect, Settings settings) {
- this(new DefaultConfiguration(new NoConnectionProvider(), null, null, null, dialect, settings, null));
+ this(new DefaultConfiguration(new NoConnectionProvider(), null, null, null, null, dialect, settings, null));
}
public DefaultDSLContext(Connection connection, SQLDialect dialect) {
@@ -210,7 +210,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
}
public DefaultDSLContext(Connection connection, SQLDialect dialect, Settings settings) {
- this(new DefaultConfiguration(new DefaultConnectionProvider(connection), null, null, null, dialect, settings, null));
+ this(new DefaultConfiguration(new DefaultConnectionProvider(connection), null, null, null, null, dialect, settings, null));
}
public DefaultDSLContext(DataSource datasource, SQLDialect dialect) {
@@ -218,7 +218,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
}
public DefaultDSLContext(DataSource datasource, SQLDialect dialect, Settings settings) {
- this(new DefaultConfiguration(new DataSourceConnectionProvider(datasource), null, null, null, dialect, settings, null));
+ this(new DefaultConfiguration(new DataSourceConnectionProvider(datasource), null, null, null, null, dialect, settings, null));
}
public DefaultDSLContext(ConnectionProvider connectionProvider, SQLDialect dialect) {
@@ -226,7 +226,7 @@ public class DefaultDSLContext implements DSLContext, Serializable {
}
public DefaultDSLContext(ConnectionProvider connectionProvider, SQLDialect dialect, Settings settings) {
- this(new DefaultConfiguration(connectionProvider, null, null, null, dialect, settings, null));
+ this(new DefaultConfiguration(connectionProvider, null, null, null, null, dialect, settings, null));
}
public DefaultDSLContext(Configuration configuration) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultVisitListenerProvider.java b/jOOQ/src/main/java/org/jooq/impl/DefaultVisitListenerProvider.java
new file mode 100644
index 0000000000..b50171581b
--- /dev/null
+++ b/jOOQ/src/main/java/org/jooq/impl/DefaultVisitListenerProvider.java
@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
+ * All rights reserved.
+ *
+ * This software is licensed to you under the Apache License, Version 2.0
+ * (the "License"); You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name "jOOQ" nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jooq.impl;
+
+import java.io.Serializable;
+
+import org.jooq.VisitListener;
+import org.jooq.VisitListenerProvider;
+
+/**
+ * A default implementation for {@link VisitListenerProvider}.
+ *
+ * This implementation just wraps an instance of {@link VisitListener}, always
+ * providing the same.
+ *
+ * @author Lukas Eder
+ */
+public class DefaultVisitListenerProvider implements VisitListenerProvider, Serializable {
+
+ /**
+ * Generated UID.
+ */
+ private static final long serialVersionUID = -2122007794302549679L;
+
+ /**
+ * The delegate listener.
+ */
+ private final VisitListener listener;
+
+ /**
+ * Convenience method to construct an array of
+ * DefaultVisitListenerProvider from an array of
+ * VisitListener instances.
+ */
+ public static VisitListenerProvider[] providers(VisitListener... listeners) {
+ VisitListenerProvider[] result = new VisitListenerProvider[listeners.length];
+
+ for (int i = 0; i < listeners.length; i++) {
+ result[i] = new DefaultVisitListenerProvider(listeners[i]);
+ }
+
+ return result;
+ }
+
+ /**
+ * Create a new provider instance from an argument listener.
+ *
+ * @param listener The argument listener.
+ */
+ public DefaultVisitListenerProvider(VisitListener listener) {
+ this.listener = listener;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public final VisitListener provide() {
+ return listener;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return listener.toString();
+ }
+}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java
index 0ad3a87aba..b7ca33137b 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DeleteQueryImpl.java
@@ -37,12 +37,14 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.DELETE;
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
import java.util.Collection;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.DeleteQuery;
@@ -131,4 +133,9 @@ class DeleteQueryImpl extends AbstractQuery implements DeleteQ
public final void bind(BindContext context) {
context.visit(getFrom()).visit(getWhere());
}
+
+ @Override
+ public final Clause clause() {
+ return DELETE;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/DivideBy.java b/jOOQ/src/main/java/org/jooq/impl/DivideBy.java
index ffb4ecf423..5d99773eb7 100644
--- a/jOOQ/src/main/java/org/jooq/impl/DivideBy.java
+++ b/jOOQ/src/main/java/org/jooq/impl/DivideBy.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.condition;
import static org.jooq.impl.DSL.exists;
import static org.jooq.impl.DSL.notExists;
@@ -74,7 +75,7 @@ implements
this.divisor = divisor;
this.condition = new ConditionProviderImpl();
- this.returning = new QueryPartList>();
+ this.returning = new QueryPartList>(DUMMY);
}
// ------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/Dual.java b/jOOQ/src/main/java/org/jooq/impl/Dual.java
index 1ebe11f3eb..5dbe4b9355 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Dual.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Dual.java
@@ -36,7 +36,10 @@
package org.jooq.impl;
+import static org.jooq.Clause.TABLE;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Schema;
@@ -124,6 +127,11 @@ class Dual extends AbstractTable {
@Override
public final void bind(BindContext context) {}
+ @Override
+ public final Clause clause() {
+ return TABLE;
+ }
+
@Override
final Fields fields0() {
return new Fields();
diff --git a/jOOQ/src/main/java/org/jooq/impl/Expression.java b/jOOQ/src/main/java/org/jooq/impl/Expression.java
index 24337b6472..08c888ddf0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Expression.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Expression.java
@@ -36,6 +36,7 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
@@ -99,7 +100,7 @@ class Expression extends AbstractFunction {
this.operator = operator;
this.lhs = lhs;
- this.rhs = new QueryPartList>(rhs);
+ this.rhs = new QueryPartList>(DUMMY, rhs);
}
@Override
diff --git a/jOOQ/src/main/java/org/jooq/impl/FalseCondition.java b/jOOQ/src/main/java/org/jooq/impl/FalseCondition.java
index 96e0a01402..4bf2eac11a 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FalseCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FalseCondition.java
@@ -36,7 +36,10 @@
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_COMPARISON;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.RenderContext;
/**
@@ -54,5 +57,10 @@ class FalseCondition extends AbstractCondition {
context.sql("1 = 0");
}
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
+
FalseCondition() {}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldCondition.java b/jOOQ/src/main/java/org/jooq/impl/FieldCondition.java
index 00c2e10217..f3034e4e2e 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FieldCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FieldCondition.java
@@ -35,10 +35,12 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.condition;
import static org.jooq.impl.DSL.inline;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.QueryPartInternal;
@@ -69,6 +71,11 @@ class FieldCondition extends AbstractCondition {
delegate(ctx.configuration()).bind(ctx);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final QueryPartInternal delegate(Configuration configuration) {
switch (configuration.dialect().family()) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java
index 786004bdf8..8881179cff 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapForInsert.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.Utils.visitAll;
import java.util.Collection;
@@ -42,6 +43,7 @@ import java.util.Iterator;
import java.util.Map;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -136,6 +138,11 @@ class FieldMapForInsert extends AbstractQueryPartMap, Field>> {
visitAll(context, values());
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
final void putFields(Collection extends Field>> fields) {
for (Field> field : fields) {
put(field, null);
diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java
index a92062ca68..d959a06869 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapForUpdate.java
@@ -36,12 +36,15 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.DUMMY;
+import static org.jooq.Clause.UPDATE_SET_ASSIGNMENT;
import static org.jooq.SQLDialect.POSTGRES;
import static org.jooq.SQLDialect.SQLITE;
import java.util.Map;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -79,11 +82,13 @@ class FieldMapForUpdate extends AbstractQueryPartMap, Field>> {
context.formatNewLine();
}
- context.qualify(supportsQualify)
+ context.start(UPDATE_SET_ASSIGNMENT)
+ .qualify(supportsQualify)
.visit(entry.getKey())
.qualify(restoreQualify)
.sql(" = ")
- .visit(entry.getValue());
+ .visit(entry.getValue())
+ .end(UPDATE_SET_ASSIGNMENT);
separator = ", ";
}
@@ -101,6 +106,11 @@ class FieldMapForUpdate extends AbstractQueryPartMap, Field>> {
}
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
final void set(Map extends Field>, ?> map) {
for (Entry extends Field>, ?> entry : map.entrySet()) {
Field> field = entry.getKey();
diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java
index e4b0947502..12fa47f343 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java
@@ -35,12 +35,14 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.Utils.visitAll;
import java.util.ArrayList;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Select;
@@ -137,6 +139,11 @@ class FieldMapsForInsert extends AbstractQueryPart {
visitAll(context, insertMaps);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
// -------------------------------------------------------------------------
// The FieldMapsForInsert API
// -------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/Fields.java b/jOOQ/src/main/java/org/jooq/impl/Fields.java
index 8aeb3c7264..f7be7f3bff 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Fields.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Fields.java
@@ -36,14 +36,17 @@
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import java.util.Collection;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.Record;
-import org.jooq.RenderContext;
import org.jooq.RecordType;
+import org.jooq.RenderContext;
/**
* A simple wrapper for Field[], providing some useful lookup
@@ -246,12 +249,17 @@ class Fields extends AbstractQueryPart implements RecordType>(fields).toSQL(context);
+ new QueryPartList>(DUMMY, fields).toSQL(context);
}
@Override
public final void bind(BindContext context) {
- new QueryPartList>(fields).bind(context);
+ new QueryPartList>(DUMMY, fields).bind(context);
+ }
+
+ @Override
+ public final Clause clause() {
+ return DUMMY;
}
// -------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/FlashbackTable.java b/jOOQ/src/main/java/org/jooq/impl/FlashbackTable.java
index 8762f03d5c..bc61dd1177 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FlashbackTable.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FlashbackTable.java
@@ -35,10 +35,12 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.keyword;
import static org.jooq.impl.DSL.val;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.QueryPart;
import org.jooq.Record;
@@ -143,6 +145,11 @@ implements VersionsBetweenAndStep {
}
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
public final boolean declaresTables() {
return true;
diff --git a/jOOQ/src/main/java/org/jooq/impl/Function.java b/jOOQ/src/main/java/org/jooq/impl/Function.java
index 552138bf4a..72dcb59f50 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Function.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Function.java
@@ -37,6 +37,7 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
import static org.jooq.SQLDialect.H2;
@@ -54,6 +55,7 @@ import java.util.Collection;
import org.jooq.AggregateFunction;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.Name;
@@ -136,10 +138,10 @@ class Function extends AbstractField implements
this.term = null;
this.name = null;
this.distinct = distinct;
- this.arguments = new QueryPartList(arguments);
+ this.arguments = new QueryPartList(DUMMY, arguments);
this.keepDenseRankOrderBy = new SortFieldList();
this.withinGroupOrderBy = new SortFieldList();
- this.partitionBy = new QueryPartList>();
+ this.partitionBy = new QueryPartList>(DUMMY);
this.orderBy = new SortFieldList();
}
@@ -149,10 +151,10 @@ class Function extends AbstractField implements
this.term = term;
this.name = null;
this.distinct = distinct;
- this.arguments = new QueryPartList(arguments);
+ this.arguments = new QueryPartList(DUMMY, arguments);
this.keepDenseRankOrderBy = new SortFieldList();
this.withinGroupOrderBy = new SortFieldList();
- this.partitionBy = new QueryPartList>();
+ this.partitionBy = new QueryPartList>(DUMMY);
this.orderBy = new SortFieldList();
}
@@ -162,10 +164,10 @@ class Function extends AbstractField implements
this.term = null;
this.name = name;
this.distinct = distinct;
- this.arguments = new QueryPartList(arguments);
+ this.arguments = new QueryPartList(DUMMY, arguments);
this.keepDenseRankOrderBy = new SortFieldList();
this.withinGroupOrderBy = new SortFieldList();
- this.partitionBy = new QueryPartList>();
+ this.partitionBy = new QueryPartList>(DUMMY);
this.orderBy = new SortFieldList();
}
@@ -182,8 +184,12 @@ class Function extends AbstractField implements
// -------------------------------------------------------------------------
@Override
- public final void bind(BindContext context) {
+ public final Clause clause() {
+ return DUMMY;
+ }
+ @Override
+ public final void bind(BindContext context) {
if (term == LIST_AGG && asList(CUBRID, H2, HSQLDB, MARIADB, MYSQL).contains(context.configuration().dialect())) {
context.visit(arguments.get(0));
context.visit(withinGroupOrderBy);
diff --git a/jOOQ/src/main/java/org/jooq/impl/FunctionTable.java b/jOOQ/src/main/java/org/jooq/impl/FunctionTable.java
index 11e62c0a13..a7adc63f50 100644
--- a/jOOQ/src/main/java/org/jooq/impl/FunctionTable.java
+++ b/jOOQ/src/main/java/org/jooq/impl/FunctionTable.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.Record;
import org.jooq.RenderContext;
@@ -101,6 +104,11 @@ class FunctionTable extends AbstractTable {
}
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
final Fields fields0() {
return new Fields();
diff --git a/jOOQ/src/main/java/org/jooq/impl/InCondition.java b/jOOQ/src/main/java/org/jooq/impl/InCondition.java
index 5ab2a40f3d..24cce4e561 100644
--- a/jOOQ/src/main/java/org/jooq/impl/InCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/InCondition.java
@@ -36,12 +36,16 @@
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_IN;
+import static org.jooq.Clause.CONDITION_IN_NOT;
+import static org.jooq.Comparator.IN;
import static org.jooq.impl.Utils.visitAll;
import java.util.Arrays;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -64,6 +68,11 @@ class InCondition extends AbstractCondition {
this.comparator = comparator;
}
+ @Override
+ public final Clause clause() {
+ return comparator == IN ? CONDITION_IN : CONDITION_IN_NOT;
+ }
+
@Override
public final void bind(BindContext context) {
context.visit(field);
@@ -93,11 +102,13 @@ class InCondition extends AbstractCondition {
// operator
if (comparator == Comparator.IN) {
context.formatSeparator()
- .keyword("or ");
+ .keyword("or")
+ .sql(" ");
}
else {
context.formatSeparator()
- .keyword("and ");
+ .keyword("and")
+ .sql(" ");
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java
index d9d22da1f2..e559e45187 100644
--- a/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/InsertQueryImpl.java
@@ -37,6 +37,8 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.INSERT;
+import static org.jooq.Clause.INSERT_RETURNING;
import static org.jooq.SQLDialect.MARIADB;
import static org.jooq.SQLDialect.MYSQL;
@@ -45,6 +47,7 @@ import java.util.List;
import java.util.Map;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -313,16 +316,23 @@ class InsertQueryImpl extends AbstractStoreQuery implements
}
}
+ @Override
+ public final Clause clause() {
+ return INSERT;
+ }
+
private final void toSQLInsert(RenderContext context) {
- context.keyword("insert ")
+ context.keyword("insert")
+ .sql(" ")
// [#1295] MySQL natively supports the IGNORE keyword
.keyword((onDuplicateKeyIgnore && asList(MARIADB, MYSQL).contains(context.configuration().dialect())) ? "ignore " : "")
- .keyword("into ")
+ .keyword("into")
+ .sql(" ")
.visit(getInto())
.sql(" ")
.visit(insertMaps);
- toSQLReturning(context);
+ toSQLReturning(context, INSERT_RETURNING);
}
private final void bindInsert(BindContext context) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/InsertSelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/InsertSelectQueryImpl.java
index 9a8449d719..c6a5f12abe 100644
--- a/jOOQ/src/main/java/org/jooq/impl/InsertSelectQueryImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/InsertSelectQueryImpl.java
@@ -35,9 +35,11 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.INSERT;
import static org.jooq.impl.Utils.visitAll;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.Insert;
@@ -70,7 +72,8 @@ class InsertSelectQueryImpl extends AbstractQuery implements I
@Override
public final void toSQL(RenderContext context) {
- context.keyword("insert into ")
+ context.keyword("insert into")
+ .sql(" ")
.visit(into)
.sql(" (");
@@ -93,4 +96,9 @@ class InsertSelectQueryImpl extends AbstractQuery implements I
visitAll(context, fields);
context.visit(select);
}
+
+ @Override
+ public final Clause clause() {
+ return INSERT;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/IsDistinctFrom.java b/jOOQ/src/main/java/org/jooq/impl/IsDistinctFrom.java
index 23db495833..2e973fd9ea 100644
--- a/jOOQ/src/main/java/org/jooq/impl/IsDistinctFrom.java
+++ b/jOOQ/src/main/java/org/jooq/impl/IsDistinctFrom.java
@@ -36,6 +36,7 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
@@ -53,6 +54,7 @@ import static org.jooq.impl.DSL.one;
import static org.jooq.impl.DSL.zero;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -94,6 +96,11 @@ class IsDistinctFrom extends AbstractCondition {
delegate(context.configuration()).bind(context);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
/**
* Get a delegate CompareCondition, in case the context
* {@link SQLDialect} natively supports the IS DISTINCT FROM
diff --git a/jOOQ/src/main/java/org/jooq/impl/IsNull.java b/jOOQ/src/main/java/org/jooq/impl/IsNull.java
index 18f496e702..7507ebbee6 100644
--- a/jOOQ/src/main/java/org/jooq/impl/IsNull.java
+++ b/jOOQ/src/main/java/org/jooq/impl/IsNull.java
@@ -36,7 +36,11 @@
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_NULL;
+import static org.jooq.Clause.CONDITION_NULL_NOT;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -62,6 +66,11 @@ class IsNull extends AbstractCondition {
@Override
public final void toSQL(RenderContext context) {
- context.visit(field).keyword(isNull ? " is null" : " is not null");
+ context.visit(field).sql(" ").keyword(isNull ? "is null" : "is not null");
+ }
+
+ @Override
+ public final Clause clause() {
+ return isNull ? CONDITION_NULL : CONDITION_NULL_NOT;
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java
index 85b8af04d7..a1e921894a 100644
--- a/jOOQ/src/main/java/org/jooq/impl/JoinTable.java
+++ b/jOOQ/src/main/java/org/jooq/impl/JoinTable.java
@@ -36,6 +36,19 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.DUMMY;
+import static org.jooq.Clause.TABLE_JOIN;
+import static org.jooq.Clause.TABLE_JOIN_CROSS;
+import static org.jooq.Clause.TABLE_JOIN_INNER;
+import static org.jooq.Clause.TABLE_JOIN_NATURAL;
+import static org.jooq.Clause.TABLE_JOIN_NATURAL_OUTER_LEFT;
+import static org.jooq.Clause.TABLE_JOIN_NATURAL_OUTER_RIGHT;
+import static org.jooq.Clause.TABLE_JOIN_ON;
+import static org.jooq.Clause.TABLE_JOIN_OUTER_FULL;
+import static org.jooq.Clause.TABLE_JOIN_OUTER_LEFT;
+import static org.jooq.Clause.TABLE_JOIN_OUTER_RIGHT;
+import static org.jooq.Clause.TABLE_JOIN_PARTITION_BY;
+import static org.jooq.Clause.TABLE_JOIN_USING;
import static org.jooq.JoinType.CROSS_JOIN;
import static org.jooq.JoinType.JOIN;
import static org.jooq.JoinType.LEFT_OUTER_JOIN;
@@ -59,6 +72,7 @@ import java.util.Collection;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Field;
import org.jooq.ForeignKey;
@@ -101,11 +115,11 @@ class JoinTable extends AbstractTable implements TableOptionalOnStep, Ta
this.lhs = lhs.asTable();
this.rhs = rhs.asTable();
- this.rhsPartitionBy = new QueryPartList>();
+ this.rhsPartitionBy = new QueryPartList>(DUMMY);
this.type = type;
this.condition = new ConditionProviderImpl();
- this.using = new QueryPartList>();
+ this.using = new QueryPartList>(DUMMY);
}
// ------------------------------------------------------------------------
@@ -125,10 +139,14 @@ class JoinTable extends AbstractTable implements TableOptionalOnStep, Ta
@Override
public final void toSQL(RenderContext context) {
+ JoinType translatedType = translateType(context);
+ Clause translatedClause = translateClause(translatedType);
+
context.visit(lhs)
.formatIndentStart()
.formatSeparator()
- .keyword(translateType(context).toSQL())
+ .start(translatedClause)
+ .keyword(translatedType.toSQL())
.sql(" ");
// [#671] Some databases formally require nested JOINS to be
@@ -151,20 +169,41 @@ class JoinTable extends AbstractTable implements TableOptionalOnStep, Ta
// OUTER JOINed table
if (!rhsPartitionBy.isEmpty()) {
context.formatSeparator()
- .keyword("partition by (")
+ .start(TABLE_JOIN_PARTITION_BY)
+ .keyword("partition by")
+ .sql(" (")
.visit(rhsPartitionBy)
- .sql(")");
+ .sql(")")
+ .end(TABLE_JOIN_PARTITION_BY);
}
// CROSS JOIN and NATURAL JOIN do not have any condition clauses
if (!asList(CROSS_JOIN,
NATURAL_JOIN,
NATURAL_LEFT_OUTER_JOIN,
- NATURAL_RIGHT_OUTER_JOIN).contains(translateType(context))) {
+ NATURAL_RIGHT_OUTER_JOIN).contains(translatedType)) {
toSQLJoinCondition(context);
}
- context.formatIndentEnd();
+ context.end(translatedClause)
+ .formatIndentEnd();
+ }
+
+ /**
+ * Translate the join type into a join clause
+ */
+ final Clause translateClause(JoinType translatedType) {
+ switch (translatedType) {
+ case JOIN: return TABLE_JOIN_INNER;
+ case CROSS_JOIN: return TABLE_JOIN_CROSS;
+ case NATURAL_JOIN: return TABLE_JOIN_NATURAL;
+ case LEFT_OUTER_JOIN: return TABLE_JOIN_OUTER_LEFT;
+ case RIGHT_OUTER_JOIN: return TABLE_JOIN_OUTER_RIGHT;
+ case FULL_OUTER_JOIN: return TABLE_JOIN_OUTER_FULL;
+ case NATURAL_LEFT_OUTER_JOIN: return TABLE_JOIN_NATURAL_OUTER_LEFT;
+ case NATURAL_RIGHT_OUTER_JOIN: return TABLE_JOIN_NATURAL_OUTER_RIGHT;
+ default: throw new IllegalArgumentException("Bad join type: " + translatedType);
+ }
}
/**
@@ -210,24 +249,38 @@ class JoinTable extends AbstractTable implements TableOptionalOnStep, Ta
// [#582] Some dialects don't explicitly support a JOIN .. USING
// syntax. This can be simulated with JOIN .. ON
if (asList(ASE, CUBRID, DB2, H2, SQLSERVER, SYBASE).contains(context.configuration().dialect().family())) {
- String glue = "on ";
+ boolean first = true;
for (Field> field : using) {
- context.formatSeparator()
- .keyword(glue)
+ context.formatSeparator();
+
+ if (first) {
+ first = false;
+
+ context.start(TABLE_JOIN_ON)
+ .keyword("on");
+ }
+ else {
+ context.keyword("and");
+ }
+
+ context.sql(" ")
.visit(lhs.field(field))
.sql(" = ")
.visit(rhs.field(field));
-
- glue = "and ";
}
+
+ context.end(TABLE_JOIN_ON);
}
// Native supporters of JOIN .. USING
else {
context.formatSeparator()
- .keyword("using (");
+ .start(TABLE_JOIN_USING)
+ .keyword("using")
+ .sql("( ");
Utils.fieldNames(context, using);
- context.sql(")");
+ context.sql(")")
+ .end(TABLE_JOIN_USING);
}
}
@@ -237,27 +290,41 @@ class JoinTable extends AbstractTable implements TableOptionalOnStep, Ta
simulateNaturalLeftOuterJoin(context) ||
simulateNaturalRightOuterJoin(context)) {
- String glue = "on ";
+ boolean first = true;
for (Field> field : lhs.fields()) {
Field> other = rhs.field(field);
if (other != null) {
- context.formatSeparator()
- .keyword(glue)
+ context.formatSeparator();
+
+ if (first) {
+ first = false;
+
+ context.start(TABLE_JOIN_ON)
+ .keyword("on");
+ }
+ else {
+ context.keyword("and");
+ }
+
+ context.sql(" ")
.visit(field)
.sql(" = ")
.visit(other);
-
- glue = "and ";
}
}
+
+ context.end(TABLE_JOIN_ON);
}
// Regular JOIN condition
else {
context.formatSeparator()
- .keyword("on ")
- .visit(condition);
+ .start(TABLE_JOIN_ON)
+ .keyword("on")
+ .sql(" ")
+ .visit(condition)
+ .end(TABLE_JOIN_ON);
}
}
@@ -273,6 +340,11 @@ class JoinTable extends AbstractTable implements TableOptionalOnStep, Ta
}
}
+ @Override
+ public final Clause clause() {
+ return TABLE_JOIN;
+ }
+
@Override
public final Table as(String alias) {
return new TableAlias(this, alias, true);
diff --git a/jOOQ/src/main/java/org/jooq/impl/KeywordImpl.java b/jOOQ/src/main/java/org/jooq/impl/KeywordImpl.java
index de8cb92730..a8beaf03c0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/KeywordImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/KeywordImpl.java
@@ -36,6 +36,7 @@
package org.jooq.impl;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Keyword;
import org.jooq.RenderContext;
@@ -64,4 +65,9 @@ public class KeywordImpl extends AbstractQueryPart implements Keyword {
@Override
public final void bind(BindContext ctx) {}
+
+ @Override
+ public final Clause clause() {
+ return null;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/Limit.java b/jOOQ/src/main/java/org/jooq/impl/Limit.java
index 810440a2e5..afeabb4cfa 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Limit.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Limit.java
@@ -35,12 +35,14 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.RenderContext.CastMode.NEVER;
import static org.jooq.conf.ParamType.INLINED;
import static org.jooq.impl.DSL.inline;
import static org.jooq.impl.DSL.val;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.Param;
import org.jooq.RenderContext;
@@ -320,6 +322,11 @@ class Limit extends AbstractQueryPart {
}
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
/**
* Whether this limit has an offset of zero
*/
diff --git a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java
index 63b3a9c626..2c86e64636 100644
--- a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java
@@ -35,6 +35,8 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+import static org.jooq.Clause.MERGE;
import static org.jooq.SQLDialect.H2;
import static org.jooq.impl.DSL.condition;
import static org.jooq.impl.DSL.exists;
@@ -52,6 +54,7 @@ import java.util.Map;
import java.util.Set;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -230,7 +233,7 @@ implements
if (fields != null) {
h2Style = true;
- h2Fields = new QueryPartList>(fields);
+ h2Fields = new QueryPartList>(DUMMY, fields);
}
}
@@ -240,7 +243,7 @@ implements
QueryPartList> getH2Fields() {
if (h2Fields == null) {
- h2Fields = new QueryPartList>(table.fields());
+ h2Fields = new QueryPartList>(DUMMY, table.fields());
}
return h2Fields;
@@ -248,7 +251,7 @@ implements
QueryPartList> getH2Keys() {
if (h2Keys == null) {
- h2Keys = new QueryPartList>();
+ h2Keys = new QueryPartList>(DUMMY);
}
return h2Keys;
@@ -256,7 +259,7 @@ implements
QueryPartList> getH2Values() {
if (h2Values == null) {
- h2Values = new QueryPartList>();
+ h2Values = new QueryPartList>(DUMMY);
}
return h2Values;
@@ -1194,4 +1197,9 @@ implements
.visit(notMatchedInsert)
.visit(notMatchedWhere);
}
+
+ @Override
+ public final Clause clause() {
+ return MERGE;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/NameImpl.java b/jOOQ/src/main/java/org/jooq/impl/NameImpl.java
index 265f1d9727..b3b10cdf04 100644
--- a/jOOQ/src/main/java/org/jooq/impl/NameImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/NameImpl.java
@@ -35,9 +35,12 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import java.util.Arrays;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Name;
import org.jooq.RenderContext;
@@ -72,6 +75,11 @@ class NameImpl extends AbstractQueryPart implements Name {
@Override
public final void bind(BindContext context) {}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
public final String[] getName() {
return qualifiedName;
diff --git a/jOOQ/src/main/java/org/jooq/impl/NotCondition.java b/jOOQ/src/main/java/org/jooq/impl/NotCondition.java
index 2922e2caf7..063f7e419d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/NotCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/NotCondition.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_NOT;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.RenderContext;
@@ -58,4 +61,9 @@ class NotCondition extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(condition);
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_NOT;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/PackageImpl.java b/jOOQ/src/main/java/org/jooq/impl/PackageImpl.java
index b7ae1bc71f..56ab174c80 100644
--- a/jOOQ/src/main/java/org/jooq/impl/PackageImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/PackageImpl.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Package;
import org.jooq.RenderContext;
import org.jooq.SQLDialect;
@@ -85,6 +88,11 @@ public class PackageImpl extends AbstractQueryPart implements Package {
@Override
public final void bind(BindContext context) {}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
// ------------------------------------------------------------------------
// XXX: Object API
// ------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/ParameterImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParameterImpl.java
index 63913eb432..177f2882dd 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ParameterImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ParameterImpl.java
@@ -36,7 +36,10 @@
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.DataType;
import org.jooq.Parameter;
@@ -82,12 +85,17 @@ class ParameterImpl extends AbstractQueryPart implements Parameter {
return type.getType();
}
+ @Override
+ public final void toSQL(RenderContext context) {
+ context.literal(getName());
+ }
+
@Override
public final void bind(BindContext context) {}
@Override
- public final void toSQL(RenderContext context) {
- context.literal(getName());
+ public final Clause clause() {
+ return DUMMY;
}
@Override
diff --git a/jOOQ/src/main/java/org/jooq/impl/Pivot.java b/jOOQ/src/main/java/org/jooq/impl/Pivot.java
index 173469b123..a13ca8947a 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Pivot.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Pivot.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.conf.ParamType.INLINED;
import static org.jooq.impl.DSL.trueCondition;
import static org.jooq.impl.DSL.using;
@@ -44,6 +45,7 @@ import java.util.Collection;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -145,6 +147,11 @@ implements
.declareTables(false);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private Table select(Configuration configuration) {
List> groupingFields = new ArrayList>();
List> aliasedGroupingFields = new ArrayList>();
@@ -261,6 +268,11 @@ implements
.visit(table)
.declareTables(declareTables);
}
+
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
}
/**
@@ -317,6 +329,11 @@ implements
context.visit(pivot(context.configuration()));
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
public final Table as(String alias) {
return new TableAlias(this, alias, true);
diff --git a/jOOQ/src/main/java/org/jooq/impl/QualifiedTable.java b/jOOQ/src/main/java/org/jooq/impl/QualifiedTable.java
index da5a510e50..491fa18bea 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QualifiedTable.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QualifiedTable.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.TABLE;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Table;
@@ -79,6 +82,11 @@ class QualifiedTable extends AbstractTable {
@Override
public final void bind(BindContext context) {}
+ @Override
+ public final Clause clause() {
+ return TABLE;
+ }
+
@Override
public final Class extends Record> getRecordType() {
return RecordImpl.class;
diff --git a/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java b/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java
index d18774442a..84fb63fb40 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java
@@ -37,7 +37,10 @@
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_COMPARISON;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Field;
import org.jooq.QuantifiedSelect;
@@ -73,4 +76,9 @@ class QuantifiedComparisonCondition extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(field).visit(query);
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/QuantifiedSelectImpl.java b/jOOQ/src/main/java/org/jooq/impl/QuantifiedSelectImpl.java
index ca6e5eca04..d832c416eb 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QuantifiedSelectImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QuantifiedSelectImpl.java
@@ -35,9 +35,11 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.table;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.QuantifiedSelect;
@@ -114,6 +116,11 @@ class QuantifiedSelectImpl extends AbstractQueryPart implement
}
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final QueryPart part(Configuration context) {
if (query != null) {
return query;
diff --git a/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java b/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java
index 136f7f42f9..e34740f2f7 100644
--- a/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java
+++ b/jOOQ/src/main/java/org/jooq/impl/QueryPartList.java
@@ -36,6 +36,7 @@
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.Utils.visitAll;
import java.util.ArrayList;
@@ -46,6 +47,7 @@ import java.util.List;
import java.util.ListIterator;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.QueryPart;
import org.jooq.RenderContext;
@@ -55,22 +57,26 @@ import org.jooq.RenderContext;
class QueryPartList extends AbstractQueryPart implements List {
private static final long serialVersionUID = -2936922742534009564L;
- private final List wrappedList = new ArrayList();
+ private final List wrappedList;
+ private final Clause clause;
- QueryPartList() {
- this((Collection) null);
+ QueryPartList(Clause clause) {
+ this(clause, (Collection) null);
}
- QueryPartList(Collection extends T> wrappedList) {
+ QueryPartList(Clause clause, Collection extends T> wrappedList) {
super();
+ this.clause = clause;
+ this.wrappedList = new ArrayList();
+
if (wrappedList != null) {
addAll(wrappedList);
}
}
- QueryPartList(T... wrappedList) {
- this(Arrays.asList(wrappedList));
+ QueryPartList(Clause clause, T... wrappedList) {
+ this(clause, Arrays.asList(wrappedList));
}
@Override
@@ -78,7 +84,13 @@ class QueryPartList extends AbstractQueryPart implements Li
// Some lists render different SQL when empty
if (isEmpty()) {
+// if (clause != null && clause != DUMMY)
+// context.start(clause);
+
toSQLEmptyList(context);
+
+// if (clause != null && clause != DUMMY)
+// context.end(clause);
}
else {
@@ -94,7 +106,14 @@ class QueryPartList extends AbstractQueryPart implements Li
if (indent)
context.formatNewLine();
+// if (clause != null && clause != DUMMY)
+// context.start(clause);
+
context.visit(queryPart);
+
+// if (clause != null && clause != DUMMY)
+// context.end(clause);
+
separator = ", ";
}
@@ -108,6 +127,11 @@ class QueryPartList extends AbstractQueryPart implements Li
visitAll(context, wrappedList);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
/**
* Subclasses may override this method
*/
diff --git a/jOOQ/src/main/java/org/jooq/impl/RegexpLike.java b/jOOQ/src/main/java/org/jooq/impl/RegexpLike.java
index 34d468e52f..2c6a08b246 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RegexpLike.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RegexpLike.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -69,7 +72,9 @@ class RegexpLike extends AbstractCondition {
case SQLITE:
case SYBASE: {
context.visit(search)
- .keyword(" regexp ")
+ .sql(" ")
+ .keyword("regexp")
+ .sql(" ")
.visit(pattern);
break;
@@ -109,7 +114,9 @@ class RegexpLike extends AbstractCondition {
case SQLSERVER:
default: {
context.visit(search)
- .keyword(" like_regex ")
+ .sql(" ")
+ .keyword("like_regex")
+ .sql(" ")
.visit(pattern);
break;
@@ -121,4 +128,9 @@ class RegexpLike extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(search).visit(pattern);
}
+
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/Rollup.java b/jOOQ/src/main/java/org/jooq/impl/Rollup.java
index c66d359972..12a6824fcf 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Rollup.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Rollup.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.field;
import static org.jooq.impl.DSL.function;
@@ -61,7 +62,7 @@ class Rollup extends AbstractFunction {
case CUBRID:
case MARIADB:
case MYSQL:
- return field("{0} {with rollup}", new QueryPartList>(getArguments()));
+ return field("{0} {with rollup}", new QueryPartList>(DUMMY, getArguments()));
default:
return function("rollup", Object.class, getArguments());
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowBetweenCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowBetweenCondition.java
index c9513223a7..c246ff632c 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowBetweenCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowBetweenCondition.java
@@ -36,6 +36,8 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.CONDITION_BETWEEN;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
@@ -76,6 +78,7 @@ import org.jooq.BetweenAndStep8;
import org.jooq.BetweenAndStep9;
import org.jooq.BetweenAndStepN;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -685,6 +688,11 @@ implements
delegate(context.configuration()).toSQL(context);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final QueryPartInternal delegate(Configuration configuration) {
// These casts are safe for RowImpl
RowN r = (RowN) row;
@@ -727,11 +735,17 @@ implements
@Override
public final void toSQL(RenderContext context) {
context.visit(row)
- .keyword(not ? " not" : "")
- .keyword(" between ")
- .keyword(symmetric ? "symmetric " : "")
+ .sql(not ? " " : "")
+ .keyword(not ? "not" : "")
+ .sql(" ")
+ .keyword("between")
+ .sql(" ")
+ .keyword(symmetric ? "symmetric" : "")
+ .sql(symmetric ? " " : "")
.visit(minValue)
- .keyword(" and ")
+ .sql(" ")
+ .keyword("and")
+ .sql(" ")
.visit(maxValue);
}
@@ -739,5 +753,10 @@ implements
public final void bind(BindContext context) {
context.visit(row).visit(minValue).visit(maxValue);
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_BETWEEN;
+ }
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowCondition.java
index 25e12b5687..3406029182 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowCondition.java
@@ -36,6 +36,8 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.CONDITION_COMPARISON;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.Comparator.EQUALS;
import static org.jooq.Comparator.GREATER;
import static org.jooq.Comparator.GREATER_OR_EQUAL;
@@ -57,6 +59,7 @@ import java.util.ArrayList;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Configuration;
@@ -98,6 +101,11 @@ class RowCondition extends AbstractCondition {
delegate(context.configuration()).bind(context);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final QueryPartInternal delegate(Configuration configuration) {
SQLDialect dialect = configuration.dialect();
@@ -206,5 +214,10 @@ class RowCondition extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(left).visit(right);
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
}
}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowImpl.java b/jOOQ/src/main/java/org/jooq/impl/RowImpl.java
index 837975ebe9..ff6b82fd3d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowImpl.java
@@ -35,6 +35,7 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.row;
import java.util.Arrays;
@@ -66,6 +67,7 @@ import org.jooq.BetweenAndStep8;
import org.jooq.BetweenAndStep9;
import org.jooq.BetweenAndStepN;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.DataType;
@@ -200,6 +202,11 @@ implements
context.visit(fields);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
// ------------------------------------------------------------------------
// XXX: Row accessor API
// ------------------------------------------------------------------------
@@ -9910,13 +9917,13 @@ implements
@Override
public final Condition in(Collection rows) {
- QueryPartList list = new QueryPartList(rows);
+ QueryPartList list = new QueryPartList(DUMMY, rows);
return new RowInCondition(this, list, Comparator.IN);
}
@Override
public final Condition notIn(Collection rows) {
- QueryPartList list = new QueryPartList(rows);
+ QueryPartList list = new QueryPartList(DUMMY, rows);
return new RowInCondition(this, list, Comparator.NOT_IN);
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowInCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowInCondition.java
index 5b5098e7a0..78b1cf5ff4 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowInCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowInCondition.java
@@ -36,7 +36,11 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.CONDITION_IN;
+import static org.jooq.Clause.CONDITION_IN_NOT;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.Comparator.EQUALS;
+import static org.jooq.Comparator.IN;
import static org.jooq.Comparator.NOT_IN;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.DB2;
@@ -51,6 +55,7 @@ import java.util.ArrayList;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Configuration;
@@ -89,6 +94,11 @@ class RowInCondition extends AbstractCondition {
delegate(context.configuration()).bind(context);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final QueryPartInternal delegate(Configuration configuration) {
if (asList(ASE, DB2, DERBY, FIREBIRD, INGRES, SQLSERVER, SQLITE, SYBASE).contains(configuration.dialect().family())) {
List conditions = new ArrayList();
@@ -131,5 +141,10 @@ class RowInCondition extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(left).visit(right);
}
+
+ @Override
+ public final Clause clause() {
+ return comparator == IN ? CONDITION_IN : CONDITION_IN_NOT;
+ }
}
}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java b/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java
index ab0f9c29e5..88a6e8ef24 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowIsNull.java
@@ -36,6 +36,9 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.CONDITION_NULL;
+import static org.jooq.Clause.CONDITION_NULL_NOT;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
import static org.jooq.SQLDialect.DERBY;
@@ -53,6 +56,7 @@ import java.util.ArrayList;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -89,6 +93,11 @@ class RowIsNull extends AbstractCondition {
delegate(context.configuration()).bind(context);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final QueryPartInternal delegate(Configuration configuration) {
// CUBRID 9.0.0 and HSQLDB have buggy implementations of the NULL predicate.
@@ -125,5 +134,10 @@ class RowIsNull extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(row);
}
+
+ @Override
+ public final Clause clause() {
+ return isNull ? CONDITION_NULL : CONDITION_NULL_NOT;
+ }
}
}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowOverlapsCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowOverlapsCondition.java
index 52a2cc6c94..d4e80249ab 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowOverlapsCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowOverlapsCondition.java
@@ -36,6 +36,8 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.CONDITION_OVERLAPS;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
@@ -51,6 +53,7 @@ import static org.jooq.SQLDialect.SQLSERVER;
import static org.jooq.SQLDialect.SYBASE;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.DataType;
import org.jooq.Field;
@@ -86,6 +89,11 @@ class RowOverlapsCondition extends AbstractCondition {
delegate(context.configuration()).bind(context);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final QueryPartInternal delegate(Configuration configuration) {
Field left1 = left.field1();
Field left2 = left.field2();
@@ -152,5 +160,10 @@ class RowOverlapsCondition extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(left).visit(right);
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_OVERLAPS;
+ }
}
}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/impl/RowSubqueryCondition.java b/jOOQ/src/main/java/org/jooq/impl/RowSubqueryCondition.java
index 151e13a3f2..aa6c61e46d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/RowSubqueryCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/RowSubqueryCondition.java
@@ -36,6 +36,8 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.CONDITION_COMPARISON;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.Comparator.EQUALS;
import static org.jooq.Comparator.IN;
import static org.jooq.Comparator.NOT_EQUALS;
@@ -58,6 +60,7 @@ import java.util.ArrayList;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Configuration;
@@ -100,6 +103,11 @@ class RowSubqueryCondition extends AbstractCondition {
delegate(context.configuration(), null).bind(context);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
private final QueryPartInternal delegate(Configuration configuration, RenderContext context) {
SQLDialect family = configuration.dialect().family();
@@ -214,5 +222,10 @@ class RowSubqueryCondition extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(left).visit(right);
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
}
}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLCondition.java b/jOOQ/src/main/java/org/jooq/impl/SQLCondition.java
index 363ca8d267..2f2e0fd0cf 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SQLCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SQLCondition.java
@@ -35,8 +35,12 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.QueryPart;
+import org.jooq.QueryPartInternal;
import org.jooq.RenderContext;
class SQLCondition extends AbstractCondition {
@@ -70,4 +74,13 @@ class SQLCondition extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(delegate);
}
+
+ @Override
+ public final Clause clause() {
+ if (delegate instanceof QueryPartInternal) {
+ return ((QueryPartInternal) delegate).clause();
+ }
+
+ return CONDITION;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLField.java b/jOOQ/src/main/java/org/jooq/impl/SQLField.java
index 7c6e923201..89fcf8a315 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SQLField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SQLField.java
@@ -35,9 +35,13 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.FIELD;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.DataType;
import org.jooq.QueryPart;
+import org.jooq.QueryPartInternal;
import org.jooq.RenderContext;
class SQLField extends AbstractField {
@@ -68,4 +72,13 @@ class SQLField extends AbstractField {
public final void bind(BindContext context) {
context.visit(delegate);
}
+
+ @Override
+ public final Clause clause() {
+ if (delegate instanceof QueryPartInternal) {
+ return ((QueryPartInternal) delegate).clause();
+ }
+
+ return FIELD;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLQuery.java b/jOOQ/src/main/java/org/jooq/impl/SQLQuery.java
index fb9f37a615..a0fc23bb5d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SQLQuery.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SQLQuery.java
@@ -36,8 +36,10 @@
package org.jooq.impl;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.QueryPart;
+import org.jooq.QueryPartInternal;
import org.jooq.RenderContext;
/**
@@ -71,4 +73,13 @@ class SQLQuery extends AbstractQuery {
public final void bind(BindContext context) {
context.visit(delegate);
}
+
+ @Override
+ public final Clause clause() {
+ if (delegate instanceof QueryPartInternal) {
+ return ((QueryPartInternal) delegate).clause();
+ }
+
+ return null;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLResultQuery.java b/jOOQ/src/main/java/org/jooq/impl/SQLResultQuery.java
index 3b8a296f30..c13ef074b9 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SQLResultQuery.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SQLResultQuery.java
@@ -38,9 +38,11 @@ package org.jooq.impl;
import java.sql.ResultSetMetaData;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.QueryPart;
+import org.jooq.QueryPartInternal;
import org.jooq.Record;
import org.jooq.RenderContext;
@@ -78,6 +80,15 @@ class SQLResultQuery extends AbstractResultQuery {
context.visit(delegate);
}
+ @Override
+ public final Clause clause() {
+ if (delegate instanceof QueryPartInternal) {
+ return ((QueryPartInternal) delegate).clause();
+ }
+
+ return null;
+ }
+
@Override
public final Class extends Record> getRecordType() {
return RecordImpl.class;
diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLTable.java b/jOOQ/src/main/java/org/jooq/impl/SQLTable.java
index 9470d05499..88e116a14f 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SQLTable.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SQLTable.java
@@ -35,8 +35,12 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.TABLE;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.QueryPart;
+import org.jooq.QueryPartInternal;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Table;
@@ -85,6 +89,15 @@ class SQLTable extends AbstractTable {
context.visit(delegate);
}
+ @Override
+ public final Clause clause() {
+ if (delegate instanceof QueryPartInternal) {
+ return ((QueryPartInternal) delegate).clause();
+ }
+
+ return TABLE;
+ }
+
@Override
final Fields fields0() {
return new Fields();
diff --git a/jOOQ/src/main/java/org/jooq/impl/SQLTemplate.java b/jOOQ/src/main/java/org/jooq/impl/SQLTemplate.java
index a24616c2f2..b6e2286bc5 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SQLTemplate.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SQLTemplate.java
@@ -38,6 +38,7 @@ package org.jooq.impl;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.QueryPart;
import org.jooq.RenderContext;
import org.jooq.Template;
@@ -79,5 +80,10 @@ class SQLTemplate implements Template {
public final void bind(BindContext context) {
Utils.renderAndBind(null, context, sql, substitutes);
}
+
+ @Override
+ public final Clause clause() {
+ return null;
+ }
}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SchemaImpl.java b/jOOQ/src/main/java/org/jooq/impl/SchemaImpl.java
index 18a0fd43ec..b4569cef59 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SchemaImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SchemaImpl.java
@@ -36,10 +36,13 @@
package org.jooq.impl;
+import static org.jooq.Clause.SCHEMA;
+
import java.util.Collections;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.RenderContext;
import org.jooq.Schema;
import org.jooq.Sequence;
@@ -70,12 +73,17 @@ public class SchemaImpl extends AbstractQueryPart implements Schema {
return schemaName;
}
+ @Override
+ public final void toSQL(RenderContext context) {
+ context.literal(getName());
+ }
+
@Override
public final void bind(BindContext context) {}
@Override
- public final void toSQL(RenderContext context) {
- context.literal(getName());
+ public final Clause clause() {
+ return SCHEMA;
}
@Override
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectFieldList.java b/jOOQ/src/main/java/org/jooq/impl/SelectFieldList.java
index b2b551ab97..30959d1284 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectFieldList.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectFieldList.java
@@ -36,6 +36,8 @@
package org.jooq.impl;
+import static org.jooq.Clause.FIELD;
+
import java.util.Collection;
import org.jooq.Field;
@@ -49,15 +51,15 @@ class SelectFieldList extends QueryPartList> {
private static final long serialVersionUID = 8850104968428500798L;
SelectFieldList() {
- super();
+ super(FIELD);
}
SelectFieldList(Collection extends Field>> wrappedList) {
- super(wrappedList);
+ super(FIELD, wrappedList);
}
SelectFieldList(Field>... wrappedList) {
- super(wrappedList);
+ super(FIELD, wrappedList);
}
@Override
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java
index 75ab96f213..72e7a00d56 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsExistsCondition.java
@@ -36,7 +36,12 @@
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_EXISTS;
+import static org.jooq.Clause.CONDITION_EXISTS_NOT;
+import static org.jooq.impl.ExistsOperator.EXISTS;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.RenderContext;
import org.jooq.Select;
@@ -96,4 +101,9 @@ class SelectQueryAsExistsCondition extends AbstractCondition {
.subquery(false);
}
}
+
+ @Override
+ public final Clause clause() {
+ return operator == EXISTS ? CONDITION_EXISTS : CONDITION_EXISTS_NOT;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java
index c9a3b8064a..3bf32885d1 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsField.java
@@ -37,6 +37,7 @@
package org.jooq.impl;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -101,4 +102,9 @@ class SelectQueryAsField extends AbstractField {
.sql(")");
}
}
+
+ @Override
+ public final Clause clause() {
+ return null;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsSubQueryCondition.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsSubQueryCondition.java
index 0abd47b881..0f13cf1010 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsSubQueryCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsSubQueryCondition.java
@@ -36,7 +36,10 @@
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_COMPARISON;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Comparator;
import org.jooq.Field;
import org.jooq.RenderContext;
@@ -105,4 +108,9 @@ class SelectQueryAsSubQueryCondition extends AbstractCondition {
.subquery(false);
}
}
+
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsTable.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsTable.java
index badae9c2b2..2b7b78c2f0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsTable.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryAsTable.java
@@ -37,6 +37,7 @@
package org.jooq.impl;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Select;
@@ -112,4 +113,9 @@ class SelectQueryAsTable extends AbstractTable {
.subquery(false);
}
}
+
+ @Override
+ public final Clause clause() {
+ return null;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java
index 2fb5f059bb..92ca04b8c4 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java
@@ -36,6 +36,16 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.DUMMY;
+import static org.jooq.Clause.SELECT;
+import static org.jooq.Clause.SELECT_CONNECT_BY;
+import static org.jooq.Clause.SELECT_FROM;
+import static org.jooq.Clause.SELECT_GROUP_BY;
+import static org.jooq.Clause.SELECT_HAVING;
+import static org.jooq.Clause.SELECT_ORDER_BY;
+import static org.jooq.Clause.SELECT_SELECT;
+import static org.jooq.Clause.SELECT_START_WITH;
+import static org.jooq.Clause.SELECT_WHERE;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DERBY;
@@ -62,6 +72,7 @@ import java.util.Collection;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -140,7 +151,7 @@ class SelectQueryImpl extends AbstractSelect implements Sel
this.condition = new ConditionProviderImpl();
this.connectBy = new ConditionProviderImpl();
this.connectByStartWith = new ConditionProviderImpl();
- this.groupBy = new QueryPartList();
+ this.groupBy = new QueryPartList(DUMMY);
this.having = new ConditionProviderImpl();
this.orderBy = new SortFieldList();
this.limit = new Limit();
@@ -149,10 +160,15 @@ class SelectQueryImpl extends AbstractSelect implements Sel
this.from.add(from.asTable());
}
- this.forUpdateOf = new QueryPartList>();
+ this.forUpdateOf = new QueryPartList>(DUMMY);
this.forUpdateOfTables = new TableList();
}
+ @Override
+ public final Clause clause() {
+ return SELECT;
+ }
+
@Override
public final void bind(BindContext context) {
context.declareFields(true)
@@ -323,7 +339,6 @@ class SelectQueryImpl extends AbstractSelect implements Sel
context.formatSeparator()
.sql(option);
}
-
}
/**
@@ -434,7 +449,9 @@ class SelectQueryImpl extends AbstractSelect implements Sel
// SELECT clause
// -------------
- context.keyword("select ");
+ context.start(SELECT_SELECT)
+ .keyword("select")
+ .sql(" ");
// [#1493] Oracle hints come directly after the SELECT keyword
if (!StringUtils.isBlank(hint)) {
@@ -442,7 +459,7 @@ class SelectQueryImpl extends AbstractSelect implements Sel
}
if (distinct) {
- context.keyword("distinct ");
+ context.keyword("distinct").sql(" ");
}
// Sybase and SQL Server have leading TOP clauses
@@ -527,15 +544,24 @@ class SelectQueryImpl extends AbstractSelect implements Sel
.paramType(paramType);
}
- context.declareFields(false);
+ context.declareFields(false)
+ .end(SELECT_SELECT);
// FROM and JOIN clauses
// ---------------------
- context.declareTables(true);
+ context.start(SELECT_FROM)
+ .declareTables(true);
- if (!context.render(getFrom()).isEmpty()) {
+ // The simplest way to see if no FROM clause needs to be rendered is to
+ // render it. But use a new RenderContext (without any VisitListeners)
+ // for that purpose!
+ DefaultConfiguration c = new DefaultConfiguration(context.configuration().dialect());
+ String renderedFrom = new DefaultRenderContext(c).render(getFrom());
+
+ if (!renderedFrom.isEmpty()) {
context.formatSeparator()
- .keyword("from ")
+ .keyword("from")
+ .sql(" ")
.visit(getFrom());
// [#1681] Sybase ASE and Ingres need a cross-joined dummy table
@@ -545,32 +571,61 @@ class SelectQueryImpl extends AbstractSelect implements Sel
}
}
- context.declareTables(false);
+ context.declareTables(false)
+ .end(SELECT_FROM);
// WHERE clause
// ------------
+ context.start(SELECT_WHERE);
+
if (!(getWhere().getWhere() instanceof TrueCondition)) {
context.formatSeparator()
- .keyword("where ")
+ .keyword("where")
+ .sql(" ")
.visit(getWhere());
}
+ context.end(SELECT_WHERE);
+
// CONNECT BY clause
// -----------------
- if (!(getConnectBy().getWhere() instanceof TrueCondition)) {
- // CUBRID supports this clause only as [ START WITH .. ] CONNECT BY
- // Oracle also knows the CONNECT BY .. [ START WITH ] alternative
- // syntax
- toSQLStartWith(context);
- toSQLConnectBy(context);
+ // CUBRID supports this clause only as [ START WITH .. ] CONNECT BY
+ // Oracle also knows the CONNECT BY .. [ START WITH ] alternative
+ // syntax
+ context.start(SELECT_START_WITH);
+
+ if (!(getConnectByStartWith().getWhere() instanceof TrueCondition)) {
+ context.formatSeparator()
+ .keyword("start with")
+ .sql(" ")
+ .visit(getConnectByStartWith());
}
+ context.end(SELECT_START_WITH);
+ context.start(SELECT_CONNECT_BY);
+
+ if (!(getConnectBy().getWhere() instanceof TrueCondition)) {
+ context.formatSeparator()
+ .keyword("connect by");
+
+ if (connectByNoCycle) {
+ context.keyword(" nocycle");
+ }
+
+ context.sql(" ").visit(getConnectBy());
+ }
+
+ context.end(SELECT_CONNECT_BY);
+
// GROUP BY and HAVING clause
// --------------------------
+ context.start(SELECT_GROUP_BY);
+
if (grouping) {
context.formatSeparator()
- .keyword("group by ");
+ .keyword("group by")
+ .sql(" ");
// [#1665] Empty GROUP BY () clauses need parentheses
if (getGroupBy().isEmpty()) {
@@ -595,19 +650,33 @@ class SelectQueryImpl extends AbstractSelect implements Sel
}
}
+ context.end(SELECT_GROUP_BY);
+
+ // HAVING clause
+ // -------------
+ context.start(SELECT_HAVING);
+
if (!(getHaving().getWhere() instanceof TrueCondition)) {
context.formatSeparator()
- .keyword("having ")
+ .keyword("having")
+ .sql(" ")
.visit(getHaving());
}
+ context.end(SELECT_HAVING);
+
// ORDER BY clause
// ---------------
+ context.start(SELECT_ORDER_BY);
+
if (!getOrderBy().isEmpty()) {
context.formatSeparator()
- .keyword("order ")
- .keyword(orderBySiblings ? "siblings " : "")
- .keyword("by ")
+ .keyword("order")
+ .sql(orderBySiblings ? " " : "")
+ .keyword(orderBySiblings ? "siblings" : "")
+ .sql(" ")
+ .keyword("by")
+ .sql(" ")
.visit(getOrderBy());
}
@@ -615,27 +684,11 @@ class SelectQueryImpl extends AbstractSelect implements Sel
// OFFSET .. FETCH
else if (getLimit().isApplicable() && asList(SQLSERVER, SQLSERVER2012).contains(dialect)){
context.formatSeparator()
- .keyword("order by 1");
- }
- }
-
- private void toSQLStartWith(RenderContext context) {
- if (!(getConnectByStartWith().getWhere() instanceof TrueCondition)) {
- context.formatSeparator()
- .keyword("start with ")
- .visit(getConnectByStartWith());
- }
- }
-
- private void toSQLConnectBy(RenderContext context) {
- context.formatSeparator()
- .keyword("connect by");
-
- if (connectByNoCycle) {
- context.keyword(" nocycle");
+ .keyword("order by")
+ .sql(" 1");
}
- context.sql(" ").visit(getConnectBy());
+ context.end(SELECT_ORDER_BY);
}
@Override
diff --git a/jOOQ/src/main/java/org/jooq/impl/SortFieldImpl.java b/jOOQ/src/main/java/org/jooq/impl/SortFieldImpl.java
index 92fbc5044d..a32593d94c 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SortFieldImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SortFieldImpl.java
@@ -35,11 +35,13 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.DSL.nvl2;
import static org.jooq.impl.DSL.one;
import static org.jooq.impl.DSL.zero;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.RenderContext;
import org.jooq.SortField;
@@ -122,10 +124,10 @@ class SortFieldImpl extends AbstractQueryPart implements SortField {
.keyword(order.toSQL());
if (nullsFirst) {
- context.keyword(" nulls first");
+ context.sql(" ").keyword("nulls first");
}
else {
- context.keyword(" nulls last");
+ context.sql(" ").keyword("nulls last");
}
break;
@@ -162,4 +164,9 @@ class SortFieldImpl extends AbstractQueryPart implements SortField {
context.visit(field);
}
+
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/SortFieldList.java b/jOOQ/src/main/java/org/jooq/impl/SortFieldList.java
index 9f05642e9a..7b56fb6586 100644
--- a/jOOQ/src/main/java/org/jooq/impl/SortFieldList.java
+++ b/jOOQ/src/main/java/org/jooq/impl/SortFieldList.java
@@ -36,6 +36,8 @@
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -55,7 +57,7 @@ class SortFieldList extends QueryPartList> {
}
SortFieldList(List> wrappedList) {
- super(wrappedList);
+ super(DUMMY, wrappedList);
}
void addAll(Field>... fields) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/TableAlias.java b/jOOQ/src/main/java/org/jooq/impl/TableAlias.java
index bca3428e47..6480395833 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TableAlias.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TableAlias.java
@@ -36,10 +36,13 @@
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import java.util.ArrayList;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Field;
import org.jooq.ForeignKey;
import org.jooq.Record;
@@ -125,6 +128,11 @@ class TableAlias extends AbstractTable {
context.visit(alias);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
public final Table as(String as) {
return alias.wrapped().as(as);
diff --git a/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java
index 1a38fd22de..d3ae226db5 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TableFieldImpl.java
@@ -36,7 +36,10 @@
package org.jooq.impl;
+import static org.jooq.Clause.FIELD;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.DataType;
import org.jooq.Record;
import org.jooq.RenderContext;
@@ -79,6 +82,11 @@ class TableFieldImpl extends AbstractField implements Ta
@Override
public final void bind(BindContext context) {}
+ @Override
+ public final Clause clause() {
+ return FIELD;
+ }
+
// ------------------------------------------------------------------------
// XXX: Object API
// ------------------------------------------------------------------------
diff --git a/jOOQ/src/main/java/org/jooq/impl/TableImpl.java b/jOOQ/src/main/java/org/jooq/impl/TableImpl.java
index cab6fb07fe..f118e013e1 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TableImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TableImpl.java
@@ -36,7 +36,10 @@
package org.jooq.impl;
+import static org.jooq.Clause.TABLE;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Schema;
@@ -89,6 +92,16 @@ public class TableImpl extends AbstractTable {
return null;
}
+ @Override
+ final Fields fields0() {
+ return fields;
+ }
+
+ @Override
+ public final Clause clause() {
+ return TABLE;
+ }
+
@Override
public final void bind(BindContext context) {
if (alias != null) {
@@ -96,11 +109,6 @@ public class TableImpl extends AbstractTable {
}
}
- @Override
- final Fields fields0() {
- return fields;
- }
-
@Override
public final void toSQL(RenderContext context) {
if (alias != null) {
diff --git a/jOOQ/src/main/java/org/jooq/impl/TableList.java b/jOOQ/src/main/java/org/jooq/impl/TableList.java
index 934339085f..21789634c0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TableList.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TableList.java
@@ -36,6 +36,8 @@
package org.jooq.impl;
+import static org.jooq.Clause.TABLE;
+
import java.util.List;
import org.jooq.Field;
@@ -50,11 +52,11 @@ class TableList extends QueryPartList> {
private static final long serialVersionUID = -8545559185481762229L;
TableList() {
- super();
+ super(TABLE);
}
TableList(List extends Table>> wrappedList) {
- super(wrappedList);
+ super(TABLE, wrappedList);
}
@Override
diff --git a/jOOQ/src/main/java/org/jooq/impl/TrueCondition.java b/jOOQ/src/main/java/org/jooq/impl/TrueCondition.java
index ae23b3b3be..1eb4a0758b 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TrueCondition.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TrueCondition.java
@@ -36,7 +36,10 @@
package org.jooq.impl;
+import static org.jooq.Clause.CONDITION_COMPARISON;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.RenderContext;
/**
@@ -54,5 +57,10 @@ class TrueCondition extends AbstractCondition {
context.sql("1 = 1");
}
+ @Override
+ public final Clause clause() {
+ return CONDITION_COMPARISON;
+ }
+
TrueCondition() {}
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/TruncateImpl.java b/jOOQ/src/main/java/org/jooq/impl/TruncateImpl.java
index 95276eca6b..19730eb1fb 100644
--- a/jOOQ/src/main/java/org/jooq/impl/TruncateImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/TruncateImpl.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.TRUNCATE;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Record;
import org.jooq.RenderContext;
@@ -132,4 +135,9 @@ class TruncateImpl extends AbstractQuery implements
public final void bind(BindContext context) {
context.visit(table);
}
+
+ @Override
+ public final Clause clause() {
+ return TRUNCATE;
+ }
}
diff --git a/jOOQ/src/main/java/org/jooq/impl/UDTImpl.java b/jOOQ/src/main/java/org/jooq/impl/UDTImpl.java
index 719ac3eaec..cb85b2c1fd 100644
--- a/jOOQ/src/main/java/org/jooq/impl/UDTImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/UDTImpl.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.Record;
@@ -136,6 +139,11 @@ public class UDTImpl> extends AbstractQueryPart implement
context.visit(fields);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
/**
* Subclasses may call this method to create {@link UDTField} objects that
* are linked to this table.
diff --git a/jOOQ/src/main/java/org/jooq/impl/Union.java b/jOOQ/src/main/java/org/jooq/impl/Union.java
index 88afe182dd..0227bf4812 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Union.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Union.java
@@ -35,12 +35,17 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.SELECT_EXCEPT;
+import static org.jooq.Clause.SELECT_INTERSECT;
+import static org.jooq.Clause.SELECT_UNION;
+import static org.jooq.Clause.SELECT_UNION_ALL;
import static org.jooq.impl.Utils.visitAll;
import java.util.ArrayList;
import java.util.List;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Configuration;
import org.jooq.Field;
import org.jooq.Record;
@@ -63,10 +68,10 @@ class Union extends AbstractSelect {
Union(Configuration configuration, Select query1, Select extends R> query2, CombineOperator operator) {
super(configuration);
- this.operator = operator;
this.queries = new ArrayList>();
this.queries.add(query1);
this.queries.add(query2);
+ this.operator = operator;
}
@Override
@@ -128,6 +133,17 @@ class Union extends AbstractSelect {
visitAll(context, queries);
}
+ @Override
+ public final Clause clause() {
+ switch (operator) {
+ case EXCEPT: return SELECT_EXCEPT;
+ case INTERSECT: return SELECT_INTERSECT;
+ case UNION: return SELECT_UNION;
+ case UNION_ALL: return SELECT_UNION_ALL;
+ default: throw new IllegalArgumentException("Operator not supported : " + operator);
+ }
+ }
+
@Override
final boolean isForUpdate() {
return false;
diff --git a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java
index a693e017cc..d83aa05019 100644
--- a/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/UpdateQueryImpl.java
@@ -37,6 +37,12 @@
package org.jooq.impl;
import static java.util.Arrays.asList;
+import static org.jooq.Clause.UPDATE;
+import static org.jooq.Clause.UPDATE_RETURNING;
+import static org.jooq.Clause.UPDATE_SET;
+import static org.jooq.Clause.UPDATE_SET_ASSIGNMENT;
+import static org.jooq.Clause.UPDATE_UPDATE;
+import static org.jooq.Clause.UPDATE_WHERE;
import static org.jooq.SQLDialect.INGRES;
import static org.jooq.SQLDialect.ORACLE;
import static org.jooq.impl.DSL.select;
@@ -47,6 +53,7 @@ import java.util.Map;
import javax.annotation.Generated;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.Field;
@@ -445,18 +452,24 @@ class UpdateQueryImpl extends AbstractStoreQuery implements
@Override
public final void toSQL(RenderContext context) {
- context.keyword("update ")
+ context.start(UPDATE_UPDATE)
+ .keyword("update")
+ .sql(" ")
.declareTables(true)
.visit(getInto())
.declareTables(false)
+ .end(UPDATE_UPDATE)
.formatSeparator()
- .keyword("set ");
+ .start(UPDATE_SET)
+ .keyword("set")
+ .sql(" ");
// A multi-row update was specified
if (multiRow != null) {
boolean qualify = context.qualify();
- context.qualify(false)
+ context.start(UPDATE_SET_ASSIGNMENT)
+ .qualify(false)
.visit(multiRow)
.qualify(qualify)
.sql(" = ");
@@ -467,7 +480,7 @@ class UpdateQueryImpl extends AbstractStoreQuery implements
context.visit(multiValue);
}
- // Subselects or subselect simulatinos of row value expressions
+ // Subselects or subselect simulations of row value expressions
else {
Select> select = multiSelect;
@@ -485,6 +498,8 @@ class UpdateQueryImpl extends AbstractStoreQuery implements
.formatNewLine()
.sql(")");
}
+
+ context.end(UPDATE_SET_ASSIGNMENT);
}
// A regular (non-multi-row) update was specified
@@ -494,13 +509,17 @@ class UpdateQueryImpl extends AbstractStoreQuery implements
.formatIndentLockEnd();
}
+ context.end(UPDATE_SET);
+
if (!(getWhere() instanceof TrueCondition)) {
context.formatSeparator()
+ .start(UPDATE_WHERE)
.keyword("where ")
- .visit(getWhere());
+ .visit(getWhere())
+ .end(UPDATE_WHERE);
}
- toSQLReturning(context);
+ toSQLReturning(context, UPDATE_RETURNING);
}
@Override
@@ -530,6 +549,11 @@ class UpdateQueryImpl extends AbstractStoreQuery implements
bindReturning(context);
}
+ @Override
+ public final Clause clause() {
+ return UPDATE;
+ }
+
@Override
public final boolean isExecutable() {
return updateMap.size() > 0 || multiRow != null;
diff --git a/jOOQ/src/main/java/org/jooq/impl/Values.java b/jOOQ/src/main/java/org/jooq/impl/Values.java
index 22e1f26bfb..dd48eb3c9d 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Values.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Values.java
@@ -35,9 +35,11 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
import static org.jooq.impl.Utils.visitAll;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Row;
@@ -158,6 +160,11 @@ class Values extends AbstractTable {
visitAll(context, rows);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
final Fields fields0() {
return new Fields(rows[0].fields());
diff --git a/jOOQ/src/main/java/org/jooq/impl/WithTable.java b/jOOQ/src/main/java/org/jooq/impl/WithTable.java
index 4aaaf735f6..82016866cd 100644
--- a/jOOQ/src/main/java/org/jooq/impl/WithTable.java
+++ b/jOOQ/src/main/java/org/jooq/impl/WithTable.java
@@ -35,7 +35,10 @@
*/
package org.jooq.impl;
+import static org.jooq.Clause.DUMMY;
+
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.Record;
import org.jooq.RenderContext;
import org.jooq.Table;
@@ -79,6 +82,11 @@ class WithTable extends AbstractTable {
context.visit(delegate);
}
+ @Override
+ public final Clause clause() {
+ return DUMMY;
+ }
+
@Override
public final Class extends R> getRecordType() {
return delegate.getRecordType();
diff --git a/jOOQ/src/main/java/org/jooq/impl/WrappedList.java b/jOOQ/src/main/java/org/jooq/impl/WrappedList.java
index 2c1c8d4d43..96a7703a1c 100644
--- a/jOOQ/src/main/java/org/jooq/impl/WrappedList.java
+++ b/jOOQ/src/main/java/org/jooq/impl/WrappedList.java
@@ -36,6 +36,7 @@
package org.jooq.impl;
import org.jooq.BindContext;
+import org.jooq.Clause;
import org.jooq.RenderContext;
/**
@@ -65,4 +66,9 @@ class WrappedList extends AbstractQueryPart {
public final void bind(BindContext context) {
context.visit(wrapped);
}
+
+ @Override
+ public final Clause clause() {
+ return null;
+ }
}
diff --git a/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java b/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java
new file mode 100644
index 0000000000..78d72adf01
--- /dev/null
+++ b/jOOQ/src/test/java/org/jooq/test/VisitContextTest.java
@@ -0,0 +1,133 @@
+/**
+ * Copyright (c) 2009-2013, Lukas Eder, lukas.eder@gmail.com
+ * All rights reserved.
+ *
+ * This software is licensed to you under the Apache License, Version 2.0
+ * (the "License"); You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * . Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * . Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * . Neither the name "jOOQ" nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.jooq.test;
+
+import static org.jooq.Clause.SELECT_WHERE;
+import static org.jooq.impl.DSL.select;
+import static org.jooq.impl.DSL.using;
+import static org.jooq.impl.DefaultVisitListenerProvider.providers;
+import static org.jooq.test.data.Table1.FIELD_ID1;
+import static org.jooq.test.data.Table1.FIELD_NAME1;
+import static org.jooq.test.data.Table1.TABLE1;
+import static org.jooq.tools.StringUtils.leftPad;
+
+import org.jooq.Clause;
+import org.jooq.Configuration;
+import org.jooq.VisitContext;
+import org.jooq.VisitListener;
+
+import org.junit.Test;
+
+/**
+ * Some common tests related to {@link VisitContext}
+ *
+ * @author Lukas Eder
+ */
+public class VisitContextTest extends AbstractTest {
+
+ @Test
+ public void testClauses() {
+ Configuration c = create.configuration().derive(providers(new ClausesListener()));
+
+// String sql =
+// using(c)
+// .select(FIELD_ID1, FIELD_NAME1)
+// .from(select(FIELD_NAME1).from(
+// TABLE1,
+// TABLE2.join(TABLE3).on("1 = 2")
+// .leftOuterJoin(TABLE3).on("1 = 1")))
+// .where(FIELD_ID1.eq(1))
+// .and(FIELD_NAME1.ne("3"))
+// .and("x = y")
+// .having(FIELD_ID1.eq(1))
+// .getSQL();
+ String sql =
+ using(c)
+ .select(FIELD_ID1, FIELD_NAME1)
+ .from(select(FIELD_NAME1).from(TABLE1))
+ .getSQL();
+
+ System.out.println();
+ System.out.println(sql);
+ }
+
+ private static class ClausesListener implements VisitListener {
+
+ Clause clause;
+ String where = "where";
+ int indent = 0;
+
+ @Override
+ public void clauseStart(VisitContext context) {
+ if (context.clause() == Clause.DUMMY)
+ return;
+
+ clause = context.clause();
+ indent += 2;
+ System.out.println(leftPad("+-", indent, "| ") + context.clause());
+ }
+
+ @Override
+ public void clauseEnd(VisitContext context) {
+ if (context.clause() == Clause.DUMMY)
+ return;
+
+ if (clause == SELECT_WHERE) {
+ if (context.renderContext() != null) {
+ context.renderContext()
+ .sql(" ")
+ .keyword(where)
+ .sql(" ")
+ .sql("SecurityCode IN (1, 2, 3)");
+ }
+ }
+
+ clause = null;
+ indent -= 2;
+ }
+
+ @Override
+ public void visitStart(VisitContext context) {
+ if (clause == SELECT_WHERE) {
+ where = "and";
+ }
+ }
+
+ @Override
+ public void visitEnd(VisitContext context) {
+ }
+ }
+}