io.ebeaninternal.server.persist.Binder Maven / Gradle / Ivy
package io.ebeaninternal.server.persist;
import io.ebean.config.dbplatform.DbPlatformType;
import io.ebean.core.type.DataReader;
import io.ebean.core.type.PostgresHelper;
import io.ebean.core.type.ScalarType;
import io.ebeaninternal.api.BindParams;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.api.SpiLogManager;
import io.ebeaninternal.server.core.timezone.DataTimeZone;
import io.ebeaninternal.server.bind.DataBind;
import io.ebeaninternal.server.expression.platform.DbExpressionHandler;
import io.ebeaninternal.server.persist.platform.MultiValueBind;
import io.ebeaninternal.server.type.*;
import javax.persistence.PersistenceException;
import java.math.BigDecimal;
import java.sql.*;
import java.util.Collection;
import java.util.List;
import static java.lang.System.Logger.Level.WARNING;
/**
* Binds bean values to a PreparedStatement.
*/
public final class Binder {
private final TypeManager typeManager;
private final int asOfBindCount;
private final boolean asOfStandardsBased;
private final DbExpressionHandler dbExpressionHandler;
private final DataTimeZone dataTimeZone;
private final MultiValueBind multiValueBind;
private final boolean enableBindLog;
private final GeoTypeBinder geoTypeBinder;
public Binder(TypeManager typeManager, SpiLogManager logManager, int asOfBindCount, boolean asOfStandardsBased,
DbExpressionHandler dbExpressionHandler, DataTimeZone dataTimeZone, MultiValueBind multiValueBind) {
this.typeManager = typeManager;
this.geoTypeBinder = typeManager.geoTypeBinder();
this.asOfBindCount = asOfBindCount;
this.asOfStandardsBased = asOfStandardsBased;
this.dbExpressionHandler = dbExpressionHandler;
this.dataTimeZone = dataTimeZone;
this.multiValueBind = multiValueBind;
this.enableBindLog = logManager.enableBindLog();
}
/**
* Return true if bind log is enabled.
*/
public boolean isEnableBindLog() {
return enableBindLog;
}
/**
* Return the bind count per predicate for 'As Of' query predicates.
*/
public int getAsOfBindCount() {
return asOfBindCount;
}
/**
* Return true if the 'as of' history support is SQL2011 standards based.
*/
public boolean isAsOfStandardsBased() {
return asOfStandardsBased;
}
/**
* Bind the parameters to the preparedStatement returning the bind log.
*/
public String bind(BindParams bindParams, PreparedStatement statement, Connection connection) throws SQLException {
return bind(bindParams, new DataBind(dataTimeZone, statement, connection));
}
/**
* Bind the list of positionedParameters in BindParams.
*/
private String bind(BindParams bindParams, DataBind dataBind) throws SQLException {
StringBuilder bindLog = new StringBuilder();
bind(bindParams, dataBind, bindLog);
return bindLog.toString();
}
/**
* Bind the list of positionedParameters in BindParams.
*/
public void bind(BindParams bindParams, DataBind dataBind, StringBuilder bindLog) throws SQLException {
bind(bindParams.positionedParameters(), dataBind, bindLog);
}
/**
* Bind the list of parameters..
*/
private void bind(List list, DataBind dataBind, StringBuilder bindLog) throws SQLException {
CallableStatement cstmt = null;
if (dataBind.getPstmt() instanceof CallableStatement) {
cstmt = (CallableStatement) dataBind.getPstmt();
}
// the iterator is assumed to be in the correct order
Object value = null;
try {
for (BindParams.Param param : list) {
if (param.isOutParam() && cstmt != null) {
cstmt.registerOutParameter(dataBind.nextPos(), param.type());
if (param.isInParam()) {
dataBind.decrementPos();
}
}
if (param.isInParam()) {
value = param.inValue();
if (bindLog != null) {
if (bindLog.length() > 0) {
bindLog.append(", ");
}
if (param.isEncryptionKey()) {
bindLog.append("****");
} else {
String sv = String.valueOf(value);
if (sv.length() > 50) {
sv = sv.substring(0, 47) + "...";
}
bindLog.append(sv);
}
}
if (value instanceof Collection) {
for (Object entry: (Collection>) value) {
bindObject(dataBind, entry);
}
} else if (value == null) {
// this doesn't work for query predicates
bindObject(dataBind, null, param.type());
} else {
bindObject(dataBind, value);
}
}
}
} catch (SQLException ex) {
CoreLog.log.log(WARNING, "error binding parameter [{0}][{1}]", (dataBind.currentPos() - 1), value);
throw ex;
}
}
/**
* Return true if MultiValue binding is supported for the given type.
*/
public boolean isMultiValueSupported(Class> cls) {
try {
ScalarType> scalarType = getScalarType(cls);
return multiValueBind.isTypeSupported(scalarType.jdbcType());
} catch (PersistenceException e) {
return false;
}
}
public ScalarType> getScalarType(Class> clazz) {
ScalarType> type = typeManager.type(clazz);
if (type == null) {
throw new PersistenceException("No ScalarType registered for " + clazz);
}
return type;
}
/**
* Bind an Object with unknown data type.
*/
public void bindObject(DataBind dataBind, Object value) throws SQLException {
if (value == null) {
// null of unknown type
bindObject(dataBind, null, Types.OTHER);
} else if (value instanceof MultiValueWrapper) {
MultiValueWrapper wrapper = (MultiValueWrapper) value;
Collection> values = wrapper.getValues();
ScalarType> type = getScalarType(wrapper.getType());
int dbType = type.jdbcType();
// let the multiValueBind decide what to do with the value
multiValueBind.bindMultiValues(dataBind, values, type, one -> bindObject(dataBind, one, dbType));
} else {
ScalarType> type = getScalarType(value.getClass());
if (!type.jdbcNative()) {
// convert to a JDBC native type
value = type.toJdbcType(value);
}
bindObject(dataBind, value, type.jdbcType());
}
}
/**
* Return the SQL in clause taking into account Multi-value support.
*/
public String getInExpression(boolean not, List
© 2015 - 2024 Weber Informatics LLC | Privacy Policy