[#914] Allow for modifying bind values of existing QueryParts / Queries
[#980] Add support for named parameters, to better interact with Spring
This commit is contained in:
parent
de42b79cb5
commit
ea48c9dcd0
@ -185,6 +185,11 @@ public class FactoryProxy implements FactoryOperations, MethodInterceptor {
|
||||
return getDelegate().render(part);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String renderNamedParams(QueryPart part) {
|
||||
return getDelegate().renderNamedParams(part);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String renderInlined(QueryPart part) {
|
||||
return getDelegate().renderInlined(part);
|
||||
|
||||
@ -1561,9 +1561,9 @@ public abstract class jOOQAbstractTest<
|
||||
|
||||
// CRUD with plain SQL
|
||||
Table<Record> table = table(TAuthor().getName());
|
||||
Field<Object> id = field(TAuthor_ID().getName());
|
||||
Field<Object> firstName = field(TAuthor_FIRST_NAME().getName());
|
||||
Field<Object> lastName = field(TAuthor_LAST_NAME().getName());
|
||||
Field<Integer> id = field(TAuthor_ID().getName(), Integer.class);
|
||||
Field<String> firstName = field(TAuthor_FIRST_NAME().getName(), String.class);
|
||||
Field<String> lastName = field(TAuthor_LAST_NAME().getName(), String.class);
|
||||
|
||||
assertEquals(2,
|
||||
create().insertInto(table, id, firstName, lastName)
|
||||
@ -1579,8 +1579,8 @@ public abstract class jOOQAbstractTest<
|
||||
.fetch();
|
||||
|
||||
assertEquals(2, authors1.size());
|
||||
assertEquals(10, authors1.getValue(0, id));
|
||||
assertEquals(11, authors1.getValue(1, id));
|
||||
assertEquals(10, (int) authors1.getValue(0, id));
|
||||
assertEquals(11, (int) authors1.getValue(1, id));
|
||||
assertEquals("Herbert", authors1.getValue(0, firstName));
|
||||
assertEquals("Friedrich", authors1.getValue(1, firstName));
|
||||
assertEquals("Meier", authors1.getValue(0, lastName));
|
||||
@ -1601,8 +1601,8 @@ public abstract class jOOQAbstractTest<
|
||||
.fetch();
|
||||
|
||||
assertEquals(2, authors2.size());
|
||||
assertEquals(10, authors2.getValue(0, id));
|
||||
assertEquals(11, authors2.getValue(1, id));
|
||||
assertEquals(10, (int) authors2.getValue(0, id));
|
||||
assertEquals(11, (int) authors2.getValue(1, id));
|
||||
assertEquals("Friedrich", authors2.getValue(0, firstName));
|
||||
assertEquals("Friedrich", authors2.getValue(1, firstName));
|
||||
assertEquals("Schiller", authors2.getValue(0, lastName));
|
||||
@ -8788,6 +8788,40 @@ public abstract class jOOQAbstractTest<
|
||||
.fetch(TAuthor_LAST_NAME()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNamedParams() throws Exception {
|
||||
Select<?> select =
|
||||
create().select(
|
||||
TAuthor_ID(),
|
||||
param("p1", String.class))
|
||||
.from(TAuthor())
|
||||
.where(TAuthor_ID().in(
|
||||
param("p2", Integer.class),
|
||||
param("p3", Integer.class)))
|
||||
.orderBy(TAuthor_ID().asc());
|
||||
|
||||
// Should execute fine, but no results due to IN (null, null) filter
|
||||
assertEquals(0, select.fetch().size());
|
||||
|
||||
// Set both parameters to the same value
|
||||
select.getParam("p2").setConverted(1L);
|
||||
select.getParam("p3").setConverted("1");
|
||||
Result<?> result1 = select.fetch();
|
||||
assertEquals(1, result1.size());
|
||||
assertEquals(1, result1.getValue(0, 0));
|
||||
assertNull(result1.getValue(0, 1));
|
||||
|
||||
// Set more parameters
|
||||
select.getParam("p1").setConverted("asdf");
|
||||
select.getParam("p3").setConverted("2");
|
||||
Result<?> result2 = select.fetch();
|
||||
assertEquals(2, result2.size());
|
||||
assertEquals(1, result2.getValue(0, 0));
|
||||
assertEquals(2, result2.getValue(1, 0));
|
||||
assertEquals("asdf", result2.getValue(0, 1));
|
||||
assertEquals("asdf", result2.getValue(1, 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoader() throws Exception {
|
||||
reset = false;
|
||||
|
||||
@ -47,7 +47,7 @@ import org.jooq.exception.DataAccessException;
|
||||
* will then pass the same context to their components
|
||||
* <p>
|
||||
* This interface is for JOOQ INTERNAL USE only. Do not reference directly
|
||||
*
|
||||
*
|
||||
* @author Lukas Eder
|
||||
* @see RenderContext
|
||||
*/
|
||||
@ -58,23 +58,10 @@ public interface BindContext extends Context<BindContext> {
|
||||
*/
|
||||
PreparedStatement statement();
|
||||
|
||||
/**
|
||||
* Get the next bind index. This increments an internal counter. Client code
|
||||
* must assure that calling {@link #nextIndex()} is followed by setting a
|
||||
* bind value to {@link #statement()}
|
||||
*/
|
||||
int nextIndex();
|
||||
|
||||
/**
|
||||
* Peek the next bind index. This won't increment the internal counter,
|
||||
* unlike {@link #nextIndex()}
|
||||
*/
|
||||
int peekIndex();
|
||||
|
||||
/**
|
||||
* Bind values from a {@link QueryPart}. This will also increment the
|
||||
* internal counter.
|
||||
*
|
||||
*
|
||||
* @throws DataAccessException If something went wrong while binding a
|
||||
* variable
|
||||
*/
|
||||
@ -83,7 +70,7 @@ public interface BindContext extends Context<BindContext> {
|
||||
/**
|
||||
* Bind values from several {@link QueryPart}'s. This will also increment
|
||||
* the internal counter.
|
||||
*
|
||||
*
|
||||
* @throws DataAccessException If something went wrong while binding a
|
||||
* variable
|
||||
*/
|
||||
@ -92,7 +79,7 @@ public interface BindContext extends Context<BindContext> {
|
||||
/**
|
||||
* Bind values from several {@link QueryPart}'s. This will also increment
|
||||
* the internal counter.
|
||||
*
|
||||
*
|
||||
* @throws DataAccessException If something went wrong while binding a
|
||||
* variable
|
||||
*/
|
||||
@ -101,7 +88,7 @@ public interface BindContext extends Context<BindContext> {
|
||||
/**
|
||||
* Bind a value using a specific type. This will also increment the internal
|
||||
* counter.
|
||||
*
|
||||
*
|
||||
* @throws DataAccessException If something went wrong while binding a
|
||||
* variable
|
||||
*/
|
||||
@ -109,7 +96,7 @@ public interface BindContext extends Context<BindContext> {
|
||||
|
||||
/**
|
||||
* Bind several values. This will also increment the internal counter.
|
||||
*
|
||||
*
|
||||
* @throws DataAccessException If something went wrong while binding a
|
||||
* variable
|
||||
*/
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
*/
|
||||
package org.jooq;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
|
||||
/**
|
||||
* A context type that is used for rendering SQL or for binding
|
||||
* <p>
|
||||
@ -78,4 +80,24 @@ public interface Context<C extends Context<C>> extends Configuration {
|
||||
* Set the new context value for {@link #subquery()}
|
||||
*/
|
||||
C subquery(boolean subquery);
|
||||
|
||||
/**
|
||||
* Get the next bind index. This increments an internal counter. This is
|
||||
* relevant for two use-cases:
|
||||
* <ul>
|
||||
* <li>When binding variables to a {@link PreparedStatement}. Client code
|
||||
* must assure that calling {@link #nextIndex()} is followed by setting a
|
||||
* bind value to {@link #statement()}</li>
|
||||
* <li>When rendering unnamed bind variables with
|
||||
* {@link RenderContext#namedParams()} being to <code>true</code></li>
|
||||
* </ul>
|
||||
*/
|
||||
int nextIndex();
|
||||
|
||||
/**
|
||||
* Peek the next bind index. This won't increment the internal counter,
|
||||
* unlike {@link #nextIndex()}
|
||||
*/
|
||||
int peekIndex();
|
||||
|
||||
}
|
||||
|
||||
@ -69,6 +69,18 @@ public interface FactoryOperations extends Configuration {
|
||||
*/
|
||||
String render(QueryPart part);
|
||||
|
||||
/**
|
||||
* Render a QueryPart in the context of this factory, rendering bind
|
||||
* variables as named parameters.
|
||||
* <p>
|
||||
* This is the same as calling
|
||||
* <code>renderContext().namedParams(true).render(part)</code>
|
||||
*
|
||||
* @param part The {@link QueryPart} to be rendered
|
||||
* @return The rendered SQL
|
||||
*/
|
||||
String renderNamedParams(QueryPart part);
|
||||
|
||||
/**
|
||||
* Render a QueryPart in the context of this factory, inlining all bind
|
||||
* variables.
|
||||
|
||||
@ -62,6 +62,7 @@ public interface Field<T> extends NamedTypeProviderQueryPart<T>, AliasProvider<F
|
||||
* <li>The formal name of the field, if it is a <i>physical table/view field</i></li>
|
||||
* <li>The alias of an <i>aliased field</i></li>
|
||||
* <li>A generated / unspecified value for any other <i>expression</i></li>
|
||||
* <li>The name of a parameter if it is a named {@link Param}</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Override
|
||||
|
||||
91
jOOQ/src/main/java/org/jooq/Param.java
Normal file
91
jOOQ/src/main/java/org/jooq/Param.java
Normal file
@ -0,0 +1,91 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2011, 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.Factory;
|
||||
import org.jooq.tools.Convert;
|
||||
|
||||
/**
|
||||
* A named parameter
|
||||
*
|
||||
* @author Lukas Eder
|
||||
* @see Factory#param(String, Object)
|
||||
*/
|
||||
public interface Param<T> extends Field<T> {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <hr/>
|
||||
* The <code>Param</code>'s value for {@link #getName()} coincides with
|
||||
* {@link #getParamName()}
|
||||
*/
|
||||
@Override
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* The parameter name. This name is useful for two things:
|
||||
* <ul>
|
||||
* <li>Named parameters in frameworks that support them, such as Spring's
|
||||
* <code>JdbcTemplate</code></li>
|
||||
* <li>Accessing the parameter from the {@link Query} API, with
|
||||
* {@link Query#getParam(String)}, {@link Query#getParams()}</li>
|
||||
* </ul>
|
||||
*/
|
||||
String getParamName();
|
||||
|
||||
/**
|
||||
* Get the parameter's underlying value. This returns <code>null</code> if
|
||||
* no value has been set yet.
|
||||
*/
|
||||
T getValue();
|
||||
|
||||
/**
|
||||
* Set the parameter's underlying value. This is the same as
|
||||
* {@link #setConverted(Object)}, but ensures generic type-safety.
|
||||
*
|
||||
* @see #setConverted(Object)
|
||||
*/
|
||||
void setValue(T value);
|
||||
|
||||
/**
|
||||
* Sets a converted value, using this {@link Param}'s underlying
|
||||
* {@link DataType}, obtained from {@link #getDataType()}
|
||||
*
|
||||
* @see DataType#convert(Object)
|
||||
* @see Convert#convert(Object, Class)
|
||||
*/
|
||||
void setConverted(Object value);
|
||||
}
|
||||
@ -37,13 +37,14 @@
|
||||
package org.jooq;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.impl.Factory;
|
||||
|
||||
/**
|
||||
* Any query
|
||||
*
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
public interface Query extends QueryPart {
|
||||
@ -51,7 +52,7 @@ public interface Query extends QueryPart {
|
||||
/**
|
||||
* Execute the query, if it has been created with a properly configured
|
||||
* factory
|
||||
*
|
||||
*
|
||||
* @return A result value, depending on the concrete implementation of
|
||||
* {@link Query}:
|
||||
* <ul>
|
||||
@ -84,8 +85,34 @@ public interface Query extends QueryPart {
|
||||
String getSQL();
|
||||
|
||||
/**
|
||||
* Retrieve the bind values that will be bound by this Query
|
||||
* Retrieve the bind values that will be bound by this Query. This
|
||||
* <code>List</code> cannot be modified. To modify bind values, use
|
||||
* {@link #getParams()} instead.
|
||||
*/
|
||||
List<Object> getBindValues();
|
||||
|
||||
/**
|
||||
* Get a <code>Map</code> of named parameters. The <code>Map</code> itself
|
||||
* cannot be modified, but the {@link Param} elements allow for modifying
|
||||
* bind values on an existing {@link Query}.
|
||||
* <p>
|
||||
* Bind values created with {@link Factory#val(Object)} will have their bind
|
||||
* index as name.
|
||||
*
|
||||
* @see Param
|
||||
* @see Factory#param(String, Object)
|
||||
*/
|
||||
Map<String, Param<?>> getParams();
|
||||
|
||||
/**
|
||||
* Get a named parameter from the {@link Query}, provided its name.
|
||||
* <p>
|
||||
* Bind values created with {@link Factory#val(Object)} will have their bind
|
||||
* index as name.
|
||||
*
|
||||
* @see Param
|
||||
* @see Factory#param(String, Object)
|
||||
*/
|
||||
Param<?> getParam(String name);
|
||||
|
||||
}
|
||||
|
||||
@ -37,6 +37,7 @@
|
||||
package org.jooq;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.exception.DataAccessException;
|
||||
|
||||
@ -60,14 +61,35 @@ public interface QueryPartInternal extends QueryPart {
|
||||
void toSQL(RenderContext context);
|
||||
|
||||
/**
|
||||
* Retrieve the bind values that will be bound by this QueryPart
|
||||
* Retrieve the SQL that will be rendered by this {@link QueryPart}
|
||||
* <p>
|
||||
* This method is exposed publicly in {@link Query#getSQL()}
|
||||
*/
|
||||
String getSQL();
|
||||
|
||||
/**
|
||||
* Retrieve the bind values that will be bound by this {@link QueryPart}
|
||||
* <p>
|
||||
* This method is exposed publicly in {@link Query#getBindValues()}
|
||||
*/
|
||||
List<Object> getBindValues();
|
||||
|
||||
/**
|
||||
* Bind all parameters of this QueryPart to a PreparedStatement
|
||||
* Retrieve the named parameters that will be bound by this {@link QueryPart}
|
||||
* <p>
|
||||
* This method is exposed publicly in {@link Query#getParams()}
|
||||
*/
|
||||
Map<String, Param<?>> getParams();
|
||||
|
||||
/**
|
||||
* Retrieve a named parameter that will be bound by this {@link QueryPart}
|
||||
* <p>
|
||||
* This method is exposed publicly in {@link Query#getParam(String)}
|
||||
*/
|
||||
Param<?> getParam(String name);
|
||||
|
||||
/**
|
||||
* Bind all parameters of this {@link QueryPart} to a PreparedStatement
|
||||
* <p>
|
||||
* This method is for JOOQ INTERNAL USE only. Do not reference directly
|
||||
*
|
||||
@ -79,7 +101,7 @@ public interface QueryPartInternal extends QueryPart {
|
||||
void bind(BindContext context) throws DataAccessException;
|
||||
|
||||
/**
|
||||
* Reproduce the SQL dialect this QueryPart was created with
|
||||
* Reproduce the SQL dialect this {@link QueryPart} was created with
|
||||
* <p>
|
||||
* This method is for JOOQ INTERNAL USE only. Do not reference directly
|
||||
*
|
||||
@ -88,7 +110,7 @@ public interface QueryPartInternal extends QueryPart {
|
||||
SQLDialect getDialect();
|
||||
|
||||
/**
|
||||
* Check whether this QueryPart is able to declare fields in a
|
||||
* Check whether this {@link QueryPart} is able to declare fields in a
|
||||
* <code>SELECT</code> clause.
|
||||
* <p>
|
||||
* This method can be used by any {@link Context} to check how a certain SQL
|
||||
@ -99,7 +121,7 @@ public interface QueryPartInternal extends QueryPart {
|
||||
boolean declaresFields();
|
||||
|
||||
/**
|
||||
* Check whether this QueryPart is able to declare tables in a
|
||||
* Check whether this {@link QueryPart} is able to declare tables in a
|
||||
* <code>FROM</code> clause or <code>JOIN</code> clause.
|
||||
* <p>
|
||||
* This method can be used by any {@link Context} to check how a certain SQL
|
||||
|
||||
@ -106,4 +106,18 @@ public interface RenderContext extends Context<RenderContext> {
|
||||
* Set the new context value for {@link #inline()}
|
||||
*/
|
||||
RenderContext inline(boolean inline);
|
||||
|
||||
/**
|
||||
* Whether bind variables should be rendered as named parameters:<br/>
|
||||
* <code>  :1, :2, :custom_name</code>
|
||||
* <p>
|
||||
* or as JDBC bind variables <br/>
|
||||
* <code>  ?</code>
|
||||
*/
|
||||
boolean namedParams();
|
||||
|
||||
/**
|
||||
* Set the new context value for {@link #namedParams()}
|
||||
*/
|
||||
RenderContext namedParams(boolean renderNamedParams);
|
||||
}
|
||||
|
||||
175
jOOQ/src/main/java/org/jooq/impl/AbstractBindContext.java
Normal file
175
jOOQ/src/main/java/org/jooq/impl/AbstractBindContext.java
Normal file
@ -0,0 +1,175 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2011, 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.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
|
||||
/**
|
||||
* A base class for {@link BindContext} implementations
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
abstract class AbstractBindContext extends AbstractContext<BindContext> implements BindContext {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -319766597723101571L;
|
||||
|
||||
AbstractBindContext(Configuration configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
AbstractBindContext(BindContext context) {
|
||||
this((Configuration) context);
|
||||
|
||||
declareFields(context.declareFields());
|
||||
declareTables(context.declareTables());
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// BindContext API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final BindContext bind(Collection<? extends QueryPart> parts) {
|
||||
for (QueryPart part : parts) {
|
||||
bind(part);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bind(QueryPart[] parts) {
|
||||
bind(Arrays.asList(parts));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bind(QueryPart part) {
|
||||
QueryPartInternal internal = part.internalAPI(QueryPartInternal.class);
|
||||
|
||||
// If this is supposed to be a declaration section and the part isn't
|
||||
// able to declare anything, then disable declaration temporarily
|
||||
|
||||
// We're declaring fields, but "part" does not declare fields
|
||||
if (declareFields() && !internal.declaresFields()) {
|
||||
declareFields(false);
|
||||
bindInternal(internal);
|
||||
declareFields(true);
|
||||
}
|
||||
|
||||
// We're declaring tables, but "part" does not declare tables
|
||||
else if (declareTables() && !internal.declaresTables()) {
|
||||
declareTables(false);
|
||||
bindInternal(internal);
|
||||
declareTables(true);
|
||||
}
|
||||
|
||||
// We're not declaring, or "part" can declare
|
||||
else {
|
||||
bindInternal(internal);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bindValues(Object... values) {
|
||||
|
||||
// [#724] When values is null, this is probably due to API-misuse
|
||||
// The user probably meant new Object[] { null }
|
||||
if (values == null) {
|
||||
bindValues(new Object[] { null });
|
||||
}
|
||||
else {
|
||||
for (Object value : values) {
|
||||
Class<?> type = (value == null) ? Object.class : value.getClass();
|
||||
bindValue(value, type);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bindValue(Object value, Class<?> type) {
|
||||
try {
|
||||
return bindValue0(value, type);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Util.translate("DefaultBindContext.bindValue", null, e);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// AbstractBindContext template methods
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Subclasses may override this method to achieve different behaviour
|
||||
*/
|
||||
protected void bindInternal(QueryPartInternal internal) {
|
||||
internal.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override this method to achieve different behaviour
|
||||
*/
|
||||
@SuppressWarnings("unused")
|
||||
protected BindContext bindValue0(Object value, Class<?> type) throws SQLException {
|
||||
return this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Object API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
toString(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@ -56,6 +56,7 @@ abstract class AbstractContext<C extends Context<C>> implements Context<C> {
|
||||
boolean declareFields;
|
||||
boolean declareTables;
|
||||
boolean subquery;
|
||||
int index;
|
||||
|
||||
AbstractContext(Configuration configuration) {
|
||||
this.configuration = configuration;
|
||||
@ -107,6 +108,16 @@ abstract class AbstractContext<C extends Context<C>> implements Context<C> {
|
||||
return (C) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int nextIndex() {
|
||||
return ++index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int peekIndex() {
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Configuration API
|
||||
// ------------------------------------------------------------------------
|
||||
@ -127,7 +138,10 @@ abstract class AbstractContext<C extends Context<C>> implements Context<C> {
|
||||
}
|
||||
|
||||
void toString(StringBuilder sb) {
|
||||
sb.append("\ndeclaring [");
|
||||
sb.append( "bind index [");
|
||||
sb.append(index);
|
||||
sb.append("]");
|
||||
sb.append("\ndeclaring [");
|
||||
|
||||
if (declareFields) {
|
||||
sb.append("fields");
|
||||
@ -139,7 +153,7 @@ abstract class AbstractContext<C extends Context<C>> implements Context<C> {
|
||||
sb.append("-");
|
||||
}
|
||||
|
||||
sb.append("]\nsubquery [");
|
||||
sb.append("]\nsubquery [");
|
||||
sb.append(subquery);
|
||||
sb.append("]");
|
||||
}
|
||||
|
||||
@ -42,10 +42,12 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.Attachable;
|
||||
import org.jooq.AttachableInternal;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
@ -107,16 +109,50 @@ abstract class AbstractQueryPart implements QueryPartInternal, AttachableInterna
|
||||
|
||||
/**
|
||||
* This method is also declared as {@link Query#getSQL()}
|
||||
* <p>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final String getSQL() {
|
||||
return create().render(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is also declared as {@link Query#getBindValues()}
|
||||
* <p>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final List<Object> getBindValues() {
|
||||
BindValueCollector collector = new BindValueCollector();
|
||||
create(getConfiguration()).bind(this, collector);
|
||||
return collector.result;
|
||||
List<Object> result = new ArrayList<Object>();
|
||||
|
||||
for (Param<?> param : getParams().values()) {
|
||||
result.add(param.getValue());
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is also declared as {@link Query#getParams()}
|
||||
* <p>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final Map<String, Param<?>> getParams() {
|
||||
ParamCollector collector = new ParamCollector(getConfiguration());
|
||||
collector.bind(this);
|
||||
return Collections.unmodifiableMap(collector.result);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is also declared as {@link Query#getParam(String)}
|
||||
* <p>
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final Param<?> getParam(String name) {
|
||||
return getParams().get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -1,529 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2011, 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.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.math.BigDecimal;
|
||||
import java.net.URL;
|
||||
import java.sql.Array;
|
||||
import java.sql.Blob;
|
||||
import java.sql.Clob;
|
||||
import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.NClob;
|
||||
import java.sql.ParameterMetaData;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Ref;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.RowId;
|
||||
import java.sql.SQLWarning;
|
||||
import java.sql.SQLXML;
|
||||
import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import org.jooq.Query;
|
||||
|
||||
/**
|
||||
* A stub prepared statement that acts as a collector of bind values, in order
|
||||
* to retrieve the bound values in correct order for
|
||||
* {@link Query#getBindValues()}
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class BindValueCollector implements PreparedStatement {
|
||||
|
||||
final List<Object> result = new ArrayList<Object>();
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> iface) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery(String sql) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {}
|
||||
|
||||
@Override
|
||||
public int getMaxFieldSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFieldSize(int max) {}
|
||||
|
||||
@Override
|
||||
public int getMaxRows() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxRows(int max) {}
|
||||
|
||||
@Override
|
||||
public void setEscapeProcessing(boolean enable) {}
|
||||
|
||||
@Override
|
||||
public int getQueryTimeout() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQueryTimeout(int seconds) {}
|
||||
|
||||
@Override
|
||||
public void cancel() {}
|
||||
|
||||
@Override
|
||||
public SQLWarning getWarnings() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearWarnings() {}
|
||||
|
||||
@Override
|
||||
public void setCursorName(String name) {}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getResultSet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchDirection(int direction) {}
|
||||
|
||||
@Override
|
||||
public int getFetchDirection() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFetchSize(int rows) {}
|
||||
|
||||
@Override
|
||||
public int getFetchSize() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetConcurrency() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetType() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch(String sql) {}
|
||||
|
||||
@Override
|
||||
public void clearBatch() {}
|
||||
|
||||
@Override
|
||||
public int[] executeBatch() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getMoreResults(int current) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet getGeneratedKeys() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int autoGeneratedKeys) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, int[] columnIndexes) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate(String sql, String[] columnNames) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int autoGeneratedKeys) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, int[] columnIndexes) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(String sql, String[] columnNames) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResultSetHoldability() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isClosed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPoolable(boolean poolable) {}
|
||||
|
||||
@Override
|
||||
public boolean isPoolable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSet executeQuery() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNull(int parameterIndex, int sqlType) {
|
||||
result.add(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBoolean(int parameterIndex, boolean x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setByte(int parameterIndex, byte x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShort(int parameterIndex, short x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInt(int parameterIndex, int x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLong(int parameterIndex, long x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloat(int parameterIndex, float x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDouble(int parameterIndex, double x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBigDecimal(int parameterIndex, BigDecimal x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setString(int parameterIndex, String x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBytes(int parameterIndex, byte[] x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(int parameterIndex, Date x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(int parameterIndex, Time x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(int parameterIndex, Timestamp x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, int length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUnicodeStream(int parameterIndex, InputStream x, int length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, int length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearParameters() {}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addBatch() {}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader x, int length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRef(int parameterIndex, Ref x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, Blob x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Clob x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setArray(int parameterIndex, Array x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultSetMetaData getMetaData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDate(int parameterIndex, Date x, Calendar cal) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTime(int parameterIndex, Time x, Calendar cal) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTimestamp(int parameterIndex, Timestamp x, Calendar cal) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNull(int parameterIndex, int sqlType, String typeName) {
|
||||
result.add(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setURL(int parameterIndex, URL x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterMetaData getParameterMetaData() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRowId(int parameterIndex, RowId x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNString(int parameterIndex, String x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNCharacterStream(int parameterIndex, Reader x, long length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, NClob x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Reader x, long length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, InputStream x, long length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, Reader x, long length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSQLXML(int parameterIndex, SQLXML x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObject(int parameterIndex, Object x, int targetSqlType, int scaleOrLength) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x, long length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x, long length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader x, long length) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAsciiStream(int parameterIndex, InputStream x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryStream(int parameterIndex, InputStream x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCharacterStream(int parameterIndex, Reader x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNCharacterStream(int parameterIndex, Reader x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setClob(int parameterIndex, Reader x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBlob(int parameterIndex, InputStream x) {
|
||||
result.add(x);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNClob(int parameterIndex, Reader x) {
|
||||
result.add(x);
|
||||
}
|
||||
}
|
||||
@ -1,151 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2011, 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.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jooq.Attachable;
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.MasterDataType;
|
||||
import org.jooq.RenderContext;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class Constant<T> extends AbstractField<T> {
|
||||
|
||||
private static final long serialVersionUID = 6807729087019209084L;
|
||||
private final T value;
|
||||
|
||||
Constant(T value, DataType<T> type) {
|
||||
super("" + value, type);
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<Attachable> getAttachables() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext context) {
|
||||
|
||||
// Casting is only done when parameters are NOT inlined
|
||||
if (!context.inline()) {
|
||||
|
||||
// Generated enums should not be cast...
|
||||
// The exception's exception
|
||||
if (!(value instanceof EnumType) && !(value instanceof MasterDataType)) {
|
||||
switch (context.getDialect()) {
|
||||
|
||||
// These dialects can hardly detect the type of a bound constant.
|
||||
case DB2:
|
||||
case DERBY:
|
||||
|
||||
// These dialects have some trouble, when they mostly get it right.
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
|
||||
// [#722] TODO This is probably not entirely right.
|
||||
case INGRES:
|
||||
|
||||
// [#632] Sybase needs explicit casting in very rare cases.
|
||||
case SYBASE: {
|
||||
toSQLCast(context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Most RDBMS can handle constants as typeless literals
|
||||
FieldTypeHelper.toSQL(context, value, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the bind variable including a cast, if necessary
|
||||
*/
|
||||
private void toSQLCast(RenderContext context) {
|
||||
switch (context.getDialect()) {
|
||||
|
||||
// [#822] Some RDBMS need precision / scale information on BigDecimals
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case HSQLDB: {
|
||||
|
||||
// Add precision / scale on BigDecimals
|
||||
if (getType() == BigDecimal.class) {
|
||||
int scale = ((BigDecimal) value).scale();
|
||||
int precision = scale + ((BigDecimal) value).precision();
|
||||
|
||||
context.sql("cast(? as ")
|
||||
.sql(getDataType(context).getCastTypeName(context, precision, scale))
|
||||
.sql(")");
|
||||
break;
|
||||
}
|
||||
|
||||
// No break, fall through
|
||||
else {
|
||||
}
|
||||
}
|
||||
|
||||
// These dialects don't need precision / scale info on BigDecimals
|
||||
case H2:
|
||||
case INGRES:
|
||||
case SYBASE: {
|
||||
context.sql("cast(? as ")
|
||||
.sql(getDataType(context).getCastTypeName(context))
|
||||
.sql(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {
|
||||
context.bindValue(value, getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return value == null;
|
||||
}
|
||||
}
|
||||
@ -46,15 +46,12 @@ import java.sql.Time;
|
||||
import java.sql.Timestamp;
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.jooq.ArrayRecord;
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.MasterDataType;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.exception.SQLDialectNotSupportedException;
|
||||
import org.jooq.tools.JooqLogger;
|
||||
@ -63,7 +60,7 @@ import org.jooq.tools.unsigned.UNumber;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class DefaultBindContext extends AbstractContext<BindContext> implements BindContext {
|
||||
class DefaultBindContext extends AbstractBindContext {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
@ -72,7 +69,6 @@ class DefaultBindContext extends AbstractContext<BindContext> implements BindCon
|
||||
private static final JooqLogger log = JooqLogger.getLogger(Util.class);
|
||||
|
||||
private final PreparedStatement stmt;
|
||||
private int index;
|
||||
|
||||
DefaultBindContext(Configuration configuration, PreparedStatement stmt) {
|
||||
super(configuration);
|
||||
@ -93,89 +89,8 @@ class DefaultBindContext extends AbstractContext<BindContext> implements BindCon
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int nextIndex() {
|
||||
return ++index;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int peekIndex() {
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bind(QueryPart part) {
|
||||
QueryPartInternal internal = part.internalAPI(QueryPartInternal.class);
|
||||
|
||||
// If this is supposed to be a declaration section and the part isn't
|
||||
// able to declare anything, then disable declaration temporarily
|
||||
|
||||
// We're declaring fields, but "part" does not declare fields
|
||||
if (declareFields() && !internal.declaresFields()) {
|
||||
declareFields(false);
|
||||
internal.bind(this);
|
||||
declareFields(true);
|
||||
}
|
||||
|
||||
// We're declaring tables, but "part" does not declare tables
|
||||
else if (declareTables() && !internal.declaresTables()) {
|
||||
declareTables(false);
|
||||
internal.bind(this);
|
||||
declareTables(true);
|
||||
}
|
||||
|
||||
// We're not declaring, or "part" can declare
|
||||
else {
|
||||
internal.bind(this);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bind(Collection<? extends QueryPart> parts) {
|
||||
for (QueryPart part : parts) {
|
||||
bind(part);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bind(QueryPart[] parts) {
|
||||
bind(Arrays.asList(parts));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bindValues(Object... values) {
|
||||
|
||||
// [#724] When values is null, this is probably due to API-misuse
|
||||
// The user probably meant new Object[] { null }
|
||||
if (values == null) {
|
||||
bindValues(new Object[] { null });
|
||||
}
|
||||
else {
|
||||
for (Object value : values) {
|
||||
Class<?> type = (value == null) ? Object.class : value.getClass();
|
||||
bindValue(value, type);
|
||||
}
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final BindContext bindValue(Object value, Class<?> type) {
|
||||
try {
|
||||
return bindValue0(value, type);
|
||||
}
|
||||
catch (SQLException e) {
|
||||
throw Util.translate("DefaultBindContext.bindValue", null, e);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final BindContext bindValue0(Object value, Class<?> type) throws SQLException {
|
||||
protected final BindContext bindValue0(Object value, Class<?> type) throws SQLException {
|
||||
SQLDialect dialect = configuration.getDialect();
|
||||
|
||||
if (log.isTraceEnabled()) {
|
||||
@ -335,20 +250,4 @@ class DefaultBindContext extends AbstractContext<BindContext> implements BindCon
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Object API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("binding [index ");
|
||||
sb.append(index);
|
||||
sb.append("]");
|
||||
|
||||
toString(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,6 +52,7 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
|
||||
private final StringBuilder sql;
|
||||
private boolean inline;
|
||||
private boolean renderNamedParams;
|
||||
private int alias;
|
||||
|
||||
DefaultRenderContext(Configuration configuration) {
|
||||
@ -64,6 +65,7 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
this((Configuration) context);
|
||||
|
||||
inline(context.inline());
|
||||
namedParams(context.namedParams());
|
||||
declareFields(context.declareFields());
|
||||
declareTables(context.declareTables());
|
||||
}
|
||||
@ -187,6 +189,17 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean namedParams() {
|
||||
return renderNamedParams;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final RenderContext namedParams(boolean r) {
|
||||
this.renderNamedParams = r;
|
||||
return this;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Object API
|
||||
// ------------------------------------------------------------------------
|
||||
@ -195,12 +208,15 @@ class DefaultRenderContext extends AbstractContext<RenderContext> implements Ren
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.append("rendering [");
|
||||
sb.append( "rendering [");
|
||||
sb.append(render());
|
||||
sb.append("]");
|
||||
sb.append("\ninlining [");
|
||||
sb.append("\ninlining [");
|
||||
sb.append(inline);
|
||||
sb.append("]");
|
||||
sb.append("\nnamed params [");
|
||||
sb.append(renderNamedParams);
|
||||
sb.append("]");
|
||||
|
||||
toString(sb);
|
||||
return sb.toString();
|
||||
|
||||
@ -79,6 +79,7 @@ import org.jooq.InsertSetStep;
|
||||
import org.jooq.InsertValuesStep;
|
||||
import org.jooq.LoaderOptionsStep;
|
||||
import org.jooq.MergeUsingStep;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.Record;
|
||||
@ -218,6 +219,7 @@ public class Factory implements FactoryOperations {
|
||||
* <li> <code>{@link RenderContext#declareFields()} == false</code></li>
|
||||
* <li> <code>{@link RenderContext#declareTables()} == false</code></li>
|
||||
* <li> <code>{@link RenderContext#inline()} == false</code></li>
|
||||
* <li> <code>{@link RenderContext#namedParams()} == false</code></li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* RenderContext for JOOQ INTERNAL USE only. Avoid referencing it directly
|
||||
@ -234,6 +236,14 @@ public class Factory implements FactoryOperations {
|
||||
return renderContext().render(part);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final String renderNamedParams(QueryPart part) {
|
||||
return renderContext().namedParams(true).render(part);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@ -3531,18 +3541,87 @@ public class Factory implements FactoryOperations {
|
||||
// Bind values
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a named parameter with a generic type ({@link Object} /
|
||||
* {@link SQLDataType#OTHER}) and no initial value.
|
||||
* <p>
|
||||
* Try to avoid this method when using any of these databases, as these
|
||||
* databases may have trouble inferring the type of the bind value. Use
|
||||
* typed named parameters instead, using {@link #param(String, Class)} or
|
||||
* {@link #param(String, DataType)}
|
||||
* <ul>
|
||||
* <li> {@link SQLDialect#DB2}</li>
|
||||
* <li> {@link SQLDialect#DERBY}</li>
|
||||
* <li> {@link SQLDialect#H2}</li>
|
||||
* <li> {@link SQLDialect#HSQLDB}</li>
|
||||
* <li> {@link SQLDialect#INGRES}</li>
|
||||
* <li> {@link SQLDialect#SYBASE}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see #param(String, Object)
|
||||
*/
|
||||
public static Param<Object> param(String name) {
|
||||
return param(name, Object.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named parameter with a defined type and no initial value.
|
||||
*
|
||||
* @see #param(String, Object)
|
||||
*/
|
||||
public static <T> Param<T> param(String name, Class<? extends T> type) {
|
||||
return param(name, SQLDataType.getDataType(null, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named parameter with a defined type and no initial value.
|
||||
*
|
||||
* @see #param(String, Object)
|
||||
*/
|
||||
public static <T> Param<T> param(String name, DataType<T> type) {
|
||||
return new Val<T>(null, type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a named parameter with an initial value.
|
||||
* <p>
|
||||
* Named parameters are useful for several use-cases:
|
||||
* <ul>
|
||||
* <li>They can be used with Spring's <code>JdbcTemplate</code>, which
|
||||
* supports named parameters. Use
|
||||
* {@link FactoryOperations#renderNamedParams(QueryPart)} to render
|
||||
* parameter names in SQL</li>
|
||||
* <li>Named parameters can be retrieved using a well-known name from
|
||||
* {@link Query#getParam(String)} and {@link Query#getParams()}.</li>
|
||||
* </ul>
|
||||
*
|
||||
* @see Query#getParam(String)
|
||||
* @see Query#getParams()
|
||||
* @see #renderNamedParams(QueryPart)
|
||||
*/
|
||||
public static <T> Param<T> param(String name, T value) {
|
||||
return new Val<T>(value, val(value).getDataType(), name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a value
|
||||
* <p>
|
||||
* jOOQ tries to derive the RDBMS {@link DataType} from the provided Java
|
||||
* type <code><T></code>. This may not always be accurate, which can
|
||||
* lead to problems in some strongly typed RDMBS (namely:
|
||||
* {@link SQLDialect#DERBY}, {@link SQLDialect#DB2}, {@link SQLDialect#H2},
|
||||
* {@link SQLDialect#HSQLDB}), especially when value is <code>null</code>.
|
||||
* lead to problems in some strongly typed RDMBS, especially when value is
|
||||
* <code>null</code>. These databases are namely:
|
||||
* <ul>
|
||||
* <li>{@link SQLDialect#DERBY}</li>
|
||||
* <li>{@link SQLDialect#DB2}</li>
|
||||
* <li>{@link SQLDialect#H2}</li>
|
||||
* <li>{@link SQLDialect#HSQLDB}
|
||||
* <li>{@link SQLDialect#INGRES}
|
||||
* <li>{@link SQLDialect#SYBASE}
|
||||
* </ul>
|
||||
* <p>
|
||||
* If you need more type-safety, please use
|
||||
* {@link #val(Object, DataType)} instead, and provide the precise
|
||||
* RDMBS-specific data type, that is needed.
|
||||
* If you need more type-safety, please use {@link #val(Object, DataType)}
|
||||
* instead, and provide the precise RDMBS-specific data type, that is
|
||||
* needed.
|
||||
*
|
||||
* @param <T> The generic value type
|
||||
* @param value The constant value
|
||||
@ -3624,7 +3703,7 @@ public class Factory implements FactoryOperations {
|
||||
|
||||
// The default behaviour
|
||||
else {
|
||||
return new Constant<T>(type.convert(value), type);
|
||||
return new Val<T>(type.convert(value), type);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -53,7 +53,6 @@ import java.sql.Types;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@ -65,9 +64,7 @@ import org.jooq.EnumType;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.FieldProvider;
|
||||
import org.jooq.MasterDataType;
|
||||
import org.jooq.NamedTypeProviderQueryPart;
|
||||
import org.jooq.Record;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.UDTRecord;
|
||||
@ -109,130 +106,6 @@ public final class FieldTypeHelper {
|
||||
|
||||
private static final JooqLogger log = JooqLogger.getLogger(FieldTypeHelper.class);
|
||||
|
||||
public static void toSQL(RenderContext context, Object value) {
|
||||
if (value == null) {
|
||||
toSQL(context, value, Object.class);
|
||||
}
|
||||
else {
|
||||
toSQL(context, value, value.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public static void toSQL(RenderContext context, Object value, NamedTypeProviderQueryPart<?> field) {
|
||||
toSQL(context, value, field.getType());
|
||||
}
|
||||
|
||||
public static void toSQL(RenderContext context, Object value, Class<?> type) {
|
||||
if (context.inline()) {
|
||||
if (value == null) {
|
||||
context.sql("null");
|
||||
}
|
||||
else if (type == Blob.class) {
|
||||
|
||||
// blob's are treated as byte[] by jOOQ
|
||||
context.sql("[BLOB]");
|
||||
}
|
||||
else if (type == Boolean.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == BigInteger.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == BigDecimal.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == Byte.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == byte[].class) {
|
||||
context.sql("'")
|
||||
.sql(new String((byte[]) value).replace("'", "''"))
|
||||
.sql("'");
|
||||
}
|
||||
else if (type == Clob.class) {
|
||||
|
||||
// clob's are treated as String by jOOQ
|
||||
context.sql("[CLOB]");
|
||||
}
|
||||
else if (type == Date.class) {
|
||||
context.sql("'").sql(value.toString()).sql("'");
|
||||
}
|
||||
else if (type == Double.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == Float.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == Integer.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == Long.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == Short.class) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (type == String.class) {
|
||||
context.sql("'")
|
||||
.sql(value.toString().replace("'", "''"))
|
||||
.sql("'");
|
||||
}
|
||||
else if (type == Time.class) {
|
||||
context.sql("'").sql(value.toString()).sql("'");
|
||||
}
|
||||
else if (type == Timestamp.class) {
|
||||
context.sql("'").sql(value.toString()).sql("'");
|
||||
}
|
||||
else if (type.isArray()) {
|
||||
context.sql("ARRAY")
|
||||
.sql(Arrays.asList((Object[]) value).toString());
|
||||
}
|
||||
else if (UNumber.class.isAssignableFrom(type)) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (ArrayRecord.class.isAssignableFrom(type)) {
|
||||
context.sql(value.toString());
|
||||
}
|
||||
else if (EnumType.class.isAssignableFrom(type)) {
|
||||
toSQL(context, ((EnumType) value).getLiteral());
|
||||
}
|
||||
else if (MasterDataType.class.isAssignableFrom(type)) {
|
||||
toSQL(context, ((MasterDataType<?>) value).getPrimaryKey());
|
||||
}
|
||||
else if (UDTRecord.class.isAssignableFrom(type)) {
|
||||
context.sql("[UDT]");
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Class " + type + " is not supported");
|
||||
}
|
||||
}
|
||||
|
||||
// In Postgres, some additional casting must be done in some cases...
|
||||
// TODO: Improve this implementation with [#215] (cast support)
|
||||
else if (context.getDialect() == SQLDialect.POSTGRES) {
|
||||
|
||||
// Postgres needs explicit casting for array types
|
||||
if (type.isArray() && byte[].class != type) {
|
||||
context.sql("?::");
|
||||
context.sql(getDataType(context.getDialect(), type).getCastTypeName(context));
|
||||
}
|
||||
|
||||
// ... and also for enum types
|
||||
else if (EnumType.class.isAssignableFrom(type)) {
|
||||
context.sql("?::");
|
||||
context.literal(((EnumType) value).getName());
|
||||
}
|
||||
|
||||
else {
|
||||
context.sql("?");
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
context.sql("?");
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <T> T getFromSQLInput(Configuration configuration, SQLInput stream, Field<T> field) throws SQLException {
|
||||
Class<? extends T> type = field.getType();
|
||||
|
||||
96
jOOQ/src/main/java/org/jooq/impl/ParamCollector.java
Normal file
96
jOOQ/src/main/java/org/jooq/impl/ParamCollector.java
Normal file
@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2011, 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.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
import org.jooq.tools.StringUtils;
|
||||
|
||||
/**
|
||||
* A stub {@link BindContext} that acts as a collector of {@link Param}
|
||||
* {@link QueryPart}'s
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class ParamCollector extends AbstractBindContext {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = -3741599479523459297L;
|
||||
|
||||
final Map<String, Param<?>> result = new LinkedHashMap<String, Param<?>>();
|
||||
|
||||
ParamCollector(Configuration configuration) {
|
||||
super(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final PreparedStatement statement() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final void bindInternal(QueryPartInternal internal) {
|
||||
if (internal instanceof Param) {
|
||||
Param<?> param = (Param<?>) internal;
|
||||
String i = String.valueOf(nextIndex());
|
||||
|
||||
if (StringUtils.isBlank(param.getParamName())) {
|
||||
result.put(i, param);
|
||||
}
|
||||
else {
|
||||
result.put(param.getParamName(), param);
|
||||
}
|
||||
}
|
||||
else {
|
||||
super.bindInternal(internal);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final BindContext bindValue0(Object value, Class<?> type) throws SQLException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,8 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.Factory.val;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
@ -173,7 +175,7 @@ final class Util {
|
||||
context.sql(split[i]);
|
||||
|
||||
if (i < bindings.length) {
|
||||
FieldTypeHelper.toSQL(context, bindings[i]);
|
||||
context.sql(val(bindings[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
307
jOOQ/src/main/java/org/jooq/impl/Val.java
Normal file
307
jOOQ/src/main/java/org/jooq/impl/Val.java
Normal file
@ -0,0 +1,307 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2011, 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.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.jooq.ArrayRecord;
|
||||
import org.jooq.Attachable;
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.DataType;
|
||||
import org.jooq.EnumType;
|
||||
import org.jooq.MasterDataType;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.UDTRecord;
|
||||
import org.jooq.tools.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class Val<T> extends AbstractField<T> implements Param<T> {
|
||||
|
||||
private static final long serialVersionUID = 6807729087019209084L;
|
||||
private final String paramName;
|
||||
private T value;
|
||||
|
||||
Val(T value, DataType<T> type) {
|
||||
this(value, type, null);
|
||||
}
|
||||
|
||||
Val(T value, DataType<T> type, String paramName) {
|
||||
super(name(value, paramName), type);
|
||||
|
||||
this.paramName = paramName;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
private static String name(Object value, String paramName) {
|
||||
return paramName == null ? String.valueOf(value) : paramName;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Field API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final List<Attachable> getAttachables() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext context) {
|
||||
|
||||
// Casting is only done when parameters are NOT inlined
|
||||
if (!context.inline()) {
|
||||
|
||||
// Generated enums should not be cast...
|
||||
// The exception's exception
|
||||
if (!(getValue() instanceof EnumType) && !(getValue() instanceof MasterDataType)) {
|
||||
switch (context.getDialect()) {
|
||||
|
||||
// These dialects can hardly detect the type of a bound constant.
|
||||
case DB2:
|
||||
case DERBY:
|
||||
|
||||
// These dialects have some trouble, when they mostly get it right.
|
||||
case H2:
|
||||
case HSQLDB:
|
||||
|
||||
// [#722] TODO This is probably not entirely right.
|
||||
case INGRES:
|
||||
|
||||
// [#632] Sybase needs explicit casting in very rare cases.
|
||||
case SYBASE: {
|
||||
toSQLCast(context);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Most RDBMS can handle constants as typeless literals
|
||||
toSQL(context, getValue(), this.getType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the bind variable including a cast, if necessary
|
||||
*/
|
||||
private void toSQLCast(RenderContext context) {
|
||||
switch (context.getDialect()) {
|
||||
|
||||
// [#822] Some RDBMS need precision / scale information on BigDecimals
|
||||
case DB2:
|
||||
case DERBY:
|
||||
case HSQLDB: {
|
||||
|
||||
// Add precision / scale on BigDecimals
|
||||
if (getType() == BigDecimal.class) {
|
||||
int scale = ((BigDecimal) getValue()).scale();
|
||||
int precision = scale + ((BigDecimal) getValue()).precision();
|
||||
|
||||
context.sql("cast(")
|
||||
.sql(getBindVariable(context))
|
||||
.sql(" as ")
|
||||
.sql(getDataType(context).getCastTypeName(context, precision, scale))
|
||||
.sql(")");
|
||||
break;
|
||||
}
|
||||
|
||||
// No break, fall through
|
||||
else {
|
||||
}
|
||||
}
|
||||
|
||||
// These dialects don't need precision / scale info on BigDecimals
|
||||
case H2:
|
||||
case INGRES:
|
||||
case SYBASE: {
|
||||
context.sql("cast(")
|
||||
.sql(getBindVariable(context))
|
||||
.sql(" as ")
|
||||
.sql(getDataType(context).getCastTypeName(context))
|
||||
.sql(")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a bind variable, depending on value of
|
||||
* {@link RenderContext#namedParams()}
|
||||
*/
|
||||
private final String getBindVariable(RenderContext context) {
|
||||
if (context.namedParams()) {
|
||||
int index = context.nextIndex();
|
||||
|
||||
if (StringUtils.isBlank(getParamName())) {
|
||||
return ":" + index;
|
||||
}
|
||||
else {
|
||||
return ":" + getName();
|
||||
}
|
||||
}
|
||||
else {
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlining abstraction
|
||||
*/
|
||||
private void toSQL(RenderContext context, Object val) {
|
||||
if (val == null) {
|
||||
toSQL(context, val, Object.class);
|
||||
}
|
||||
else {
|
||||
toSQL(context, val, val.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlining abstraction
|
||||
*/
|
||||
private void toSQL(RenderContext context, Object val, Class<?> type) {
|
||||
if (context.inline()) {
|
||||
if (val == null) {
|
||||
context.sql("null");
|
||||
}
|
||||
else if (type == Boolean.class) {
|
||||
context.sql(val.toString());
|
||||
}
|
||||
else if (type == byte[].class) {
|
||||
|
||||
// TODO [#990] This can cause issues
|
||||
context.sql("'")
|
||||
.sql(new String((byte[]) val).replace("'", "''"))
|
||||
.sql("'");
|
||||
}
|
||||
else if (Number.class.isAssignableFrom(type)) {
|
||||
context.sql(val.toString());
|
||||
}
|
||||
else if (type.isArray()) {
|
||||
context.sql("ARRAY")
|
||||
.sql(Arrays.asList((Object[]) val).toString());
|
||||
}
|
||||
else if (ArrayRecord.class.isAssignableFrom(type)) {
|
||||
context.sql(val.toString());
|
||||
}
|
||||
else if (EnumType.class.isAssignableFrom(type)) {
|
||||
toSQL(context, ((EnumType) val).getLiteral());
|
||||
}
|
||||
else if (MasterDataType.class.isAssignableFrom(type)) {
|
||||
toSQL(context, ((MasterDataType<?>) val).getPrimaryKey());
|
||||
}
|
||||
else if (UDTRecord.class.isAssignableFrom(type)) {
|
||||
context.sql("[UDT]");
|
||||
}
|
||||
|
||||
// Known fall-through types:
|
||||
// - Blob, Clob (both not supported by jOOQ)
|
||||
// - String
|
||||
// - java.util.Date subtypes
|
||||
else {
|
||||
context.sql("'")
|
||||
.sql(val.toString().replace("'", "''"))
|
||||
.sql("'");
|
||||
}
|
||||
}
|
||||
|
||||
// In Postgres, some additional casting must be done in some cases...
|
||||
// TODO: Improve this implementation with [#215] (cast support)
|
||||
else if (context.getDialect() == SQLDialect.POSTGRES) {
|
||||
|
||||
// Postgres needs explicit casting for array types
|
||||
if (type.isArray() && byte[].class != type) {
|
||||
context.sql(getBindVariable(context));
|
||||
context.sql("::");
|
||||
context.sql(FieldTypeHelper.getDataType(context.getDialect(), type).getCastTypeName(context));
|
||||
}
|
||||
|
||||
// ... and also for enum types
|
||||
else if (EnumType.class.isAssignableFrom(type)) {
|
||||
context.sql(getBindVariable(context));
|
||||
context.sql("::");
|
||||
context.literal(((EnumType) val).getName());
|
||||
}
|
||||
|
||||
else {
|
||||
context.sql(getBindVariable(context));
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
context.sql(getBindVariable(context));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext context) {
|
||||
context.bindValue(getValue(), getType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isNullLiteral() {
|
||||
return getValue() == null;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Param API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
@Override
|
||||
public final void setValue(T value) {
|
||||
setConverted(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void setConverted(Object value) {
|
||||
this.value = getDataType().convert(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getParamName() {
|
||||
return paramName;
|
||||
}
|
||||
}
|
||||
@ -48,6 +48,7 @@ import static org.jooq.impl.Factory.falseCondition;
|
||||
import static org.jooq.impl.Factory.field;
|
||||
import static org.jooq.impl.Factory.max;
|
||||
import static org.jooq.impl.Factory.min;
|
||||
import static org.jooq.impl.Factory.param;
|
||||
import static org.jooq.impl.Factory.replace;
|
||||
import static org.jooq.impl.Factory.round;
|
||||
import static org.jooq.impl.Factory.sum;
|
||||
@ -67,6 +68,8 @@ import java.sql.Connection;
|
||||
import java.sql.Date;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@ -83,6 +86,8 @@ import org.jooq.Insert;
|
||||
import org.jooq.InsertQuery;
|
||||
import org.jooq.Merge;
|
||||
import org.jooq.Operator;
|
||||
import org.jooq.Param;
|
||||
import org.jooq.Query;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.Select;
|
||||
import org.jooq.SelectFinalStep;
|
||||
@ -184,8 +189,12 @@ public class jOOQTest {
|
||||
return r_decT().inline(true);
|
||||
}
|
||||
|
||||
protected final RenderContext r_refP() {
|
||||
return r_ref().namedParams(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testNullPointerExceptionSafety() throws Exception {
|
||||
public void testNullPointerExceptionSafety() throws Exception {
|
||||
// Functions created from a field
|
||||
// ------------------------------
|
||||
assertEquals(
|
||||
@ -524,7 +533,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testTruncate() throws Exception {
|
||||
public void testTruncate() throws Exception {
|
||||
Truncate<Table1Record> t = create.truncate(TABLE1);
|
||||
|
||||
assertEquals("truncate table \"TABLE1\"", r_dec().render(t));
|
||||
@ -532,7 +541,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testAliasing() throws Exception {
|
||||
public void testAliasing() throws Exception {
|
||||
assertEquals("\"TABLE1\"", r_decT().render(TABLE1));
|
||||
assertEquals("\"TABLE1\"", r_decF().render(TABLE1));
|
||||
assertEquals("\"TABLE1\"", r_ref().render(TABLE1));
|
||||
@ -581,7 +590,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testMultipleCombinedCondition() throws Exception {
|
||||
public void testMultipleCombinedCondition() throws Exception {
|
||||
Condition c1 = FIELD_ID1.equal(10);
|
||||
Condition c2 = FIELD_ID2.equal(20);
|
||||
Condition c3 = FIELD_ID1.equal(30);
|
||||
@ -617,7 +626,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testBetweenCondition() throws Exception {
|
||||
public void testBetweenCondition() throws Exception {
|
||||
Condition c = FIELD_ID1.between(1, 10);
|
||||
assertEquals("\"TABLE1\".\"ID1\" between 1 and 10", r_refI().render(c));
|
||||
assertEquals("\"TABLE1\".\"ID1\" between ? and ?", r_ref().render(c));
|
||||
@ -634,7 +643,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInCondition() throws Exception {
|
||||
public void testInCondition() throws Exception {
|
||||
Condition c = FIELD_ID1.in(new Integer[0]);
|
||||
assertEquals(falseCondition(), c);
|
||||
|
||||
@ -657,7 +666,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInSelectCondition() throws Exception {
|
||||
public void testInSelectCondition() throws Exception {
|
||||
Condition c = FIELD_ID1.in(create.selectFrom(TABLE1).where(FIELD_NAME1.equal("x")));
|
||||
assertEquals("\"TABLE1\".\"ID1\" in (select \"TABLE1\".\"ID1\", \"TABLE1\".\"NAME1\", \"TABLE1\".\"DATE1\" from \"TABLE1\" where \"TABLE1\".\"NAME1\" = 'x')", r_refI().render(c));
|
||||
assertEquals("\"TABLE1\".\"ID1\" in (select \"TABLE1\".\"ID1\", \"TABLE1\".\"NAME1\", \"TABLE1\".\"DATE1\" from \"TABLE1\" where \"TABLE1\".\"NAME1\" = ?)", r_ref().render(c));
|
||||
@ -677,7 +686,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testCompareCondition() throws Exception {
|
||||
public void testCompareCondition() throws Exception {
|
||||
Condition c = FIELD_ID1.equal(10);
|
||||
assertEquals("\"TABLE1\".\"ID1\" = 10", r_refI().render(c));
|
||||
assertEquals("\"TABLE1\".\"ID1\" = ?", r_ref().render(c));
|
||||
@ -693,7 +702,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testNotCondition() throws Exception {
|
||||
public void testNotCondition() throws Exception {
|
||||
Condition c = FIELD_ID1.equal(10).not();
|
||||
assertEquals("not(\"TABLE1\".\"ID1\" = 10)", r_refI().render(c));
|
||||
assertEquals("not(\"TABLE1\".\"ID1\" = ?)", r_ref().render(c));
|
||||
@ -712,7 +721,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testPlainSQLCondition() throws Exception {
|
||||
public void testPlainSQLCondition() throws Exception {
|
||||
Condition c1 = condition("TABLE1.ID = 10");
|
||||
Condition c2 = condition("TABLE1.ID = ? and TABLE2.ID = ?", 10, "20");
|
||||
|
||||
@ -734,7 +743,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testCustomCondition() throws Exception {
|
||||
public void testCustomCondition() throws Exception {
|
||||
Condition c = new CustomCondition() {
|
||||
private static final long serialVersionUID = 6302350477408137757L;
|
||||
|
||||
@ -772,7 +781,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testPlainSQLField() throws Exception {
|
||||
public void testPlainSQLField() throws Exception {
|
||||
Field<?> f1 = field("DECODE(TABLE1.ID, 1, 'a', 'b')");
|
||||
Field<?> f2 = field("DECODE(TABLE1.ID, 1, ?, ?)", "a", "b");
|
||||
|
||||
@ -794,7 +803,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testCustomField() throws Exception {
|
||||
public void testCustomField() throws Exception {
|
||||
Field<?> f = new CustomField<Integer>("test", TestDataType.INTEGER_TYPE) {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ -827,7 +836,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testIsNullCondition() throws Exception {
|
||||
public void testIsNullCondition() throws Exception {
|
||||
Condition c1 = FIELD_ID1.isNull();
|
||||
assertEquals("\"TABLE1\".\"ID1\" is null", r_refI().render(c1));
|
||||
assertEquals("\"TABLE1\".\"ID1\" is null", r_ref().render(c1));
|
||||
@ -844,7 +853,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testCaseValueFunction() throws Exception {
|
||||
public void testCaseValueFunction() throws Exception {
|
||||
Case decode = decode();
|
||||
CaseValueStep<Integer> value = decode.value(FIELD_ID1);
|
||||
CaseWhenStep<Integer, String> c = value.when(1, "one");
|
||||
@ -883,7 +892,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testCaseConditionFunction() throws Exception {
|
||||
public void testCaseConditionFunction() throws Exception {
|
||||
Case decode = decode();
|
||||
CaseConditionStep<String> c = decode.when(FIELD_ID1.equal(1), "one");
|
||||
|
||||
@ -921,7 +930,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testNullFunction() throws Exception {
|
||||
public void testNullFunction() throws Exception {
|
||||
Field<?> f = val((Object) null);
|
||||
assertEquals("null", r_refI().render(f));
|
||||
assertEquals("null", r_ref().render(f));
|
||||
@ -931,7 +940,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testConstantFunction() throws Exception {
|
||||
public void testConstantFunction() throws Exception {
|
||||
Field<Integer> f1 = val(Integer.valueOf(1));
|
||||
assertEquals(Integer.class, f1.getType());
|
||||
assertEquals("1", r_refI().render(f1));
|
||||
@ -971,7 +980,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testArithmeticSumExpressions() throws Exception {
|
||||
public void testArithmeticSumExpressions() throws Exception {
|
||||
Field<Integer> sum1 = FIELD_ID1.add(FIELD_ID1).add(1).add(2);
|
||||
assertEquals(Integer.class, sum1.getType());
|
||||
assertEquals("(\"TABLE1\".\"ID1\" + \"TABLE1\".\"ID1\" + 1 + 2)", r_refI().render(sum1));
|
||||
@ -999,7 +1008,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testArithmeticDifferenceExpressions() throws Exception {
|
||||
public void testArithmeticDifferenceExpressions() throws Exception {
|
||||
Field<Integer> difference1 = FIELD_ID1.sub(FIELD_ID1).sub(1).sub(2);
|
||||
assertEquals(Integer.class, difference1.getType());
|
||||
assertEquals("(((\"TABLE1\".\"ID1\" - \"TABLE1\".\"ID1\") - 1) - 2)", r_refI().render(difference1));
|
||||
@ -1027,7 +1036,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testArithmeticProductExpressions() throws Exception {
|
||||
public void testArithmeticProductExpressions() throws Exception {
|
||||
Field<Integer> product1 = FIELD_ID1.mul(FIELD_ID1).mul(1).mul(2);
|
||||
assertEquals(Integer.class, product1.getType());
|
||||
assertEquals("(\"TABLE1\".\"ID1\" * \"TABLE1\".\"ID1\" * 1 * 2)", r_refI().render(product1));
|
||||
@ -1055,7 +1064,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testArithmeticDivisionExpressions() throws Exception {
|
||||
public void testArithmeticDivisionExpressions() throws Exception {
|
||||
Field<Integer> division1 = FIELD_ID1.div(FIELD_ID1).div(1).div(2);
|
||||
assertEquals(Integer.class, division1.getType());
|
||||
assertEquals("(((\"TABLE1\".\"ID1\" / \"TABLE1\".\"ID1\") / 1) / 2)", r_refI().render(division1));
|
||||
@ -1083,14 +1092,14 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testFunctions() {
|
||||
public void testFunctions() {
|
||||
Field<String> f = replace(FIELD_NAME1, "a", "b");
|
||||
assertEquals("replace(\"TABLE1\".\"NAME1\", 'a', 'b')", r_refI().render(f));
|
||||
assertEquals("replace(\"TABLE1\".\"NAME1\", ?, ?)", r_ref().render(f));
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testArithmeticExpressions() {
|
||||
public void testArithmeticExpressions() {
|
||||
Field<? extends Number> f;
|
||||
|
||||
f = FIELD_ID1.add(1).sub(2).add(3);
|
||||
@ -1119,7 +1128,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testArithmeticFunctions() throws Exception {
|
||||
public void testArithmeticFunctions() throws Exception {
|
||||
Field<BigDecimal> sum1 = sum(FIELD_ID1);
|
||||
assertEquals(BigDecimal.class, sum1.getType());
|
||||
assertEquals("sum(\"TABLE1\".\"ID1\")", r_refI().render(sum1));
|
||||
@ -1234,7 +1243,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInsertQuery1() throws Exception {
|
||||
public void testInsertQuery1() throws Exception {
|
||||
InsertQuery<Table1Record> q = create.insertQuery(TABLE1);
|
||||
|
||||
q.addValue(FIELD_ID1, 10);
|
||||
@ -1254,7 +1263,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInsertQuery2() throws Exception {
|
||||
public void testInsertQuery2() throws Exception {
|
||||
InsertQuery<Table1Record> q = create.insertQuery(TABLE1);
|
||||
|
||||
q.addValue(FIELD_ID1, 10);
|
||||
@ -1278,7 +1287,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInsertSelect1() throws Exception {
|
||||
public void testInsertSelect1() throws Exception {
|
||||
InsertQuery<Table1Record> q = create.insertQuery(TABLE1);
|
||||
|
||||
q.addValue(FIELD_ID1, round(val(10)));
|
||||
@ -1298,7 +1307,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInsertSelect2() throws Exception {
|
||||
public void testInsertSelect2() throws Exception {
|
||||
Insert<Table1Record> q = create.insertInto(TABLE1, create.selectQuery());
|
||||
|
||||
assertEquals("insert into \"TABLE1\" (\"ID1\", \"NAME1\", \"DATE1\") select 1 from dual", r_refI().render(q));
|
||||
@ -1321,7 +1330,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testUpdateQuery1() throws Exception {
|
||||
public void testUpdateQuery1() throws Exception {
|
||||
UpdateQuery<Table1Record> q = create.updateQuery(TABLE1);
|
||||
|
||||
q.addValue(FIELD_ID1, 10);
|
||||
@ -1340,7 +1349,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testUpdateQuery2() throws Exception {
|
||||
public void testUpdateQuery2() throws Exception {
|
||||
UpdateQuery<Table1Record> q = create.updateQuery(TABLE1);
|
||||
|
||||
q.addValue(FIELD_ID1, 10);
|
||||
@ -1361,7 +1370,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testUpdateQuery3() throws Exception {
|
||||
public void testUpdateQuery3() throws Exception {
|
||||
UpdateQuery<Table1Record> q = create.updateQuery(TABLE1);
|
||||
Condition c = FIELD_ID1.equal(10);
|
||||
|
||||
@ -1385,7 +1394,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testUpdateQuery4() throws Exception {
|
||||
public void testUpdateQuery4() throws Exception {
|
||||
UpdateQuery<Table1Record> q = create.updateQuery(TABLE1);
|
||||
Condition c1 = FIELD_ID1.equal(10);
|
||||
Condition c2 = FIELD_ID1.equal(20);
|
||||
@ -1412,7 +1421,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testUpdateQuery5() throws Exception {
|
||||
public void testUpdateQuery5() throws Exception {
|
||||
UpdateQuery<Table1Record> q = create.updateQuery(TABLE1);
|
||||
Condition c1 = FIELD_ID1.equal(10);
|
||||
Condition c2 = FIELD_ID1.equal(20);
|
||||
@ -1442,7 +1451,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testMergeQuery() throws Exception {
|
||||
public void testMergeQuery() throws Exception {
|
||||
Merge<Table1Record> q =
|
||||
create.mergeInto(TABLE1)
|
||||
.using(create.select(FIELD_ID2).from(TABLE2))
|
||||
@ -1475,7 +1484,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDeleteQuery1() throws Exception {
|
||||
public void testDeleteQuery1() throws Exception {
|
||||
DeleteQuery<Table1Record> q = create.deleteQuery(TABLE1);
|
||||
|
||||
assertEquals("delete from \"TABLE1\"", r_refI().render(q));
|
||||
@ -1484,7 +1493,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDeleteQuery2() throws Exception {
|
||||
public void testDeleteQuery2() throws Exception {
|
||||
DeleteQuery<Table1Record> q = create.deleteQuery(TABLE1);
|
||||
|
||||
q.addConditions(falseCondition());
|
||||
@ -1494,7 +1503,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDeleteQuery3() throws Exception {
|
||||
public void testDeleteQuery3() throws Exception {
|
||||
DeleteQuery<Table1Record> q = create.deleteQuery(TABLE1);
|
||||
Condition c1 = FIELD_ID1.equal(10);
|
||||
Condition c2 = FIELD_ID1.equal(20);
|
||||
@ -1517,7 +1526,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDeleteQuery4() throws Exception {
|
||||
public void testDeleteQuery4() throws Exception {
|
||||
DeleteQuery<Table1Record> q = create.deleteQuery(TABLE1);
|
||||
Condition c1 = FIELD_ID1.equal(10);
|
||||
Condition c2 = FIELD_ID1.equal(20);
|
||||
@ -1543,7 +1552,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testConditionalSelectQuery1() throws Exception {
|
||||
public void testConditionalSelectQuery1() throws Exception {
|
||||
Select<?> q = create.selectQuery();
|
||||
Select<?> s = create.select();
|
||||
|
||||
@ -1553,7 +1562,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testConditionalSelectQuery2() throws Exception {
|
||||
public void testConditionalSelectQuery2() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
|
||||
q.addConditions(falseCondition());
|
||||
@ -1563,7 +1572,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testConditionalSelectQuery3() throws Exception {
|
||||
public void testConditionalSelectQuery3() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
|
||||
q.addConditions(falseCondition());
|
||||
@ -1574,7 +1583,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testConditionalSelectQuery4() throws Exception {
|
||||
public void testConditionalSelectQuery4() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
Condition c1 = FIELD_ID1.equal(10);
|
||||
Condition c2 = FIELD_ID1.equal(20);
|
||||
@ -1600,7 +1609,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testConditionalSelectQuery5() throws Exception {
|
||||
public void testConditionalSelectQuery5() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
Condition c1 = condition("\"TABLE1\".\"ID1\" = ?", "10");
|
||||
Condition c2 = condition("\"TABLE2\".\"ID2\" = 20 or \"TABLE2\".\"ID2\" = ?", 30);
|
||||
@ -1623,7 +1632,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testDistinctSelectQuery() throws Exception {
|
||||
public void testDistinctSelectQuery() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
q.addSelect(FIELD_ID1, FIELD_ID2);
|
||||
q.setDistinct(true);
|
||||
@ -1637,7 +1646,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testProductSelectQuery() throws Exception {
|
||||
public void testProductSelectQuery() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
|
||||
q.addFrom(TABLE1);
|
||||
@ -1652,7 +1661,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testJoinSelectQuery() throws Exception {
|
||||
public void testJoinSelectQuery() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
|
||||
q.addFrom(TABLE1);
|
||||
@ -1666,7 +1675,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testJoinOnConditionSelectQuery() throws Exception {
|
||||
public void testJoinOnConditionSelectQuery() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
q.addFrom(TABLE1);
|
||||
q.addJoin(TABLE2, FIELD_ID1.equal(FIELD_ID2));
|
||||
@ -1687,7 +1696,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testJoinComplexSelectQuery() throws Exception {
|
||||
public void testJoinComplexSelectQuery() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
|
||||
q.addFrom(TABLE1);
|
||||
@ -1741,7 +1750,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testJoinSelf() throws Exception {
|
||||
public void testJoinSelf() throws Exception {
|
||||
Table<Table1Record> t1 = TABLE1.as("t1");
|
||||
Table<Table1Record> t2 = TABLE1.as("t2");
|
||||
|
||||
@ -1760,7 +1769,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testJoinTypeSelectQuery() throws Exception {
|
||||
public void testJoinTypeSelectQuery() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
q.addFrom(TABLE1);
|
||||
q.addJoin(TABLE2, LEFT_OUTER_JOIN, FIELD_ID1.equal(FIELD_ID2));
|
||||
@ -1773,7 +1782,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testGroupSelectQuery() throws Exception {
|
||||
public void testGroupSelectQuery() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
q.addFrom(TABLE1);
|
||||
|
||||
@ -1837,7 +1846,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testOrderSelectQuery() throws Exception {
|
||||
public void testOrderSelectQuery() throws Exception {
|
||||
SimpleSelectQuery<Table1Record> q = create.selectQuery(TABLE1);
|
||||
|
||||
q.addOrderBy(FIELD_ID1);
|
||||
@ -1857,7 +1866,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testCompleteSelectQuery() throws Exception {
|
||||
public void testCompleteSelectQuery() throws Exception {
|
||||
SelectQuery q = create.selectQuery();
|
||||
q.addFrom(TABLE1);
|
||||
q.addJoin(TABLE2, FIELD_ID1.equal(FIELD_ID2));
|
||||
@ -1889,7 +1898,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testCombinedSelectQuery() throws Exception {
|
||||
public void testCombinedSelectQuery() throws Exception {
|
||||
Select<?> combine = createCombinedSelectQuery();
|
||||
|
||||
assertEquals("(select \"TABLE1\".\"ID1\", \"TABLE1\".\"NAME1\", \"TABLE1\".\"DATE1\" from \"TABLE1\" where \"TABLE1\".\"ID1\" = 1) union (select \"TABLE1\".\"ID1\", \"TABLE1\".\"NAME1\", \"TABLE1\".\"DATE1\" from \"TABLE1\" where \"TABLE1\".\"ID1\" = 2)", r_refI().render(combine));
|
||||
@ -1949,7 +1958,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInnerSelect1() throws Exception {
|
||||
public void testInnerSelect1() throws Exception {
|
||||
SimpleSelectQuery<Table1Record> q1 = create.selectQuery(TABLE1);
|
||||
SimpleSelectQuery<Table1Record> q2 = create.selectQuery(q1.asTable().as("inner_temp_table"));
|
||||
SimpleSelectQuery<Table1Record> q3 = create.selectQuery(q2.asTable().as("outer_temp_table"));
|
||||
@ -1962,7 +1971,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInnerSelect2() throws Exception {
|
||||
public void testInnerSelect2() throws Exception {
|
||||
SelectQuery q1 = create.selectQuery();
|
||||
SelectQuery q2 = create.selectQuery();
|
||||
|
||||
@ -1978,7 +1987,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInnerSelect3() throws Exception {
|
||||
public void testInnerSelect3() throws Exception {
|
||||
SelectQuery q1 = create.selectQuery();
|
||||
SelectQuery q2 = create.selectQuery();
|
||||
|
||||
@ -1993,7 +2002,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInnerSelect4() throws Exception {
|
||||
public void testInnerSelect4() throws Exception {
|
||||
SelectQuery q1 = create.selectQuery();
|
||||
SelectQuery q2 = create.selectQuery();
|
||||
|
||||
@ -2008,7 +2017,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInnerSelect5() throws Exception {
|
||||
public void testInnerSelect5() throws Exception {
|
||||
SelectQuery q1 = create.selectQuery();
|
||||
SelectQuery q2 = create.selectQuery();
|
||||
|
||||
@ -2023,7 +2032,7 @@ public class jOOQTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public final void testInnerSelect6() throws Exception {
|
||||
public void testInnerSelect6() throws Exception {
|
||||
SelectQuery q1 = create.selectQuery();
|
||||
SelectQuery q2 = create.selectQuery();
|
||||
|
||||
@ -2036,4 +2045,98 @@ public class jOOQTest {
|
||||
assertEquals("select \"TABLE1\".\"ID1\", \"TABLE1\".\"NAME1\", \"TABLE1\".\"DATE1\" from \"TABLE1\" where exists (select \"TABLE2\".\"ID2\" from \"TABLE2\")", r_refI().render(q1));
|
||||
assertEquals("select \"TABLE1\".\"ID1\", \"TABLE1\".\"NAME1\", \"TABLE1\".\"DATE1\" from \"TABLE1\" where exists (select \"TABLE2\".\"ID2\" from \"TABLE2\")", r_ref().render(q1));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNamedParams() throws Exception {
|
||||
Query q1 = create.select(val(1)).from(TABLE1).where(FIELD_ID1.equal(val(2)));
|
||||
Query q2 = create.select(param("p1", 1)).from(TABLE1).where(FIELD_ID1.equal(param("p2", 2)));
|
||||
Query q3 = create.select(param("p1", 1)).from(TABLE1).where(FIELD_ID1.equal(2));
|
||||
Query q4 = create.select(val(1)).from(TABLE1).where(FIELD_ID1.equal(param("p2", 2)));
|
||||
|
||||
assertEquals("select 1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = 2", r_refI().render(q1));
|
||||
assertEquals("select :1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = :2", r_refP().render(q1));
|
||||
assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref().render(q1));
|
||||
|
||||
assertEquals("select 1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = 2", r_refI().render(q2));
|
||||
assertEquals("select :p1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = :p2", r_refP().render(q2));
|
||||
assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref().render(q2));
|
||||
|
||||
assertEquals("select 1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = 2", r_refI().render(q3));
|
||||
assertEquals("select :p1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = :2", r_refP().render(q3));
|
||||
assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref().render(q3));
|
||||
|
||||
assertEquals("select 1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = 2", r_refI().render(q4));
|
||||
assertEquals("select :1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = :p2", r_refP().render(q4));
|
||||
assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref().render(q4));
|
||||
|
||||
// Param / Val queries should be equal as toString() doesn't consider params
|
||||
assertEquals(q1, q2);
|
||||
assertEquals(q1, q3);
|
||||
assertEquals(q1, q4);
|
||||
|
||||
// Params
|
||||
Param<?> p11 = q1.getParam("1");
|
||||
Param<?> p21 = q2.getParam("p1");
|
||||
Param<?> p31 = q3.getParam("p1");
|
||||
Param<?> p41 = q4.getParam("1");
|
||||
|
||||
Param<?> p12 = q1.getParam("2");
|
||||
Param<?> p22 = q2.getParam("p2");
|
||||
Param<?> p32 = q3.getParam("2");
|
||||
Param<?> p42 = q4.getParam("p2");
|
||||
|
||||
assertEquals(Arrays.asList("1", "2"), new ArrayList<String>(q1.getParams().keySet()));
|
||||
assertEquals(Arrays.asList("p1", "p2"), new ArrayList<String>(q2.getParams().keySet()));
|
||||
assertEquals(Arrays.asList("p1", "2"), new ArrayList<String>(q3.getParams().keySet()));
|
||||
assertEquals(Arrays.asList("1", "p2"), new ArrayList<String>(q4.getParams().keySet()));
|
||||
|
||||
// Types
|
||||
assertEquals(Integer.class, p11.getType());
|
||||
assertEquals(Integer.class, p21.getType());
|
||||
assertEquals(Integer.class, p31.getType());
|
||||
assertEquals(Integer.class, p41.getType());
|
||||
|
||||
assertEquals(Integer.class, p12.getType());
|
||||
assertEquals(Integer.class, p22.getType());
|
||||
assertEquals(Integer.class, p32.getType());
|
||||
assertEquals(Integer.class, p42.getType());
|
||||
|
||||
// Values
|
||||
assertEquals(Integer.valueOf(1), p11.getValue());
|
||||
assertEquals(Integer.valueOf(1), p21.getValue());
|
||||
assertEquals(Integer.valueOf(1), p31.getValue());
|
||||
assertEquals(Integer.valueOf(1), p41.getValue());
|
||||
|
||||
assertEquals(Integer.valueOf(2), p12.getValue());
|
||||
assertEquals(Integer.valueOf(2), p22.getValue());
|
||||
assertEquals(Integer.valueOf(2), p32.getValue());
|
||||
assertEquals(Integer.valueOf(2), p42.getValue());
|
||||
|
||||
// Param replacement
|
||||
p11.setConverted(3);
|
||||
p21.setConverted(3);
|
||||
p31.setConverted(3);
|
||||
p41.setConverted(3);
|
||||
|
||||
p12.setConverted(4);
|
||||
p22.setConverted(4);
|
||||
p32.setConverted(4);
|
||||
p42.setConverted(4);
|
||||
|
||||
assertEquals("select 3 from \"TABLE1\" where \"TABLE1\".\"ID1\" = 4", r_refI().render(q1));
|
||||
assertEquals("select :1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = :2", r_refP().render(q1));
|
||||
assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref().render(q1));
|
||||
|
||||
assertEquals("select 3 from \"TABLE1\" where \"TABLE1\".\"ID1\" = 4", r_refI().render(q2));
|
||||
assertEquals("select :p1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = :p2", r_refP().render(q2));
|
||||
assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref().render(q2));
|
||||
|
||||
assertEquals("select 3 from \"TABLE1\" where \"TABLE1\".\"ID1\" = 4", r_refI().render(q3));
|
||||
assertEquals("select :p1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = :2", r_refP().render(q3));
|
||||
assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref().render(q3));
|
||||
|
||||
assertEquals("select 3 from \"TABLE1\" where \"TABLE1\".\"ID1\" = 4", r_refI().render(q4));
|
||||
assertEquals("select :1 from \"TABLE1\" where \"TABLE1\".\"ID1\" = :p2", r_refP().render(q4));
|
||||
assertEquals("select ? from \"TABLE1\" where \"TABLE1\".\"ID1\" = ?", r_ref().render(q4));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user