mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-10-23 21:15:52 +00:00
#1632 - ENH: Add bind parameter expansion for SqlUpdate
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package org.tests.update;
|
||||
|
||||
import io.ebean.BaseTestCase;
|
||||
import io.ebean.DB;
|
||||
import io.ebean.Ebean;
|
||||
import io.ebean.SqlUpdate;
|
||||
import io.ebean.Transaction;
|
||||
import org.ebeantest.LoggedSqlCollector;
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -34,6 +36,219 @@ public class TestSqlUpdateBindMultipleLists extends BaseTestCase {
|
||||
assertThat(sql).hasSize(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positionParamsExpansion() {
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate("delete from o_customer where id in (?1)");
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9991, 9992, 9993));
|
||||
sqlUpdate.execute();
|
||||
|
||||
assertEquals("delete from o_customer where id in (?,?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate = Ebean.createSqlUpdate("delete from o_customer where id in (?1)");
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9991, 9993));
|
||||
sqlUpdate.execute();
|
||||
|
||||
assertEquals("delete from o_customer where id in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate = Ebean.createSqlUpdate("delete from o_customer where id in (?1)");
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9993));
|
||||
sqlUpdate.execute();
|
||||
|
||||
assertEquals("delete from o_customer where id in (?)", sqlUpdate.getGeneratedSql());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positionParamsExpansion_withPrePost() {
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate("delete from o_customer where id > ? and id in (?2) and id < ?");
|
||||
|
||||
sqlUpdate.setParameter(1, 90);
|
||||
sqlUpdate.setParameter(2, asList(9991, 9992, 9993));
|
||||
sqlUpdate.setParameter(3, 91);
|
||||
sqlUpdate.execute();
|
||||
|
||||
assertEquals("delete from o_customer where id > ? and id in (?,?,?) and id < ?", sqlUpdate.getGeneratedSql());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positionParamsExpansion_withPrePost_usingParam() {
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate("delete from o_customer where id > ? and id in (?2) and id < ?");
|
||||
sqlUpdate.setParams(90, asList(9991, 9992, 9993), 91);
|
||||
sqlUpdate.execute();
|
||||
|
||||
assertEquals("delete from o_customer where id > ? and id in (?,?,?) and id < ?", sqlUpdate.getGeneratedSql());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positionParamsExpansion_withPre() {
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate("delete from o_customer where name = ? and id in (?2)");
|
||||
|
||||
sqlUpdate.setParameter(1, "Foo");
|
||||
sqlUpdate.setParameter(2, asList(9991, 9992, 9993));
|
||||
sqlUpdate.execute();
|
||||
|
||||
assertEquals("delete from o_customer where name = ? and id in (?,?,?)", sqlUpdate.getGeneratedSql());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positionParamsExpansion_multi() {
|
||||
|
||||
SqlUpdate upd = DB.sqlUpdate("delete from o_customer where id in (?1) and name in (?2) and id not in (?3)");
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
upd.setParams(asList(9991), asList("Foo"), asList("Bar"));
|
||||
upd.execute();
|
||||
|
||||
upd.setParams(asList(9991, 9992), asList("Foo", "Bar"), asList(1,2,3,4));
|
||||
upd.execute();
|
||||
|
||||
upd.setParams(asList(9991), asList("Foo", "Bar", "Baz"), asList(1,2));
|
||||
upd.execute();
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positionParamsExpansion_withPost() {
|
||||
|
||||
SqlUpdate sqlUpdate = Ebean.createSqlUpdate("delete from o_customer where id in (?1) and name = ?");
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9991, 9992, 9993));
|
||||
sqlUpdate.setParameter(2, "Foo");
|
||||
sqlUpdate.execute();
|
||||
|
||||
assertEquals("delete from o_customer where id in (?,?,?) and name = ?", sqlUpdate.getGeneratedSql());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positionParamsExpansion_withPost_andBatch_execute() {
|
||||
|
||||
SqlUpdate upd = DB.sqlUpdate("delete from o_customer where id in (?1) and name = ?");
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
upd.setParams(asList(9991, 9992, 9993), "Foo");
|
||||
upd.execute();
|
||||
|
||||
upd.setParams(asList(9991, 9992), "Bar");
|
||||
upd.execute();
|
||||
|
||||
upd.setParams(asList(9991, 9992, 9999), "Baz");
|
||||
upd.execute();
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void positionParamsExpansion_withPost_addBatch_execute() {
|
||||
|
||||
SqlUpdate upd = DB.sqlUpdate("delete from o_customer where id in (?1) and name = ?");
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
upd.setParams(asList(9991, 9992, 9993), "Foo");
|
||||
upd.addBatch();
|
||||
|
||||
upd.setParams(asList(9991, 9992), "Bar");
|
||||
upd.addBatch();
|
||||
|
||||
upd.setParams(asList(9991, 9992, 9999), "Baz");
|
||||
upd.addBatch();
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_multipleLists_asPositioned() {
|
||||
|
||||
SqlUpdate sqlUpdate = DB.sqlUpdate("delete from o_customer where id in (?1) and name in (?2)");
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9991, 9992, 9993));
|
||||
sqlUpdate.setParameter(2, asList("rob", "jim"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?,?,?) and name in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate.setParams(asList(9991, 9992), asList("rob", "jim", "sd"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?,?) and name in (?,?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9991, 9992));
|
||||
sqlUpdate.setParameter(2, asList("rob", "jim"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?,?) and name in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate.setParams(asList(9991), asList("rob", "jim"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?) and name in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
|
||||
sqlUpdate.setParams(asList(9992), asList("ro3b", "j3im"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?) and name in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9992, 4545));
|
||||
sqlUpdate.setParameter(2, asList("ro3b"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?,?) and name in (?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_multipleLists_asPositioned_withBatch() {
|
||||
|
||||
SqlUpdate sqlUpdate = DB.sqlUpdate("delete from o_customer where id in (?1) and name in (?2)");
|
||||
|
||||
try (Transaction transaction = DB.beginTransaction()) {
|
||||
transaction.setBatchMode(true);
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9991, 9992, 9993));
|
||||
sqlUpdate.setParameter(2, asList("rob", "jim"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?,?,?) and name in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate.setParams(asList(9991, 9992), asList("rob", "jim", "sd"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?,?) and name in (?,?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9991, 9992));
|
||||
sqlUpdate.setParameter(2, asList("rob", "jim"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?,?) and name in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate.setParams(asList(9991), asList("rob", "jim"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?) and name in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
|
||||
sqlUpdate.setParams(asList(9992), asList("ro3b", "j3im"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?) and name in (?,?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
sqlUpdate.setParameter(1, asList(9992, 4545));
|
||||
sqlUpdate.setParameter(2, asList("ro3b"));
|
||||
sqlUpdate.execute();
|
||||
assertEquals("delete from o_customer where id in (?,?) and name in (?)", sqlUpdate.getGeneratedSql());
|
||||
|
||||
transaction.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_multipleLists() {
|
||||
|
||||
Reference in New Issue
Block a user