Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of String arrays in queries/insert/updates #51

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ target
.project
.classpath
.settings
.idea
*.iml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Subscriber;
import rx.Subscription;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;

Expand Down Expand Up @@ -107,7 +108,10 @@ private void connectAndPrepareStatement(Subscriber<? super T> subscriber, State
state.ps = state.con.prepareStatement(query.sql(), ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_READ_ONLY);
log.debug("setting parameters");
Util.setParameters(state.ps, parameters, query.names());
List<Subscription> subscriptions = Util.setParameters(state.ps, parameters, query.names());
for (Subscription subscription : subscriptions) {
subscriber.add(subscription);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,10 @@ private void performUpdate(final Subscriber<? super T> subscriber, State state)
keysOption = Statement.NO_GENERATED_KEYS;
}
state.ps = state.con.prepareStatement(query.sql(), keysOption);
Util.setParameters(state.ps, parameters, query.names());
List<Subscription> subscriptions = Util.setParameters(state.ps, parameters, query.names());
for (Subscription subscription : subscriptions) {
subscriber.add(subscription);
}

if (subscriber.isUnsubscribed())
return;
Expand Down
69 changes: 62 additions & 7 deletions src/main/java/com/github/davidmoten/rx/jdbc/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
Expand All @@ -33,10 +34,13 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import rx.Subscription;
import rx.functions.Action0;
import rx.functions.Func1;

import com.github.davidmoten.rx.jdbc.QuerySelect.Builder;
import com.github.davidmoten.rx.jdbc.exceptions.SQLRuntimeException;
import rx.subscriptions.Subscriptions;

/**
* Utility methods.
Expand Down Expand Up @@ -751,8 +755,9 @@ public int read(char[] cbuf, int off, int len) throws IOException {
* @param params
* @throws SQLException
*/
static void setParameters(PreparedStatement ps, List<Parameter> params, boolean namesAllowed)
static List<Subscription> setParameters(PreparedStatement ps, List<Parameter> params, boolean namesAllowed)
throws SQLException {
final List<Subscription> subscriptions = new ArrayList<>();
for (int i = 1; i <= params.size(); i++) {
if (params.get(i - 1).hasName() && !namesAllowed)
throw new SQLException("named parameter found but sql does not contain names");
Expand Down Expand Up @@ -787,16 +792,49 @@ else if (o == Database.NULL_BLOB)
Calendar cal = Calendar.getInstance();
java.util.Date date = (java.util.Date) o;
ps.setTimestamp(i, new java.sql.Timestamp(date.getTime()), cal);
} else if (cls.isArray() && !cls.getComponentType().isPrimitive()) {
Subscription subscription = configureArray(ps, i, (Object[]) o);
if (subscription != null) {
subscriptions.add(subscription);
}
} else
ps.setObject(i, o);
}
} catch (SQLException e) {
log.debug("{} when setting ps.setObject({},{})", e.getMessage(), i, o);
for (Subscription subscription : subscriptions) {
subscription.unsubscribe();
}
throw e;
}
}

return subscriptions;
}

private static Subscription configureArray(PreparedStatement ps, int i, Object[] o) throws SQLException {
if (String[].class.isAssignableFrom(o.getClass()) && !getDatabaseProductName(ps).equals("H2")) {
final Array array = ps.getConnection().createArrayOf("varchar", o);
Subscription subscription = Subscriptions.create(new ArrayFreeAction(array));

try {
ps.setArray(i, array);
} catch (SQLException e) {
array.free();
throw e;
}

return subscription;
} else {
ps.setObject(i, o);
return null;
}
}

private static String getDatabaseProductName(PreparedStatement ps) throws SQLException {
return ps.getConnection().getMetaData().getDatabaseProductName();
}

/**
* Sets a blob parameter for the prepared statement.
*
Expand Down Expand Up @@ -905,8 +943,8 @@ static ResultSetMapper<Integer> toOne() {
return ResultSetMapperToOne.INSTANCE;
}

public static void setNamedParameters(PreparedStatement ps, List<Parameter> parameters,
List<String> names) throws SQLException {
public static List<Subscription> setNamedParameters(PreparedStatement ps, List<Parameter> parameters,
List<String> names) throws SQLException {
Map<String, Parameter> map = new HashMap<String, Parameter>();
for (Parameter p : parameters) {
if (p.hasName()) {
Expand All @@ -924,15 +962,32 @@ public static void setNamedParameters(PreparedStatement ps, List<Parameter> para
Parameter p = map.get(name);
list.add(p);
}
Util.setParameters(ps, list, true);
return Util.setParameters(ps, list, true);
}

static void setParameters(PreparedStatement ps, List<Parameter> parameters, List<String> names)
static List<Subscription> setParameters(PreparedStatement ps, List<Parameter> parameters, List<String> names)
throws SQLException {
if (names.isEmpty()) {
Util.setParameters(ps, parameters, false);
return Util.setParameters(ps, parameters, false);
} else {
Util.setNamedParameters(ps, parameters, names);
return Util.setNamedParameters(ps, parameters, names);
}
}

private static class ArrayFreeAction implements Action0 {
private final Array array;

public ArrayFreeAction(Array array) {
this.array = array;
}

@Override
public void call() {
try {
array.free();
} catch (Exception e) {
// ignore
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ public static void createDatabase(Connection c) {
c.prepareStatement(
"create table note(id bigint auto_increment primary key, text varchar(255))")
.execute();

c.prepareStatement(
"create table person_lines (name varchar(50) not null, lines array)")
.execute();
} catch (SQLException e) {
throw new SQLRuntimeException(e);
}
Expand Down
10 changes: 10 additions & 0 deletions src/test/java/com/github/davidmoten/rx/jdbc/DatabaseTestBase.java
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,16 @@ public void testCalendarParameter() throws SQLException {
assertEquals(0, t.getTime());
}

@Test
public void testStringArray() throws Exception {
Database db = db();
String[] lines = new String[] {"123 Main St.", "Nowhere, USA"};

int actual = db.update("INSERT INTO person_lines (name, lines) VALUES (?, ?)")
.parameters("fred", lines).count().first().toBlocking().single();
assertEquals(1, actual);
}

@Test
public void testDatabaseBuilder() {
Database.builder().connectionProvider(connectionProvider())
Expand Down