#1632 - ENH: Add bind parameter expansion for SqlUpdate

This commit is contained in:
rob bygrave
2019-02-07 23:19:00 +13:00
5 changed files with 282 additions and 10 deletions
@@ -41,6 +41,14 @@ public class BindParams implements Serializable {
public BindParams() {
}
/**
* Reset positioned parameters (usually due to bind parameter expansion).
*/
public void reset() {
bindHash = null;
positionedParameters.clear();
}
public int queryBindHash() {
int hc = namedParameters.hashCode();
for (Param positionedParameter : positionedParameters) {
@@ -4,6 +4,11 @@ import io.ebean.SqlUpdate;
public interface SpiSqlUpdate extends SqlUpdate {
/**
* Return the sql taking into account bind parameter expansion.
*/
String getBaseSql();
/**
* Return the Bind parameters.
*/
@@ -9,6 +9,7 @@ import io.ebeaninternal.api.SpiSqlUpdate;
import io.ebeaninternal.api.SpiTransaction;
import java.io.Serializable;
import java.util.Collection;
/**
* A SQL Update Delete or Insert statement that can be executed. For the times
@@ -35,9 +36,14 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
private final BindParams bindParams;
/**
* The sql update or delete statement.
* The original sql update or delete statement.
*/
private final String sql;
private final String origSql;
/**
* The sql taking into account bind parameter expansion.
*/
private String baseSql;
/**
* The actual sql with named parameters converted.
@@ -66,6 +72,8 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
*/
private int addPos;
private int bindExpansion;
private boolean getGeneratedKeys;
private Object generatedKey;
@@ -89,7 +97,8 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
*/
public DefaultSqlUpdate(SpiEbeanServer server, String sql, BindParams bindParams) {
this.server = server;
this.sql = sql;
this.origSql = sql;
this.baseSql = sql;
this.bindParams = bindParams;
}
@@ -221,11 +230,21 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
@Override
public void setGeneratedSql(String generatedSql) {
this.generatedSql = generatedSql;
this.baseSql = origSql;
if (bindExpansion > 0) {
bindParams.reset();
bindExpansion = 0;
}
}
@Override
public String getSql() {
return sql;
return origSql;
}
@Override
public String getBaseSql() {
return baseSql;
}
@Override
@@ -253,21 +272,47 @@ public final class DefaultSqlUpdate implements Serializable, SpiSqlUpdate {
return this;
}
private SqlUpdate setParamWithBindExpansion(int position, Collection values, String bindLiteral) {
StringBuilder sqlExpand = new StringBuilder(values.size() * 2);
position = position + bindExpansion;
int offset = 0;
for (Object val : values) {
if (offset > 0) {
sqlExpand.append(",");
}
sqlExpand.append("?");
bindParams.setParameter(position + offset++, val);
}
bindExpansion += (offset - 1);
baseSql = baseSql.replace(bindLiteral, sqlExpand.toString());
return this;
}
@Override
public SqlUpdate setParameter(int position, Object value) {
bindParams.setParameter(position, value);
if (value instanceof Collection) {
String bindLiteral = "?" + position;
int pos = baseSql.indexOf(bindLiteral);
if (pos > -1) {
return setParamWithBindExpansion(position, (Collection) value, bindLiteral);
}
}
bindParams.setParameter(bindExpansion + position, value);
return this;
}
@Override
public SqlUpdate setNull(int position, int jdbcType) {
bindParams.setNullParameter(position, jdbcType);
bindParams.setNullParameter(bindExpansion + position, jdbcType);
return this;
}
@Override
public SqlUpdate setNullParameter(int position, int jdbcType) {
bindParams.setNullParameter(position, jdbcType);
bindParams.setNullParameter(bindExpansion + position, jdbcType);
return this;
}
@@ -87,13 +87,11 @@ class ExeUpdateSql {
SpiSqlUpdate updateSql = request.getUpdateSql();
SpiTransaction t = request.getTransaction();
String sql = updateSql.getSql();
BindParams bindParams = updateSql.getBindParams();
// process named parameters if required
String sql = updateSql.getBaseSql();
sql = BindParamsParser.parse(bindParams, sql);
updateSql.setGeneratedSql(sql);
PreparedStatement pstmt;
if (batchThisRequest) {
@@ -112,6 +110,7 @@ class ExeUpdateSql {
}
request.setBindLog(bindLog);
updateSql.setGeneratedSql(sql);
// derive the statement type (for TransactionEvent)
parseUpdate(sql, request);