mirror of
https://github.com/querydsl/querydsl.git
synced 2026-06-04 21:01:21 +08:00
Merge pull request #2883 from querydsl/label-to-constant
Fix various issues caused by invalid parameter assumptions
This commit is contained in:
commit
0725a54535
0
.github/touched-file-so-ci-runs
vendored
Normal file
0
.github/touched-file-so-ci-runs
vendored
Normal file
0
.github/touched-file-so-ci-runs2
vendored
Normal file
0
.github/touched-file-so-ci-runs2
vendored
Normal file
@ -56,6 +56,10 @@ A huge thanks goes out to all contributors that made this release possible in th
|
||||
* [#2663](https://github.com/querydsl/querydsl/issues/2663) - Fix issues with the JPA implementation of `InsertClause`.
|
||||
* [#2706](https://github.com/querydsl/querydsl/pull/2706) - Fix a memory leak in `TemplateFactory`.
|
||||
* [#2467](https://github.com/querydsl/querydsl/issues/2467) - Prevent `ExtendedBeanSerializer` from generating `toString` method twice
|
||||
* [#2326](https://github.com/querydsl/querydsl/issues/2326) - Use JPA indexed parameters instead of HQL's legacy positional parameters
|
||||
* [#2816](https://github.com/querydsl/querydsl/issues/2816) - Generated JPA query with incorrect argument binding indexes
|
||||
* [#1413](https://github.com/querydsl/querydsl/issues/1413) - Incorrect parameter values with Hibernate custom types
|
||||
* [#1429](https://github.com/querydsl/querydsl/issues/1429) - Reusing of constants in JPQL generation causes issues with hibernate query caching
|
||||
|
||||
#### Breaking changes
|
||||
|
||||
@ -91,6 +95,8 @@ A huge thanks goes out to all contributors that made this release possible in th
|
||||
* Removal of `HibernateDomainExporter` in `querysql-jpa-codegen`. `HibernateDomainExporter` only supported Hibernate 4, which QueryDSL no longer actively supports. Instead, use the `JPADomainExporter` with Hibernate.
|
||||
* `ComparableExpression#coalesce` (and subtypes) no longer return a mutable `Coalesce` expression, but instead return a typed expression.
|
||||
If you need the Coalesce builder, use `new Coalesce<T>().add(expression)` instead.
|
||||
* `getConstantToNamedLabel`, `getConstantToNumberedLabel` and `getConstantToAllLabels` that were temporarily introduced to `SerializerBase` and `JPQLSerializer`
|
||||
in QueryDSL 4.3.0 to eventually replace `getConstantToLabel` are now removed in favor of `getConstants`.
|
||||
|
||||
#### Deprecations
|
||||
* `AbstractJPAQuery#fetchResults` and `AbstractJPAQuery#fetchCount` are now deprecated for queries that have multiple group by
|
||||
@ -99,6 +105,7 @@ A huge thanks goes out to all contributors that made this release possible in th
|
||||
If you want a reliable way of computing the result count for a paginated result for even the most complicated queries,
|
||||
we recommend using the [Blaze-Persistence QueryDSL integration](https://persistence.blazebit.com/documentation/1.5/core/manual/en_US/#querydsl-integration).
|
||||
`BlazeJPAQuery` properly implements both `fetchResults` and `fetchCount` and even comes with a `page` method.
|
||||
* `getConstantToLabel` which was deprecated in QueryDSL 4.3.0 is no longer deprecated.
|
||||
|
||||
#### Dependency updates
|
||||
|
||||
|
||||
@ -13,20 +13,32 @@
|
||||
*/
|
||||
package com.querydsl.core.support;
|
||||
|
||||
import com.querydsl.core.JoinFlag;
|
||||
import com.querydsl.core.QueryFlag;
|
||||
import com.querydsl.core.types.Constant;
|
||||
import com.querydsl.core.types.Expression;
|
||||
import com.querydsl.core.types.FactoryExpression;
|
||||
import com.querydsl.core.types.Operation;
|
||||
import com.querydsl.core.types.Operator;
|
||||
import com.querydsl.core.types.Ops;
|
||||
import com.querydsl.core.types.ParamExpression;
|
||||
import com.querydsl.core.types.Path;
|
||||
import com.querydsl.core.types.PathType;
|
||||
import com.querydsl.core.types.Template;
|
||||
import com.querydsl.core.types.TemplateExpression;
|
||||
import com.querydsl.core.types.Templates;
|
||||
import com.querydsl.core.types.Visitor;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import com.querydsl.core.JoinFlag;
|
||||
import com.querydsl.core.QueryFlag;
|
||||
import com.querydsl.core.types.*;
|
||||
|
||||
import static java.util.Collections.unmodifiableMap;
|
||||
|
||||
/**
|
||||
* {@code SerializerBase} is a stub for Serializer implementations which serialize query metadata to Strings
|
||||
*
|
||||
@ -46,8 +58,9 @@ public abstract class SerializerBase<S extends SerializerBase<S>> implements Vis
|
||||
|
||||
private String anonParamPrefix = "_";
|
||||
|
||||
private Map<Object, String> constantToNamedLabel;
|
||||
private Map<Object, Integer> constantToNumberedLabel;
|
||||
protected final List<Object> constants = new LinkedList<>();
|
||||
|
||||
protected final Map<Object, String> constantToLabel = new IdentityHashMap<>();
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private final S self = (S) this;
|
||||
@ -79,35 +92,8 @@ public abstract class SerializerBase<S extends SerializerBase<S>> implements Vis
|
||||
return constantPrefix;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public Map<Object, String> getConstantToLabel() {
|
||||
return getConstantToAllLabels();
|
||||
}
|
||||
|
||||
public Map<Object, String> getConstantToNamedLabel() {
|
||||
if (constantToNamedLabel == null) {
|
||||
constantToNamedLabel = new HashMap<Object, String>(4);
|
||||
}
|
||||
return constantToNamedLabel;
|
||||
}
|
||||
|
||||
public Map<Object, Integer> getConstantToNumberedLabel() {
|
||||
if (constantToNumberedLabel == null) {
|
||||
constantToNumberedLabel = new HashMap<Object, Integer>(4);
|
||||
}
|
||||
return constantToNumberedLabel;
|
||||
}
|
||||
|
||||
public Map<Object, String> getConstantToAllLabels() {
|
||||
Map<Object, String> namedLabels = getConstantToNamedLabel();
|
||||
Map<Object, Integer> numberedLabels = getConstantToNumberedLabel();
|
||||
|
||||
Map<Object, String> allLabels = new HashMap<Object, String>(namedLabels);
|
||||
for (Map.Entry<Object, Integer> entry : numberedLabels.entrySet()) {
|
||||
allLabels.put(entry.getKey(), entry.getValue().toString());
|
||||
}
|
||||
|
||||
return unmodifiableMap(allLabels);
|
||||
return constantToLabel;
|
||||
}
|
||||
|
||||
protected int getLength() {
|
||||
@ -223,13 +209,37 @@ public abstract class SerializerBase<S extends SerializerBase<S>> implements Vis
|
||||
}
|
||||
|
||||
public void visitConstant(Object constant) {
|
||||
if (!getConstantToAllLabels().containsKey(constant)) {
|
||||
final String constLabel = constantPrefix + (getConstantToNamedLabel().size() + 1);
|
||||
getConstantToNamedLabel().put(constant, constLabel);
|
||||
append(constLabel);
|
||||
} else {
|
||||
append(getConstantToNamedLabel().get(constant));
|
||||
}
|
||||
final String constantLabel = getConstantToLabel().computeIfAbsent(constant, this::getConstantLabel);
|
||||
constants.add(constant);
|
||||
serializeConstant(constants.size(), constantLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serialize the constant as parameter to the query. The default implementation writes the
|
||||
* label name for the constants. Some dialects may replace this by indexed based or
|
||||
* positional parameterization.
|
||||
* Dialects may also use this to prefix the parameter with for example ":" or "?".
|
||||
*
|
||||
* @param parameterIndex index at which this constant occurs in {@link #getConstants()}
|
||||
* @param constantLabel label under which this constant occurs in {@link #getConstantToLabel()}
|
||||
*/
|
||||
protected void serializeConstant(int parameterIndex, String constantLabel) {
|
||||
append(constantLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a constant value under which to register a new constant in {@link #getConstantToLabel()}.
|
||||
*
|
||||
* @param value the constant value or parameter to create a constant for
|
||||
* @return the generated label
|
||||
*/
|
||||
@NotNull
|
||||
protected String getConstantLabel(Object value) {
|
||||
return constantPrefix + (getConstantToLabel().size() + 1);
|
||||
}
|
||||
|
||||
public List<Object> getConstants() {
|
||||
return constants;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -240,8 +250,9 @@ public abstract class SerializerBase<S extends SerializerBase<S>> implements Vis
|
||||
} else {
|
||||
paramLabel = paramPrefix + param.getName();
|
||||
}
|
||||
getConstantToNamedLabel().put(param, paramLabel);
|
||||
append(paramLabel);
|
||||
getConstantToLabel().put(param, paramLabel);
|
||||
constants.add(param);
|
||||
serializeConstant(constants.size(), paramLabel);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@ -135,7 +135,7 @@ public abstract class AbstractJDOQuery<T, Q extends AbstractJDOQuery<T, Q>> exte
|
||||
JDOQLSerializer serializer = new JDOQLSerializer(getTemplates(), source);
|
||||
serializer.serialize(queryMixin.getMetadata(), forCount, false);
|
||||
|
||||
logQuery(serializer.toString(), serializer.getConstantToAllLabels());
|
||||
logQuery(serializer.toString(), serializer.getConstantToLabel());
|
||||
|
||||
// create Query
|
||||
Query query = persistenceManager.newQuery(serializer.toString());
|
||||
|
||||
@ -79,29 +79,20 @@ public final class JDOQLSerializer extends SerializerBase<JDOQLSerializer> {
|
||||
public JDOQLSerializer(JDOQLTemplates templates, Expression<?> candidate) {
|
||||
super(templates);
|
||||
this.candidatePath = candidate;
|
||||
this.constantToLabel.push(new HashMap<Object,String>());
|
||||
this.constantToLabel.push(new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
public Expression<?> getCandidatePath() {
|
||||
return candidatePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Object> getConstants() {
|
||||
return constants;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object,String> getConstantToLabel() {
|
||||
return getConstantToAllLabels();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object,String> getConstantToAllLabels() {
|
||||
return constantToLabel.peek();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<Object,String> getConstantToNamedLabel() {
|
||||
return constantToLabel.peek();
|
||||
}
|
||||
|
||||
@ -114,7 +105,7 @@ public final class JDOQLSerializer extends SerializerBase<JDOQLSerializer> {
|
||||
final Predicate having = metadata.getHaving();
|
||||
final List<OrderSpecifier<?>> orderBy = metadata.getOrderBy();
|
||||
|
||||
constantToLabel.push(new HashMap<Object,String>());
|
||||
constantToLabel.push(new LinkedHashMap<Object,String>());
|
||||
|
||||
// select
|
||||
boolean skippedSelect = false;
|
||||
@ -197,7 +188,7 @@ public final class JDOQLSerializer extends SerializerBase<JDOQLSerializer> {
|
||||
}
|
||||
|
||||
// parameters
|
||||
if (!getConstantToAllLabels().isEmpty()) {
|
||||
if (!getConstantToLabel().isEmpty()) {
|
||||
insert(position, serializeParameters(metadata.getParams()));
|
||||
}
|
||||
|
||||
@ -222,8 +213,7 @@ public final class JDOQLSerializer extends SerializerBase<JDOQLSerializer> {
|
||||
final StringBuilder b = new StringBuilder();
|
||||
b.append(PARAMETERS);
|
||||
boolean first = true;
|
||||
final List<Map.Entry<Object, String>> entries = new ArrayList<Map.Entry<Object, String>>(getConstantToAllLabels().entrySet());
|
||||
entries.sort(comparator);
|
||||
final Collection<Map.Entry<Object, String>> entries = getConstantToLabel().entrySet();
|
||||
for (Map.Entry<Object, String> entry : entries) {
|
||||
if (!first) {
|
||||
b.append(COMMA);
|
||||
|
||||
@ -64,7 +64,7 @@ public class JDODeleteClause implements DeleteClause<JDODeleteClause> {
|
||||
JDOQLSerializer serializer = new JDOQLSerializer(templates, entity);
|
||||
serializer.handle(metadata.getWhere());
|
||||
query.setFilter(serializer.toString());
|
||||
Map<Object,String> constToLabel = serializer.getConstantToAllLabels();
|
||||
Map<Object,String> constToLabel = serializer.getConstantToLabel();
|
||||
|
||||
try {
|
||||
if (!constToLabel.isEmpty()) {
|
||||
|
||||
@ -379,14 +379,7 @@ public class JPQLSerializer extends SerializerBase<JPQLSerializer> {
|
||||
if (wrap) {
|
||||
append("(");
|
||||
}
|
||||
append("?");
|
||||
if (!getConstantToAllLabels().containsKey(constant)) {
|
||||
Integer constLabel = getConstantToNumberedLabel().size() + 1;
|
||||
getConstantToNumberedLabel().put(constant, constLabel);
|
||||
append(constLabel.toString());
|
||||
} else {
|
||||
append(getConstantToAllLabels().get(constant));
|
||||
}
|
||||
super.visitConstant(constant);
|
||||
if (wrap) {
|
||||
append(")");
|
||||
}
|
||||
@ -398,16 +391,9 @@ public class JPQLSerializer extends SerializerBase<JPQLSerializer> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(ParamExpression<?> param, Void context) {
|
||||
protected void serializeConstant(int parameterIndex, String constantLabel) {
|
||||
append("?");
|
||||
if (!getConstantToAllLabels().containsKey(param)) {
|
||||
final Integer paramLabel = getConstantToNumberedLabel().size() + 1;
|
||||
getConstantToNumberedLabel().put(param, paramLabel);
|
||||
append(paramLabel.toString());
|
||||
} else {
|
||||
append(getConstantToAllLabels().get(param));
|
||||
}
|
||||
return null;
|
||||
append(Integer.toString(parameterIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -197,15 +197,17 @@ public final class NativeSQLSerializer extends SQLSerializer {
|
||||
first = false;
|
||||
}
|
||||
append(")");
|
||||
} else if (!getConstantToAllLabels().containsKey(constant)) {
|
||||
final Integer constLabel = getConstantToNumberedLabel().size() + 1;
|
||||
getConstantToNumberedLabel().put(constant, constLabel);
|
||||
append("?" + constLabel);
|
||||
} else {
|
||||
append("?" + getConstantToAllLabels().get(constant));
|
||||
super.visitConstant(constant);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void serializeConstant(int parameterIndex, String constantLabel) {
|
||||
append("?");
|
||||
append(Integer.toString(parameterIndex));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitOperation(Class<?> type, Operator operator, List<? extends Expression<?>> args) {
|
||||
if (operator == SQLOps.ALL
|
||||
|
||||
@ -100,9 +100,9 @@ public abstract class AbstractHibernateQuery<T, Q extends AbstractHibernateQuery
|
||||
private Query createQuery(@Nullable QueryModifiers modifiers, boolean forCount) {
|
||||
JPQLSerializer serializer = serialize(forCount);
|
||||
String queryString = serializer.toString();
|
||||
logQuery(queryString, serializer.getConstantToAllLabels());
|
||||
logQuery(queryString);
|
||||
Query query = session.createQuery(queryString);
|
||||
HibernateUtil.setConstants(query, serializer.getConstantToNamedLabel(), serializer.getConstantToNumberedLabel(),
|
||||
HibernateUtil.setConstants(query, serializer.getConstants(),
|
||||
getMetadata().getParams());
|
||||
if (fetchSize > 0) {
|
||||
query.setFetchSize(fetchSize);
|
||||
@ -208,7 +208,7 @@ public abstract class AbstractHibernateQuery<T, Q extends AbstractHibernateQuery
|
||||
}
|
||||
}
|
||||
|
||||
protected void logQuery(String queryString, Map<Object, String> parameters) {
|
||||
protected void logQuery(String queryString) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
String normalizedQuery = queryString.replace('\n', ' ');
|
||||
logger.fine(normalizedQuery);
|
||||
|
||||
@ -13,14 +13,6 @@
|
||||
*/
|
||||
package com.querydsl.jpa.hibernate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.StatelessSession;
|
||||
|
||||
import com.querydsl.core.JoinType;
|
||||
import com.querydsl.core.dml.DeleteClause;
|
||||
import com.querydsl.core.support.QueryMixin;
|
||||
@ -31,6 +23,13 @@ import com.querydsl.jpa.HQLTemplates;
|
||||
import com.querydsl.jpa.JPAQueryMixin;
|
||||
import com.querydsl.jpa.JPQLSerializer;
|
||||
import com.querydsl.jpa.JPQLTemplates;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* DeleteClause implementation for Hibernate
|
||||
@ -75,8 +74,7 @@ public class HibernateDeleteClause implements DeleteClause<HibernateDeleteClause
|
||||
for (Map.Entry<Path<?>, LockMode> entry : lockModes.entrySet()) {
|
||||
query.setLockMode(entry.getKey().toString(), entry.getValue());
|
||||
}
|
||||
HibernateUtil.setConstants(query, serializer.getConstantToNamedLabel(), serializer.getConstantToNumberedLabel(),
|
||||
queryMixin.getMetadata().getParams());
|
||||
HibernateUtil.setConstants(query, serializer.getConstants(), queryMixin.getMetadata().getParams());
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
|
||||
@ -86,13 +86,12 @@ public class HibernateInsertClause implements
|
||||
public long execute() {
|
||||
JPQLSerializer serializer = new JPQLSerializer(templates, null);
|
||||
serializer.serializeForInsert(queryMixin.getMetadata(), inserts.isEmpty() ? columns : inserts.keySet(), values, subQuery, inserts);
|
||||
Map<Object, String> constants = serializer.getConstantToLabel();
|
||||
|
||||
Query query = session.createQuery(serializer.toString());
|
||||
for (Map.Entry<Path<?>, LockMode> entry : lockModes.entrySet()) {
|
||||
query.setLockMode(entry.getKey().toString(), entry.getValue());
|
||||
}
|
||||
HibernateUtil.setConstants(query, constants, queryMixin.getMetadata().getParams());
|
||||
HibernateUtil.setConstants(query, serializer.getConstants(), queryMixin.getMetadata().getParams());
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
|
||||
@ -13,16 +13,6 @@
|
||||
*/
|
||||
package com.querydsl.jpa.hibernate;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.StatelessSession;
|
||||
|
||||
import com.querydsl.core.JoinType;
|
||||
import com.querydsl.core.dml.UpdateClause;
|
||||
import com.querydsl.core.support.QueryMixin;
|
||||
@ -35,6 +25,15 @@ import com.querydsl.jpa.HQLTemplates;
|
||||
import com.querydsl.jpa.JPAQueryMixin;
|
||||
import com.querydsl.jpa.JPQLSerializer;
|
||||
import com.querydsl.jpa.JPQLTemplates;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* UpdateClause implementation for Hibernate
|
||||
@ -83,8 +82,7 @@ public class HibernateUpdateClause implements
|
||||
for (Map.Entry<Path<?>, LockMode> entry : lockModes.entrySet()) {
|
||||
query.setLockMode(entry.getKey().toString(), entry.getValue());
|
||||
}
|
||||
HibernateUtil.setConstants(query, serializer.getConstantToNamedLabel(), serializer.getConstantToNumberedLabel(),
|
||||
queryMixin.getMetadata().getParams());
|
||||
HibernateUtil.setConstants(query, serializer.getConstants(), queryMixin.getMetadata().getParams());
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
|
||||
@ -17,7 +17,6 @@ import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.type.*;
|
||||
|
||||
import com.querydsl.core.types.ParamExpression;
|
||||
@ -61,47 +60,26 @@ public final class HibernateUtil {
|
||||
}
|
||||
|
||||
public static void setConstants(
|
||||
Query<?> query,
|
||||
Map<Object, String> namedConstants,
|
||||
org.hibernate.query.Query<?> query,
|
||||
List<Object> constants,
|
||||
Map<ParamExpression<?>, Object> params
|
||||
) {
|
||||
setConstants(query, namedConstants, new HashMap<Object, Integer>(), params);
|
||||
}
|
||||
for (int i = 0; i < constants.size(); i++) {
|
||||
Object val = constants.get(i);
|
||||
|
||||
public static void setConstants(
|
||||
Query<?> query,
|
||||
Map<Object, String> namedConstants,
|
||||
Map<Object, Integer> numberedConstants,
|
||||
Map<ParamExpression<?>, Object> params
|
||||
) {
|
||||
for (Map.Entry<Object, String> entry : namedConstants.entrySet()) {
|
||||
String key = entry.getValue();
|
||||
Object val = entry.getKey();
|
||||
if (val instanceof Param) {
|
||||
Param<?> param = (Param<?>) val;
|
||||
val = params.get(val);
|
||||
if (val == null) {
|
||||
throw new ParamNotSetException((Param<?>) entry.getKey());
|
||||
throw new ParamNotSetException(param);
|
||||
}
|
||||
}
|
||||
|
||||
setValueWithNamedLabel(query, key, val);
|
||||
}
|
||||
|
||||
for (Map.Entry<Object, Integer> entry : numberedConstants.entrySet()) {
|
||||
Integer key = entry.getValue();
|
||||
Object val = entry.getKey();
|
||||
if (val instanceof Param) {
|
||||
val = params.get(val);
|
||||
if (val == null) {
|
||||
throw new ParamNotSetException((Param<?>) entry.getKey());
|
||||
}
|
||||
}
|
||||
|
||||
setValueWithNumberedLabel(query, key, val);
|
||||
setValueWithNumberedLabel(query, i + 1, val);
|
||||
}
|
||||
}
|
||||
|
||||
private static void setValueWithNamedLabel(Query<?> query, String key, Object val) {
|
||||
private static void setValueWithNumberedLabel(org.hibernate.query.Query<?> query, Integer key, Object val) {
|
||||
if (val instanceof Collection<?>) {
|
||||
query.setParameterList(key, (Collection<?>) val);
|
||||
} else if (val instanceof Object[] && !BUILT_IN.contains(val.getClass())) {
|
||||
@ -113,16 +91,8 @@ public final class HibernateUtil {
|
||||
}
|
||||
}
|
||||
|
||||
private static void setValueWithNumberedLabel(Query<?> query, Integer key, Object val) {
|
||||
if (val instanceof Number && TYPES.containsKey(val.getClass())) {
|
||||
query.setParameter(key, val, getType(val.getClass()));
|
||||
} else {
|
||||
query.setParameter(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Type getType(Class<?> clazz) {
|
||||
return TYPES.get(clazz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -84,11 +84,10 @@ public abstract class AbstractHibernateSQLQuery<T, Q extends AbstractHibernateSQ
|
||||
private Query createQuery(boolean forCount) {
|
||||
NativeSQLSerializer serializer = (NativeSQLSerializer) serialize(forCount);
|
||||
String queryString = serializer.toString();
|
||||
logQuery(queryString, serializer.getConstantToAllLabels());
|
||||
logQuery(queryString);
|
||||
org.hibernate.query.NativeQuery query = session.createSQLQuery(queryString);
|
||||
// set constants
|
||||
HibernateUtil.setConstants(query, serializer.getConstantToNamedLabel(), serializer.getConstantToNumberedLabel(),
|
||||
queryMixin.getMetadata().getParams());
|
||||
HibernateUtil.setConstants(query, serializer.getConstants(), queryMixin.getMetadata().getParams());
|
||||
|
||||
if (!forCount) {
|
||||
Map<Expression<?>, List<String>> aliases = serializer.getAliases();
|
||||
@ -201,7 +200,7 @@ public abstract class AbstractHibernateSQLQuery<T, Q extends AbstractHibernateSQ
|
||||
}
|
||||
}
|
||||
|
||||
protected void logQuery(String queryString, Map<Object, String> parameters) {
|
||||
protected void logQuery(String queryString) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
String normalizedQuery = queryString.replace('\n', ' ');
|
||||
logger.fine(normalizedQuery);
|
||||
|
||||
@ -128,9 +128,9 @@ public abstract class AbstractJPAQuery<T, Q extends AbstractJPAQuery<T, Q>> exte
|
||||
protected Query createQuery(@Nullable QueryModifiers modifiers, boolean forCount) {
|
||||
JPQLSerializer serializer = serialize(forCount);
|
||||
String queryString = serializer.toString();
|
||||
logQuery(queryString, serializer.getConstantToAllLabels());
|
||||
logQuery(queryString);
|
||||
Query query = entityManager.createQuery(queryString);
|
||||
JPAUtil.setConstants(query, serializer.getConstantToAllLabels(), getMetadata().getParams());
|
||||
JPAUtil.setConstants(query, serializer.getConstants(), getMetadata().getParams());
|
||||
if (modifiers != null && modifiers.isRestricting()) {
|
||||
Integer limit = modifiers.getLimitAsInteger();
|
||||
Integer offset = modifiers.getOffsetAsInteger();
|
||||
@ -306,7 +306,7 @@ public abstract class AbstractJPAQuery<T, Q extends AbstractJPAQuery<T, Q>> exte
|
||||
|
||||
}
|
||||
|
||||
protected void logQuery(String queryString, Map<Object, String> parameters) {
|
||||
protected void logQuery(String queryString) {
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
String normalizedQuery = queryString.replace('\n', ' ');
|
||||
logger.finest(normalizedQuery);
|
||||
|
||||
@ -13,8 +13,6 @@
|
||||
*/
|
||||
package com.querydsl.jpa.impl;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.LockModeType;
|
||||
@ -60,13 +58,12 @@ public class JPADeleteClause implements DeleteClause<JPADeleteClause> {
|
||||
public long execute() {
|
||||
JPQLSerializer serializer = new JPQLSerializer(templates, entityManager);
|
||||
serializer.serializeForDelete(queryMixin.getMetadata());
|
||||
Map<Object,String> constants = serializer.getConstantToAllLabels();
|
||||
|
||||
Query query = entityManager.createQuery(serializer.toString());
|
||||
if (lockMode != null) {
|
||||
query.setLockMode(lockMode);
|
||||
}
|
||||
JPAUtil.setConstants(query, constants, queryMixin.getMetadata().getParams());
|
||||
JPAUtil.setConstants(query, serializer.getConstants(), queryMixin.getMetadata().getParams());
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
|
||||
@ -75,13 +75,12 @@ public class JPAInsertClause implements InsertClause<JPAInsertClause> {
|
||||
public long execute() {
|
||||
JPQLSerializer serializer = new JPQLSerializer(templates, entityManager);
|
||||
serializer.serializeForInsert(queryMixin.getMetadata(), inserts.isEmpty() ? columns : inserts.keySet(), values, subQuery, inserts);
|
||||
Map<Object,String> constants = serializer.getConstantToLabel();
|
||||
|
||||
Query query = entityManager.createQuery(serializer.toString());
|
||||
if (lockMode != null) {
|
||||
query.setLockMode(lockMode);
|
||||
}
|
||||
JPAUtil.setConstants(query, constants, queryMixin.getMetadata().getParams());
|
||||
JPAUtil.setConstants(query, serializer.getConstants(), queryMixin.getMetadata().getParams());
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
|
||||
@ -67,13 +67,12 @@ public class JPAUpdateClause implements UpdateClause<JPAUpdateClause> {
|
||||
public long execute() {
|
||||
JPQLSerializer serializer = new JPQLSerializer(templates, entityManager);
|
||||
serializer.serializeForUpdate(queryMixin.getMetadata(), updates);
|
||||
Map<Object,String> constants = serializer.getConstantToAllLabels();
|
||||
|
||||
Query query = entityManager.createQuery(serializer.toString());
|
||||
if (lockMode != null) {
|
||||
query.setLockMode(lockMode);
|
||||
}
|
||||
JPAUtil.setConstants(query, constants, queryMixin.getMetadata().getParams());
|
||||
JPAUtil.setConstants(query, serializer.getConstants(), queryMixin.getMetadata().getParams());
|
||||
return query.executeUpdate();
|
||||
}
|
||||
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
*/
|
||||
package com.querydsl.jpa.impl;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.persistence.Parameter;
|
||||
@ -33,19 +34,22 @@ public final class JPAUtil {
|
||||
|
||||
private JPAUtil() { }
|
||||
|
||||
public static void setConstants(Query query, Map<Object,String> constants, Map<ParamExpression<?>, Object> params) {
|
||||
public static void setConstants(Query query, List<Object> constants, Map<ParamExpression<?>, Object> params) {
|
||||
boolean hasParameters = !query.getParameters().isEmpty();
|
||||
for (Map.Entry<Object,String> entry : constants.entrySet()) {
|
||||
String key = entry.getValue();
|
||||
Object val = entry.getKey();
|
||||
if (Param.class.isInstance(val)) {
|
||||
|
||||
for (int i = 0; i < constants.size(); i++) {
|
||||
Object val = constants.get(i);
|
||||
|
||||
if (val instanceof Param) {
|
||||
Param<?> param = (Param<?>) val;
|
||||
val = params.get(val);
|
||||
if (val == null) {
|
||||
throw new ParamNotSetException((Param<?>) entry.getKey());
|
||||
throw new ParamNotSetException(param);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasParameters) {
|
||||
Parameter parameter = query.getParameter(Integer.parseInt(key));
|
||||
Parameter parameter = query.getParameter(i + 1);
|
||||
Class parameterType = parameter != null ? parameter.getParameterType() : null;
|
||||
if (parameterType != null && !parameterType.isInstance(val)) {
|
||||
if (val instanceof Number && Number.class.isAssignableFrom(parameterType)) {
|
||||
@ -53,7 +57,8 @@ public final class JPAUtil {
|
||||
}
|
||||
}
|
||||
}
|
||||
query.setParameter(Integer.parseInt(key), val);
|
||||
|
||||
query.setParameter(i + 1, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -94,7 +94,7 @@ public abstract class AbstractJPASQLQuery<T, Q extends AbstractJPASQLQuery<T, Q>
|
||||
private Query createQuery(boolean forCount) {
|
||||
NativeSQLSerializer serializer = (NativeSQLSerializer) serialize(forCount);
|
||||
String queryString = serializer.toString();
|
||||
logQuery(queryString, serializer.getConstantToAllLabels());
|
||||
logQuery(queryString);
|
||||
Expression<?> projection = queryMixin.getMetadata().getProjection();
|
||||
Query query;
|
||||
|
||||
@ -152,7 +152,7 @@ public abstract class AbstractJPASQLQuery<T, Q extends AbstractJPASQLQuery<T, Q>
|
||||
|
||||
|
||||
// set constants
|
||||
JPAUtil.setConstants(query, serializer.getConstantToAllLabels(), queryMixin.getMetadata().getParams());
|
||||
JPAUtil.setConstants(query, serializer.getConstants(), queryMixin.getMetadata().getParams());
|
||||
this.projection = null; // necessary when query is reused
|
||||
|
||||
if (!forCount && projection instanceof FactoryExpression) {
|
||||
@ -280,7 +280,7 @@ public abstract class AbstractJPASQLQuery<T, Q extends AbstractJPASQLQuery<T, Q>
|
||||
|
||||
}
|
||||
|
||||
protected void logQuery(String queryString, Map<Object, String> parameters) {
|
||||
protected void logQuery(String queryString) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
String normalizedQuery = queryString.replace('\n', ' ');
|
||||
logger.fine(normalizedQuery);
|
||||
|
||||
@ -57,7 +57,7 @@ public class FeaturesTest extends AbstractQueryTest {
|
||||
public void argumentHandling() {
|
||||
// Kitty is reused, so it should be used via one named parameter
|
||||
assertToString(
|
||||
"cat.name = ?1 or cust.name.firstName = ?2 or kitten.name = ?1",
|
||||
"cat.name = ?1 or cust.name.firstName = ?2 or kitten.name = ?3",
|
||||
cat.name.eq("Kitty").or(cust.name.firstName.eq("Hans")).or(kitten.name.eq("Kitty")));
|
||||
}
|
||||
|
||||
|
||||
@ -55,8 +55,7 @@ public class IntegrationBase extends ParsingTest implements HibernateTest {
|
||||
JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT);
|
||||
serializer.serialize(getMetadata(), false, null);
|
||||
Query query = session.createQuery(serializer.toString());
|
||||
HibernateUtil.setConstants(query, serializer.getConstantToNamedLabel(),
|
||||
serializer.getConstantToNumberedLabel(), getMetadata().getParams());
|
||||
HibernateUtil.setConstants(query, serializer.getConstants(), getMetadata().getParams());
|
||||
query.list();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
||||
@ -51,7 +51,7 @@ public class JPAIntegrationBase extends ParsingTest implements JPATest {
|
||||
JPQLSerializer serializer = new JPQLSerializer(templates);
|
||||
serializer.serialize(getMetadata(), false, null);
|
||||
Query query = em.createQuery(serializer.toString());
|
||||
JPAUtil.setConstants(query, serializer.getConstantToAllLabels(), getMetadata().getParams());
|
||||
JPAUtil.setConstants(query, serializer.getConstants(), getMetadata().getParams());
|
||||
try {
|
||||
query.getResultList();
|
||||
} catch (Exception e) {
|
||||
|
||||
@ -58,7 +58,7 @@ public class JPQLSerializerTest {
|
||||
.when(cat.toes.eq(3)).then(3)
|
||||
.otherwise(4);
|
||||
serializer.handle(expr);
|
||||
assertEquals("case when (cat.toes = ?1) then ?1 when (cat.toes = ?2) then ?2 else ?3 end", serializer.toString());
|
||||
assertEquals("case when (cat.toes = ?1) then ?2 when (cat.toes = ?3) then ?4 else ?5 end", serializer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -69,7 +69,7 @@ public class JPQLSerializerTest {
|
||||
.when(cat.toes.eq(3)).then(3)
|
||||
.otherwise(4);
|
||||
serializer.handle(expr);
|
||||
assertEquals("case when (cat.toes = ?1) then ?1 when (cat.toes = ?2) then ?2 else 4 end", serializer.toString());
|
||||
assertEquals("case when (cat.toes = ?1) then ?2 when (cat.toes = ?3) then ?4 else 4 end", serializer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -80,7 +80,7 @@ public class JPQLSerializerTest {
|
||||
.when(cat.toes.eq(3)).then(cat.id.multiply(3))
|
||||
.otherwise(4);
|
||||
serializer.handle(expr);
|
||||
assertEquals("case when (cat.toes = ?1) then (cat.id * ?1) when (cat.toes = ?2) then (cat.id * ?2) else ?3 end", serializer.toString());
|
||||
assertEquals("case when (cat.toes = ?1) then (cat.id * ?2) when (cat.toes = ?3) then (cat.id * ?4) else ?5 end", serializer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -91,7 +91,7 @@ public class JPQLSerializerTest {
|
||||
.when(cat.toes.eq(3)).then(cat.id.multiply(3))
|
||||
.otherwise(4);
|
||||
serializer.handle(expr);
|
||||
assertEquals("case when (cat.toes = ?1) then (cat.id * ?1) when (cat.toes = ?2) then (cat.id * ?2) else 4 end", serializer.toString());
|
||||
assertEquals("case when (cat.toes = ?1) then (cat.id * ?2) when (cat.toes = ?3) then (cat.id * ?4) else 4 end", serializer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -140,7 +140,7 @@ public class JPQLSerializerTest {
|
||||
serializer.handle(doublePath.add(1));
|
||||
serializer.handle(doublePath.between((float) 1.0, 1L));
|
||||
serializer.handle(doublePath.lt((byte) 1));
|
||||
for (Object constant : serializer.getConstantToAllLabels().keySet()) {
|
||||
for (Object constant : serializer.getConstants()) {
|
||||
assertEquals(Double.class, constant.getClass());
|
||||
}
|
||||
}
|
||||
@ -194,7 +194,7 @@ public class JPQLSerializerTest {
|
||||
JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT);
|
||||
serializer.handle(Expressions.stringPath("str").contains("abc!"));
|
||||
assertEquals("str like ?1 escape '!'", serializer.toString());
|
||||
assertEquals("%abc!!%", serializer.getConstantToAllLabels().keySet().iterator().next().toString());
|
||||
assertEquals("%abc!!%", serializer.getConstants().get(0).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -202,7 +202,7 @@ public class JPQLSerializerTest {
|
||||
JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT);
|
||||
serializer.handle(Expressions.stringPath("str").containsIgnoreCase("ABc!"));
|
||||
assertEquals("lower(str) like ?1 escape '!'", serializer.toString());
|
||||
assertEquals("%abc!!%", serializer.getConstantToAllLabels().keySet().iterator().next().toString());
|
||||
assertEquals("%abc!!%", serializer.getConstants().get(0).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -210,7 +210,7 @@ public class JPQLSerializerTest {
|
||||
JPQLSerializer serializer = new JPQLSerializer(HQLTemplates.DEFAULT);
|
||||
QCat cat = QCat.cat;
|
||||
serializer.handle(cat.name.substring(cat.name.length().subtract(1), 1));
|
||||
assertEquals("substring(cat.name,length(cat.name) + ?1,?2 - (length(cat.name) - ?2))", serializer.toString());
|
||||
assertEquals("substring(cat.name,length(cat.name) + ?1,?2 - (length(cat.name) - ?3))", serializer.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -50,17 +50,17 @@ public class MathTest extends AbstractQueryTest {
|
||||
|
||||
@Test
|
||||
public void add_and_compare() {
|
||||
assertToString("cat.bodyWeight + ?1 < ?1", cat.bodyWeight.add(10.0).lt(10.0));
|
||||
assertToString("cat.bodyWeight + ?1 < ?2", cat.bodyWeight.add(10.0).lt(10.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subtract_and_compare() {
|
||||
assertToString("cat.bodyWeight - ?1 < ?1", cat.bodyWeight.subtract(10.0).lt(10.0));
|
||||
assertToString("cat.bodyWeight - ?1 < ?2", cat.bodyWeight.subtract(10.0).lt(10.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void multiply_and_compare() {
|
||||
assertToString("cat.bodyWeight * ?1 < ?1", cat.bodyWeight.multiply(10.0).lt(10.0));
|
||||
assertToString("cat.bodyWeight * ?1 < ?2", cat.bodyWeight.multiply(10.0).lt(10.0));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -47,8 +47,6 @@ public class SQLSerializer extends SerializerBase<SQLSerializer> {
|
||||
|
||||
protected final LinkedList<Path<?>> constantPaths = new LinkedList<Path<?>>();
|
||||
|
||||
protected final List<Object> constants = new ArrayList<Object>();
|
||||
|
||||
protected final Set<Path<?>> withAliases = new HashSet<>();
|
||||
|
||||
protected final boolean dml;
|
||||
@ -105,10 +103,6 @@ public class SQLSerializer extends SerializerBase<SQLSerializer> {
|
||||
append(templates.quoteIdentifier(table, precededByDot));
|
||||
}
|
||||
|
||||
public List<Object> getConstants() {
|
||||
return constants;
|
||||
}
|
||||
|
||||
public List<Path<?>> getConstantPaths() {
|
||||
return constantPaths;
|
||||
}
|
||||
@ -801,7 +795,7 @@ public class SQLSerializer extends SerializerBase<SQLSerializer> {
|
||||
if (!first) {
|
||||
append(COMMA);
|
||||
}
|
||||
append("?");
|
||||
serializeConstant(constants.size() + 1, null);
|
||||
constants.add(o);
|
||||
if (first && (constantPaths.size() < constants.size())) {
|
||||
constantPaths.add(null);
|
||||
@ -823,7 +817,7 @@ public class SQLSerializer extends SerializerBase<SQLSerializer> {
|
||||
Expression type = Expressions.constant(typeName);
|
||||
super.visitOperation(constant.getClass(), SQLOps.CAST, Arrays.<Expression<?>> asList(Q, type));
|
||||
} else {
|
||||
append("?");
|
||||
serializeConstant(constants.size() + 1, null);
|
||||
}
|
||||
constants.add(constant);
|
||||
if (constantPaths.size() < constants.size()) {
|
||||
@ -834,14 +828,19 @@ public class SQLSerializer extends SerializerBase<SQLSerializer> {
|
||||
|
||||
@Override
|
||||
public Void visit(ParamExpression<?> param, Void context) {
|
||||
append("?");
|
||||
constants.add(param);
|
||||
serializeConstant(constants.size(), null);
|
||||
if (constantPaths.size() < constants.size()) {
|
||||
constantPaths.add(null);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void serializeConstant(int parameterIndex, String constantLabel) {
|
||||
append("?");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visit(Path<?> path, Void context) {
|
||||
if (dml) {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user