[#2665] [#2667] [#2676] First API and implementation draft

* [#2665] Implement SPI for RenderContext and BindContext listening to
allow for custom SQL transformation
* [#2667] Add org.jooq.Clause and let org.jooq.Context listen on
start(Clause) and end(Clause) events - First API and implementation
draft
* [#2676] Add QueryPartInternal.clause() to allow for QueryParts to
return Clause information to org.jooq.Context
This commit is contained in:
Lukas Eder 2013-08-02 19:40:15 +02:00
parent 0f4297cc97
commit 1e5e4f5bf0
100 changed files with 2134 additions and 188 deletions

View File

@ -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.
* <p>
* This "clause" surrounds a complete table reference as it can be encountered
* in
* <ul>
* <li> {@link #SELECT_FROM}</li>
* <li> {@link #INSERT_INSERT_INTO}</li>
* <li> {@link #UPDATE_UPDATE}</li>
* <li> {@link #DELETE_DELETE}</li>
* <li> {@link #MERGE_MERGE_INTO}</li>
* <li> {@link #TRUNCATE_TRUNCATE}</li>
* </ul>
*/
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 <code>SELECT</code> statement or a subselect.
* <p>
* This "clause" surrounds a complete <code>SELECT</code> statement, a
* subselect, or a set operation, such as
* <ul>
* <li> {@link #SELECT_UNION}</li>
* <li> {@link #SELECT_UNION_ALL}</li>
* <li> {@link #SELECT_INTERSECT}</li>
* <li> {@link #SELECT_EXCEPT}</li>
* </ul>
*/
SELECT,
/**
* A <code>UNION</code> set operation.
* <p>
* This clause surrounds two or more subselects (see {@link #SELECT})
* concatenating them using a <code>UNION</code> set operation.
*/
SELECT_UNION,
/**
* A <code>UNION ALL</code> set operation.
* <p>
* This clause surrounds two or more subselects (see {@link #SELECT})
* concatenating them using a <code>UNION ALL</code> set operation.
*/
SELECT_UNION_ALL,
/**
* A <code>INTERSECT</code> set operation.
* <p>
* This clause surrounds two or more subselects (see {@link #SELECT})
* concatenating them using a <code>INTERSECT</code> set operation.
*/
SELECT_INTERSECT,
/**
* A <code>EXCEPT</code> set operation.
* <p>
* This clause surrounds two or more subselects (see {@link #SELECT})
* concatenating them using a <code>EXCEPT</code> set operation.
*/
SELECT_EXCEPT,
/**
* A <code>SELECT</code> clause within a {@link #SELECT} statement or
* subselect.
* <p>
* This clause surrounds
* <ul>
* <li>the <code>SELECT</code> keyword</li>
* <li>Oracle style hints</li>
* <li>the T-SQL style <code>TOP .. START AT</code> clause</li>
* <li>the select field list</li>
* </ul>
*/
SELECT_SELECT,
/**
* A <code>FROM</code> clause within a {@link #SELECT} statement or
* subselect.
* <p>
* This clause surrounds
* <ul>
* <li>the <code>FROM</code> keyword</li>
* <li>the table reference list</li>
* </ul>
* <p>
* 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,
}

View File

@ -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.
* <p>
* This method is not thread-safe and should not be used in globally
* available <code>Configuration</code> 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.
* <p>
@ -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.
*

View File

@ -120,6 +120,15 @@ public interface Context<C extends Context<C>> {
*/
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 <code>SELECT</code> clause of the query).

View File

@ -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.
* <p>
* {@link QueryPart}s can specify a <code>Clause</code> 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)}
* <p>
* This method is for JOOQ INTERNAL USE only. Do not reference directly
*
* @return The <code>Clause</code> represented by this query part or
* <code>null</code> if this query part does not represent a clause.
*/
Clause clause();
/**
* Check whether this {@link QueryPart} is able to declare fields in a
* <code>SELECT</code> clause.

View File

@ -35,6 +35,8 @@
*/
package org.jooq;
import java.util.EventListener;
/**
* A listener for manipulation events on {@link UpdatableRecord}s.
* <p>
@ -52,7 +54,7 @@ package org.jooq;
*
* @author Lukas Eder
*/
public interface RecordListener {
public interface RecordListener extends EventListener {
/**
* Called before storing an <code>UpdatableRecord</code>.

View File

@ -43,8 +43,8 @@ import org.jooq.impl.DefaultRecordListenerProvider;
* In order to facilitate the lifecycle management of
* <code>RecordListener</code> 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

View File

@ -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 <code>VisitContext</code>.
* <p>
* This corresponds to {@link Context#data()} returned from
* {@link #context()}.
*
* @return The custom data. This is never <code>null</code>
* @see VisitListener
*/
Map<Object, Object> data();
/**
* Get some custom data from this <code>VisitContext</code>.
* <p>
* 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 <code>null</code> if no such data is contained
* in this <code>VisitListener</code>
* @see VisitListener
*/
Object data(Object key);
/**
* Set some custom data to this <code>VisitContext</code>.
* <p>
* 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 <code>null</code> to unset the custom
* data
* @return The previously set custom data or <code>null</code> 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.
* <p>
* 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, <code>VisitContext</code>
* 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 <code>null</code>, if the underlying context is a {@link BindContext}.
*/
RenderContext renderContext();
/**
* The underlying {@link BindContext} or <code>null</code>, if the underlying context is a {@link RenderContext}.
*/
BindContext bindContext();
}

View File

@ -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.
* <p>
* 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:
* <ul>
* <li>The visit of a {@link Clause}</li>
* <li>The visit of a {@link QueryPart}</li>
* </ul>
* <p>
* The following rules apply to visiting clauses and query parts:
* <ul>
* <li>Clauses may "surround" a query part. See an example below.</li>
* <li>Not every query part is "surrounded" by a clause</li>
* </ul>
* <p>
* An example is given here:
* <code><pre>SELECT 1 FROM [A CROSS JOIN B]</pre></code>
* <p>
* The above example will create the following set of events:
*
* <pre>
* {@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")
* </pre>
* <p>
* 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);
}

View File

@ -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.
* <p>
* In order to facilitate the lifecycle management of <code>VisitListener</code>
* 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 <code>VisitListener</code> instance.
* <p>
* Implementations are free to choose whether this method returns new
* instances at every call or whether the same instance is returned
* repetitively.
* <p>
* A <code>VisitListener</code> shall be provided exactly once per
* <code>Context</code> traversal, i.e. per <code>RenderContext</code> or
* <code>BindContext</code>.
*
* @return A <code>VisitListener</code> instance.
* @see VisitListener
* @see VisitContext
* @see DefaultVisitListenerProvider
*/
VisitListener provide();
}

View File

@ -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<C extends Context<C>> implements Context<C> {
final Configuration configuration;
final Map<Object, Object> data;
boolean declareFields;
boolean declareTables;
boolean subquery;
int index;
final Configuration configuration;
final Map<Object, Object> data;
final VisitListener[] visitListeners;
private final DefaultVisitContext visitContext;
private final Deque<Clause> visitClauses;
private final Deque<QueryPart> visitParts;
boolean declareFields;
boolean declareTables;
boolean subquery;
int index;
AbstractContext(Configuration configuration) {
VisitListenerProvider[] providers = configuration.visitListenerProviders();
this.configuration = configuration;
this.data = new HashMap<Object, Object>();
this.visitListeners = new VisitListener[providers.length];
this.visitContext = new DefaultVisitContext();
this.visitClauses = new ArrayDeque<Clause>();
this.visitParts = new ArrayDeque<QueryPart>();
for (int i = 0; i < providers.length; i++) {
this.visitListeners[i] = providers[i].provide();
}
}
// ------------------------------------------------------------------------
@ -85,9 +110,112 @@ abstract class AbstractContext<C extends Context<C>> implements Context<C> {
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<Object, Object> 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<C extends Context<C>> implements Context<C> {
else {
visit0(internal);
}
end(part);
if (clause != null)
end(clause);
}
return (C) this;
}
/**
* Emit a clause from a query part being visited.
* <p>
* 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:
* <p>
* <code><pre>SELECT * FROM [A CROSS JOIN B]</pre></code>
* <p>
* The type of the above <code>JoinTable</code> modelling
* <code>A CROSS JOIN B</code> is not known to the surrounding
* <code>SELECT</code> 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
* <code>AbstractContext</code>.
*/
private final Clause clause(QueryPart part) {
if (part instanceof QueryPartInternal) {
return ((QueryPartInternal) part).clause();
}
return null;
}
protected abstract void visit0(QueryPartInternal internal);
@Override

View File

@ -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<Q extends Query> 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();

View File

@ -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<T> extends AbstractQueryPart implements Field<T> {
@Override
public abstract void bind(BindContext context);
@Override
public /* non-final for now */ Clause clause() {
return DUMMY;
}
// ------------------------------------------------------------------------
// XXX: API
// ------------------------------------------------------------------------

View File

@ -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<T> extends AbstractField<T> {
ctx.visit(getFunction0(ctx.configuration()));
}
@Override
public final Clause clause() {
return DUMMY;
}
final Field<?>[] getArguments() {
return arguments;
}

View File

@ -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<T> extends AbstractQueryPart implements Ro
}
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
public final void bind(BindContext context) {
for (Parameter<?> parameter : getParameters()) {

View File

@ -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<R extends Record> extends AbstractQuery implem
super(configuration);
this.into = into;
this.returning = new QueryPartList<Field<?>>();
this.returning = new QueryPartList<Field<?>>(DUMMY);
}
protected abstract Map<Field<?>, Field<?>> getValues();
@ -147,14 +149,17 @@ abstract class AbstractStoreQuery<R extends Record> 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:

View File

@ -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<Q extends QueryPart> extends AbstractQueryPart {
}
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
public final boolean declaresFields() {
return true;

View File

@ -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<Record> {
ctx.visit(table(ctx.configuration()));
}
@Override
public final Clause clause() {
return DUMMY;
}
private final Table<Record> table(Configuration configuration) {
switch (configuration.dialect().family()) {
case ORACLE: {
@ -296,6 +303,11 @@ class ArrayTable extends AbstractTable<Record> {
context.visit(array);
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
final Fields<Record> fields0() {
return ArrayTable.this.fields0();

View File

@ -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<Record> {
ctx.visit(table(ctx.configuration()));
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
final Fields<Record> fields0() {
return field;

View File

@ -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<T> extends AbstractCondition implements BetweenAndStep<T>
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<T> extends AbstractCondition implements BetweenAndStep<T>
public final void bind(BindContext context) {
context.visit(field).visit(minValue).visit(maxValue);
}
@Override
public final Clause clause() {
return CONDITION_BETWEEN;
}
}
}

View File

@ -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<T> extends AbstractField<T> implements CaseCondition
context.keyword("end")
.formatIndentLockEnd();
}
@Override
public final Clause clause() {
return DUMMY;
}
}

View File

@ -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()) {

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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
// -------------------------------------------------------------------------

View File

@ -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<T> 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<T> extends AbstractCondition {
context.visit(lhs).visit(rhs());
}
@Override
public final Clause clause() {
return CONDITION_COMPARISON;
}
private final Field<T> rhs() {
return (rhs == null) ? val(value, lhs) : rhs;
}

View File

@ -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
* <hr/>
* {@inheritDoc}
*/
@Override
public Clause clause() {
return null;
}
// -------------------------------------------------------------------------
// No further overrides allowed
// -------------------------------------------------------------------------

View File

@ -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<T> extends AbstractField<T> {
public abstract void bind(BindContext context) throws DataAccessException;
// -------------------------------------------------------------------------
// Further overrides allowed
// Implementation optional
// -------------------------------------------------------------------------
/**
* Subclasses may implement this method
* <hr/>
* {@inheritDoc}
*/
@Override
public Clause clause() {
return null;
}
// -------------------------------------------------------------------------
// No further overrides allowed
// -------------------------------------------------------------------------

View File

@ -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
* <hr/>
* {@inheritDoc}
*/
@Override
public Clause clause() {
return null;
}
// -------------------------------------------------------------------------
// No further overrides allowed
// -------------------------------------------------------------------------

View File

@ -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<Field<?>>(fieldSets[i]));
array[i] = new WrappedList(new QueryPartList<Field<?>>(DUMMY, fieldSets[i]));
}
return new Function<Object>("grouping sets", SQLDataType.OTHER, array);

View File

@ -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 <code>derive()</code> or <code>set()</code> methods.
*/
public DefaultConfiguration() {
this(SQL99);
}
/**
* Create a new "empty" configuration object given a {@link SQLDialect}.
* <p>
* 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 <code>derive()</code> or <code>set()</code> 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<Object, Object> 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> 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();
}
}

View File

@ -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) {

View File

@ -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}.
* <p>
* 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
* <code>DefaultVisitListenerProvider</code> from an array of
* <code>VisitListener</code> 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();
}
}

View File

@ -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<R extends Record> extends AbstractQuery implements DeleteQ
public final void bind(BindContext context) {
context.visit(getFrom()).visit(getWhere());
}
@Override
public final Clause clause() {
return DELETE;
}
}

View File

@ -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<Field<?>>();
this.returning = new QueryPartList<Field<?>>(DUMMY);
}
// ------------------------------------------------------------------------

View File

@ -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<Record> {
@Override
public final void bind(BindContext context) {}
@Override
public final Clause clause() {
return TABLE;
}
@Override
final Fields<Record> fields0() {
return new Fields<Record>();

View File

@ -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<T> extends AbstractFunction<T> {
this.operator = operator;
this.lhs = lhs;
this.rhs = new QueryPartList<Field<?>>(rhs);
this.rhs = new QueryPartList<Field<?>>(DUMMY, rhs);
}
@Override

View File

@ -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() {}
}

View File

@ -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()) {

View File

@ -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<?>, 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);

View File

@ -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<?>, 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<?>, 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();

View File

@ -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
// -------------------------------------------------------------------------

View File

@ -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 <code>Field[]</code>, providing some useful lookup
@ -246,12 +249,17 @@ class Fields<R extends Record> extends AbstractQueryPart implements RecordType<R
@Override
public final void toSQL(RenderContext context) {
new QueryPartList<Field<?>>(fields).toSQL(context);
new QueryPartList<Field<?>>(DUMMY, fields).toSQL(context);
}
@Override
public final void bind(BindContext context) {
new QueryPartList<Field<?>>(fields).bind(context);
new QueryPartList<Field<?>>(DUMMY, fields).bind(context);
}
@Override
public final Clause clause() {
return DUMMY;
}
// -------------------------------------------------------------------------

View File

@ -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<R, T> {
}
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
public final boolean declaresTables() {
return true;

View File

@ -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<T> extends AbstractField<T> implements
this.term = null;
this.name = null;
this.distinct = distinct;
this.arguments = new QueryPartList<QueryPart>(arguments);
this.arguments = new QueryPartList<QueryPart>(DUMMY, arguments);
this.keepDenseRankOrderBy = new SortFieldList();
this.withinGroupOrderBy = new SortFieldList();
this.partitionBy = new QueryPartList<Field<?>>();
this.partitionBy = new QueryPartList<Field<?>>(DUMMY);
this.orderBy = new SortFieldList();
}
@ -149,10 +151,10 @@ class Function<T> extends AbstractField<T> implements
this.term = term;
this.name = null;
this.distinct = distinct;
this.arguments = new QueryPartList<QueryPart>(arguments);
this.arguments = new QueryPartList<QueryPart>(DUMMY, arguments);
this.keepDenseRankOrderBy = new SortFieldList();
this.withinGroupOrderBy = new SortFieldList();
this.partitionBy = new QueryPartList<Field<?>>();
this.partitionBy = new QueryPartList<Field<?>>(DUMMY);
this.orderBy = new SortFieldList();
}
@ -162,10 +164,10 @@ class Function<T> extends AbstractField<T> implements
this.term = null;
this.name = name;
this.distinct = distinct;
this.arguments = new QueryPartList<QueryPart>(arguments);
this.arguments = new QueryPartList<QueryPart>(DUMMY, arguments);
this.keepDenseRankOrderBy = new SortFieldList();
this.withinGroupOrderBy = new SortFieldList();
this.partitionBy = new QueryPartList<Field<?>>();
this.partitionBy = new QueryPartList<Field<?>>(DUMMY);
this.orderBy = new SortFieldList();
}
@ -182,8 +184,12 @@ class Function<T> extends AbstractField<T> 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);

View File

@ -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<R extends Record> extends AbstractTable<R> {
}
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
final Fields<R> fields0() {
return new Fields<R>();

View File

@ -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<T> 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<T> extends AbstractCondition {
// operator
if (comparator == Comparator.IN) {
context.formatSeparator()
.keyword("or ");
.keyword("or")
.sql(" ");
}
else {
context.formatSeparator()
.keyword("and ");
.keyword("and")
.sql(" ");
}
}

View File

@ -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<R extends Record> extends AbstractStoreQuery<R> 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) {

View File

@ -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<R extends Record> 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<R extends Record> extends AbstractQuery implements I
visitAll(context, fields);
context.visit(select);
}
@Override
public final Clause clause() {
return INSERT;
}
}

View File

@ -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<T> extends AbstractCondition {
delegate(context.configuration()).bind(context);
}
@Override
public final Clause clause() {
return DUMMY;
}
/**
* Get a delegate <code>CompareCondition</code>, in case the context
* {@link SQLDialect} natively supports the <code>IS DISTINCT FROM</code>

View File

@ -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;
}
}

View File

@ -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<Record> implements TableOptionalOnStep, Ta
this.lhs = lhs.asTable();
this.rhs = rhs.asTable();
this.rhsPartitionBy = new QueryPartList<Field<?>>();
this.rhsPartitionBy = new QueryPartList<Field<?>>(DUMMY);
this.type = type;
this.condition = new ConditionProviderImpl();
this.using = new QueryPartList<Field<?>>();
this.using = new QueryPartList<Field<?>>(DUMMY);
}
// ------------------------------------------------------------------------
@ -125,10 +139,14 @@ class JoinTable extends AbstractTable<Record> 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<Record> 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<Record> 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<Record> 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<Record> implements TableOptionalOnStep, Ta
}
}
@Override
public final Clause clause() {
return TABLE_JOIN;
}
@Override
public final Table<Record> as(String alias) {
return new TableAlias<Record>(this, alias, true);

View File

@ -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;
}
}

View File

@ -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
*/

View File

@ -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<Field<?>>(fields);
h2Fields = new QueryPartList<Field<?>>(DUMMY, fields);
}
}
@ -240,7 +243,7 @@ implements
QueryPartList<Field<?>> getH2Fields() {
if (h2Fields == null) {
h2Fields = new QueryPartList<Field<?>>(table.fields());
h2Fields = new QueryPartList<Field<?>>(DUMMY, table.fields());
}
return h2Fields;
@ -248,7 +251,7 @@ implements
QueryPartList<Field<?>> getH2Keys() {
if (h2Keys == null) {
h2Keys = new QueryPartList<Field<?>>();
h2Keys = new QueryPartList<Field<?>>(DUMMY);
}
return h2Keys;
@ -256,7 +259,7 @@ implements
QueryPartList<Field<?>> getH2Values() {
if (h2Values == null) {
h2Values = new QueryPartList<Field<?>>();
h2Values = new QueryPartList<Field<?>>(DUMMY);
}
return h2Values;
@ -1194,4 +1197,9 @@ implements
.visit(notMatchedInsert)
.visit(notMatchedWhere);
}
@Override
public final Clause clause() {
return MERGE;
}
}

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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
// ------------------------------------------------------------------------

View File

@ -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<T> extends AbstractQueryPart implements Parameter<T> {
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

View File

@ -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<Record> select(Configuration configuration) {
List<Field<?>> groupingFields = new ArrayList<Field<?>>();
List<Field<?>> aliasedGroupingFields = new ArrayList<Field<?>>();
@ -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<Record> as(String alias) {
return new TableAlias<Record>(this, alias, true);

View File

@ -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<Record> {
@Override
public final void bind(BindContext context) {}
@Override
public final Clause clause() {
return TABLE;
}
@Override
public final Class<? extends Record> getRecordType() {
return RecordImpl.class;

View File

@ -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;
}
}

View File

@ -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<R extends Record> extends AbstractQueryPart implement
}
}
@Override
public final Clause clause() {
return DUMMY;
}
private final QueryPart part(Configuration context) {
if (query != null) {
return query;

View File

@ -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<T extends QueryPart> extends AbstractQueryPart implements List<T> {
private static final long serialVersionUID = -2936922742534009564L;
private final List<T> wrappedList = new ArrayList<T>();
private final List<T> wrappedList;
private final Clause clause;
QueryPartList() {
this((Collection<T>) null);
QueryPartList(Clause clause) {
this(clause, (Collection<T>) null);
}
QueryPartList(Collection<? extends T> wrappedList) {
QueryPartList(Clause clause, Collection<? extends T> wrappedList) {
super();
this.clause = clause;
this.wrappedList = new ArrayList<T>();
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<T extends QueryPart> 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<T extends QueryPart> 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<T extends QueryPart> extends AbstractQueryPart implements Li
visitAll(context, wrappedList);
}
@Override
public final Clause clause() {
return DUMMY;
}
/**
* Subclasses may override this method
*/

View File

@ -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;
}
}

View File

@ -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<Object> {
case CUBRID:
case MARIADB:
case MYSQL:
return field("{0} {with rollup}", new QueryPartList<Field<?>>(getArguments()));
return field("{0} {with rollup}", new QueryPartList<Field<?>>(DUMMY, getArguments()));
default:
return function("rollup", Object.class, getArguments());

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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<Row> list = new QueryPartList<Row>(rows);
QueryPartList<Row> list = new QueryPartList<Row>(DUMMY, rows);
return new RowInCondition(this, list, Comparator.IN);
}
@Override
public final Condition notIn(Collection rows) {
QueryPartList<Row> list = new QueryPartList<Row>(rows);
QueryPartList<Row> list = new QueryPartList<Row>(DUMMY, rows);
return new RowInCondition(this, list, Comparator.NOT_IN);
}

View File

@ -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<Condition> conditions = new ArrayList<Condition>();
@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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<T1, T2> extends AbstractCondition {
delegate(context.configuration()).bind(context);
}
@Override
public final Clause clause() {
return DUMMY;
}
private final QueryPartInternal delegate(Configuration configuration) {
Field<T1> left1 = left.field1();
Field<T2> left2 = left.field2();
@ -152,5 +160,10 @@ class RowOverlapsCondition<T1, T2> extends AbstractCondition {
public final void bind(BindContext context) {
context.visit(left).visit(right);
}
@Override
public final Clause clause() {
return CONDITION_OVERLAPS;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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<T> extends AbstractField<T> {
@ -68,4 +72,13 @@ class SQLField<T> extends AbstractField<T> {
public final void bind(BindContext context) {
context.visit(delegate);
}
@Override
public final Clause clause() {
if (delegate instanceof QueryPartInternal) {
return ((QueryPartInternal) delegate).clause();
}
return FIELD;
}
}

View File

@ -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;
}
}

View File

@ -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<Record> {
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;

View File

@ -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<Record> {
context.visit(delegate);
}
@Override
public final Clause clause() {
if (delegate instanceof QueryPartInternal) {
return ((QueryPartInternal) delegate).clause();
}
return TABLE;
}
@Override
final Fields<Record> fields0() {
return new Fields<Record>();

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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<Field<?>> {
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

View File

@ -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;
}
}

View File

@ -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<T> extends AbstractField<T> {
.sql(")");
}
}
@Override
public final Clause clause() {
return null;
}
}

View File

@ -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;
}
}

View File

@ -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<R extends Record> extends AbstractTable<R> {
.subquery(false);
}
}
@Override
public final Clause clause() {
return null;
}
}

View File

@ -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<R extends Record> extends AbstractSelect<R> implements Sel
this.condition = new ConditionProviderImpl();
this.connectBy = new ConditionProviderImpl();
this.connectByStartWith = new ConditionProviderImpl();
this.groupBy = new QueryPartList<GroupField>();
this.groupBy = new QueryPartList<GroupField>(DUMMY);
this.having = new ConditionProviderImpl();
this.orderBy = new SortFieldList();
this.limit = new Limit();
@ -149,10 +160,15 @@ class SelectQueryImpl<R extends Record> extends AbstractSelect<R> implements Sel
this.from.add(from.asTable());
}
this.forUpdateOf = new QueryPartList<Field<?>>();
this.forUpdateOf = new QueryPartList<Field<?>>(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<R extends Record> extends AbstractSelect<R> implements Sel
context.formatSeparator()
.sql(option);
}
}
/**
@ -434,7 +449,9 @@ class SelectQueryImpl<R extends Record> extends AbstractSelect<R> 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<R extends Record> extends AbstractSelect<R> 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<R extends Record> extends AbstractSelect<R> 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<R extends Record> extends AbstractSelect<R> 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<R extends Record> extends AbstractSelect<R> 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<R extends Record> extends AbstractSelect<R> 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

View File

@ -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<T> extends AbstractQueryPart implements SortField<T> {
.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<T> extends AbstractQueryPart implements SortField<T> {
context.visit(field);
}
@Override
public final Clause clause() {
return DUMMY;
}
}

View File

@ -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<SortField<?>> {
}
SortFieldList(List<SortField<?>> wrappedList) {
super(wrappedList);
super(DUMMY, wrappedList);
}
void addAll(Field<?>... fields) {

View File

@ -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<R extends Record> extends AbstractTable<R> {
context.visit(alias);
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
public final Table<R> as(String as) {
return alias.wrapped().as(as);

View File

@ -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<R extends Record, T> extends AbstractField<T> implements Ta
@Override
public final void bind(BindContext context) {}
@Override
public final Clause clause() {
return FIELD;
}
// ------------------------------------------------------------------------
// XXX: Object API
// ------------------------------------------------------------------------

View File

@ -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<R extends Record> extends AbstractTable<R> {
return null;
}
@Override
final Fields<R> 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<R extends Record> extends AbstractTable<R> {
}
}
@Override
final Fields<R> fields0() {
return fields;
}
@Override
public final void toSQL(RenderContext context) {
if (alias != null) {

View File

@ -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<Table<?>> {
private static final long serialVersionUID = -8545559185481762229L;
TableList() {
super();
super(TABLE);
}
TableList(List<? extends Table<?>> wrappedList) {
super(wrappedList);
super(TABLE, wrappedList);
}
@Override

View File

@ -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() {}
}

View File

@ -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<R extends Record> extends AbstractQuery implements
public final void bind(BindContext context) {
context.visit(table);
}
@Override
public final Clause clause() {
return TRUNCATE;
}
}

View File

@ -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<R extends UDTRecord<R>> 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.

View File

@ -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<R extends Record> extends AbstractSelect<R> {
Union(Configuration configuration, Select<R> query1, Select<? extends R> query2, CombineOperator operator) {
super(configuration);
this.operator = operator;
this.queries = new ArrayList<Select<? extends R>>();
this.queries.add(query1);
this.queries.add(query2);
this.operator = operator;
}
@Override
@ -128,6 +133,17 @@ class Union<R extends Record> extends AbstractSelect<R> {
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;

View File

@ -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<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> implements
.formatNewLine()
.sql(")");
}
context.end(UPDATE_SET_ASSIGNMENT);
}
// A regular (non-multi-row) update was specified
@ -494,13 +509,17 @@ class UpdateQueryImpl<R extends Record> extends AbstractStoreQuery<R> 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<R extends Record> extends AbstractStoreQuery<R> implements
bindReturning(context);
}
@Override
public final Clause clause() {
return UPDATE;
}
@Override
public final boolean isExecutable() {
return updateMap.size() > 0 || multiRow != null;

View File

@ -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<R extends Record> extends AbstractTable<R> {
visitAll(context, rows);
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
final Fields<R> fields0() {
return new Fields<R>(rows[0].fields());

View File

@ -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<R extends Record> extends AbstractTable<R> {
context.visit(delegate);
}
@Override
public final Clause clause() {
return DUMMY;
}
@Override
public final Class<? extends R> getRecordType() {
return delegate.getRecordType();

View File

@ -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;
}
}

View File

@ -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) {
}
}
}