All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ebeaninternal.api.BindParams Maven / Gradle / Ivy

There is a newer version: 15.8.0
Show newest version
package io.ebeaninternal.api;

import io.ebeaninternal.server.persist.MultiValueWrapper;
import io.ebeaninternal.server.querydefn.NaturalKeyBindParam;

import java.io.Serializable;
import java.util.*;
import java.util.Map.Entry;

/**
 * Parameters used for binding to a statement.
 * 

* Supports ordered or named parameters. *

*/ public final class BindParams implements Serializable { private static final long serialVersionUID = 4541081933302086285L; private final List positionedParameters = new ArrayList<>(); private final Map namedParameters = new LinkedHashMap<>(); /** * This is the sql. For named parameters this is the sql after the named * parameters have been replaced with question mark place holders and the * parameters have been ordered by addNamedParamInOrder(). */ private String preparedSql; /** * Bind hash and count used to detect when the bind values have changed such * that the generated SQL (with named parameters) needs to be recalculated. */ private String bindHash; /** * Helper to add positioned parameters in order. */ private int addPos; /** * Reset positioned parameters (usually due to bind parameter expansion). */ public void reset() { bindHash = null; positionedParameters.clear(); } public void queryBindHash(BindValuesKey key) { key.add(positionedParameters.size()); for (Param param : positionedParameters) { param.queryBindHash(key); } } /** * Return the hash that should be included with the query plan. *

* This is to handle binding collections to in clauses. The number of values * in the collection effects the query (number of bind values) and so must be * taken into account when calculating the query hash. *

*/ public String calcQueryPlanHash() { StringBuilder builder = new StringBuilder(); buildQueryPlanHash(builder); return builder.toString(); } /** * Calculate and return a query plan bind hash with total bind count. */ public void buildQueryPlanHash(StringBuilder builder) { int tempBindCount; int bc = 0; for (Param param : positionedParameters) { tempBindCount = param.queryBindCount(); bc += tempBindCount; builder.append('p').append(bc).append(" ?:").append(tempBindCount).append(','); } for (Map.Entry entry : namedParameters.entrySet()) { tempBindCount = entry.getValue().queryBindCount(); bc += tempBindCount; builder.append('n').append(bc).append(" k:").append(entry.getKey()).append(" ?:").append(tempBindCount).append(','); } } /** * Return a deep copy of the BindParams. */ public BindParams copy() { BindParams copy = new BindParams(); for (Param p : positionedParameters) { copy.positionedParameters.add(p.copy()); } for (Entry entry : namedParameters.entrySet()) { copy.namedParameters.put(entry.getKey(), entry.getValue().copy()); } return copy; } /** * Return true if there are no bind parameters. */ public boolean isEmpty() { return positionedParameters.isEmpty() && namedParameters.isEmpty(); } /** * Return a Natural Key bind param if supported. */ public NaturalKeyBindParam naturalKeyBindParam() { if (!positionedParameters.isEmpty()) { return null; } if (namedParameters.size() == 1) { Entry e = namedParameters.entrySet().iterator().next(); return new NaturalKeyBindParam(e.getKey(), e.getValue().inValue()); } return null; } public int size() { return positionedParameters.size(); } /** * Return true if named parameters are being used and they have not yet been * ordered. The sql needs to be prepared (named replaced with ?) and the * parameters ordered. */ public boolean requiresNamedParamsPrepare() { return !namedParameters.isEmpty(); } /** * Set a null parameter using position. */ public void setNullParameter(int position, int jdbcType) { Param p = parameter(position); p.setInNullType(jdbcType); } /** * Set an In Out parameter using position. */ public void setParameter(int position, Object value, int outType) { Param p = parameter(position); p.setInValue(value); p.setOutType(outType); } public void setNextParameters(Object... values) { for (Object value : values) { setNextParameter(value); } } /** * Bind the next positioned parameter. */ public void setNextParameter(Object value) { setParameter(++addPos, value); } /** * Using position set the In value of a parameter. Note that for nulls you * must use setNullParameter. */ @SuppressWarnings("rawtypes") public void setParameter(int position, Object value) { //TODO: Review - assert value != null : "use setNullParameter"; Param p = parameter(position); if (value instanceof Collection) { // use of postgres ANY with positioned parameter value = new MultiValueWrapper((Collection)value); } p.setInValue(value); } /** * Register the parameter as an Out parameter using position. */ public void registerOut(int position, int outType) { Param p = parameter(position); p.setOutType(outType); } /** * Return the named parameter. */ public Param parameter(String name) { return namedParameters.computeIfAbsent(name, k -> new Param()); } /** * Return the Parameter for a given position. */ public Param parameter(int position) { int more = position - positionedParameters.size(); if (more > 0) { for (int i = 0; i < more; i++) { positionedParameters.add(new Param()); } } return positionedParameters.get(position - 1); } /** * Set a named In Out parameter. */ public void setParameter(String name, Object value, int outType) { Param p = parameter(name); p.setInValue(value); p.setOutType(outType); } /** * Set a named In parameter that is null. */ public void setNullParameter(String name, int jdbcType) { Param p = parameter(name); p.setInNullType(jdbcType); } /** * Set a named In parameter that is not null. */ public Param setParameter(String name, Object value) { // TODO: Review - assert value != null : "use setNullParameter"; Param p = parameter(name); p.setInValue(value); return p; } /** * Set a named In parameter that is multi-valued. */ public void setArrayParameter(int position, Collection value) { Param p = parameter(position); p.setInValue(new MultiValueWrapper(value)); } /** * Set a named In parameter that is multi-valued. */ public void setArrayParameter(String name, Collection value) { Param p = parameter(name); p.setInValue(new MultiValueWrapper(value)); } /** * Set an encryption key as a bind value. *

* Needs special treatment as the value should not be included in a log. *

*/ public Param setEncryptionKey(String name, Object value) { Param p = parameter(name); p.setEncryptionKey(value); return p; } /** * Register the named parameter as an Out parameter. */ public void registerOut(String name, int outType) { Param p = parameter(name); p.setOutType(outType); } /** * Return the values of ordered parameters. */ public List positionedParameters() { return positionedParameters; } /** * Set the sql with named parameters replaced with place holder ?. */ public void setPreparedSql(String preparedSql) { this.preparedSql = preparedSql; } /** * Return the sql with ? place holders (named parameters have been processed * and ordered). */ public String preparedSql() { return preparedSql; } /** * Return true if the bind hash and count has not changed. */ public boolean isSameBindHash() { if (bindHash == null) { return false; } String newHash = calcQueryPlanHash(); return bindHash.equals(newHash); } /** * Updates the hash. */ public void updateHash() { bindHash = calcQueryPlanHash(); } /** * Create a new positioned parameters orderedList. */ public OrderedList createOrderedList() { positionedParameters.clear(); return new OrderedList(positionedParameters); } /** * The bind parameters in the correct binding order. *

* This is the result of converting sql with named parameters * into sql with ? and ordered parameters. *

*/ public static final class OrderedList { private final List paramList; private final StringBuilder preparedSql; public OrderedList(List paramList) { this.paramList = paramList; this.preparedSql = new StringBuilder(); } /** * Add a parameter in the correct binding order. */ public void add(Param param) { paramList.add(param); } /** * Return the number of bind parameters in this list. */ public int size() { return paramList.size(); } /** * Returns the ordered list of bind parameters. */ public List list() { return paramList; } /** * Append parsedSql that has named parameters converted into ?. */ public void appendSql(String parsedSql) { preparedSql.append(parsedSql); } public String getPreparedSql() { return preparedSql.toString(); } } /** * A In Out capable parameter for the CallableStatement. */ public static final class Param implements Serializable { private static final long serialVersionUID = 1L; private boolean encryptionKey; private boolean isInParam; private boolean isOutParam; private int type; private Object inValue; private Object outValue; /** * Construct a Parameter. */ public Param() { } public int queryBindCount() { if (inValue == null) { return 0; } if (inValue instanceof Collection) { return ((Collection) inValue).size(); } return 1; } /** * Create a deep copy of the Param. */ public Param copy() { Param copy = new Param(); copy.isInParam = isInParam; copy.isOutParam = isOutParam; copy.type = type; copy.inValue = inValue; copy.outValue = outValue; return copy; } @Override public int hashCode() { int hc = getClass().hashCode(); hc = hc * 92821 + (isInParam ? 0 : 1); hc = hc * 92821 + (isOutParam ? 0 : 1); hc = hc * 92821 + (type); hc = hc * 92821 + (inValue == null ? 0 : inValue.hashCode()); return hc; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Param param = (Param) o; return isInParam == param.isInParam && isOutParam == param.isOutParam && type == param.type && Objects.equals(inValue, param.inValue); } void queryBindHash(BindValuesKey key) { key.add(isInParam).add(isOutParam).add(type).add(inValue); } /** * Return true if this is an In parameter that needs to be bound before * execution. */ public boolean isInParam() { return isInParam; } /** * Return true if this is an out parameter that needs to be registered * before execution. */ public boolean isOutParam() { return isOutParam; } /** * Return the jdbc type of this parameter. Used for registering Out * parameters and setting NULL In parameters. */ public int type() { return type; } /** * Set the Out parameter type. */ public void setOutType(int type) { this.type = type; this.isOutParam = true; } /** * Set the In value. */ public void setInValue(Object in) { this.inValue = in; this.isInParam = true; } /** * Set an encryption key (which can not be logged). */ public void setEncryptionKey(Object in) { this.inValue = in; this.isInParam = true; this.encryptionKey = true; } /** * Specify that the In parameter is NULL and the specific type that it * is. */ public void setInNullType(int type) { this.type = type; this.inValue = null; this.isInParam = true; } /** * Return the OUT value that was retrieved. This value is set after * CallableStatement was executed. */ public Object outValue() { return outValue; } /** * Return the In value. If this is null, then the type should be used to * specify the type of the null. */ public Object inValue() { return inValue; } /** * Set the OUT value returned by a CallableStatement after it has * executed. */ public void setOutValue(Object out) { this.outValue = out; } /** * If true do not include this value in a transaction log. */ public boolean isEncryptionKey() { return encryptionKey; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy