Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

[#2364] Multi-Result queries may mix ResultSets with update counts.

  • Loading branch information...
commit 610f4d3c6b60c840069da64594dfcbe00cabc0d0 1 parent 958e525
@lukaseder lukaseder authored
View
66 jOOQ/src/main/java/org/jooq/ResultOrRows.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (c) 2009-2015, Data Geekery GmbH (http://www.datageekery.com)
+ * All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Other licenses:
+ * -----------------------------------------------------------------------------
+ * Commercial licenses for this work are available. These replace the above
+ * ASL 2.0 and offer limited warranties, support, maintenance, and commercial
+ * database integrations.
+ *
+ * For more information, please visit: http://www.jooq.org/licenses
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ *
+ */
+package org.jooq;
+
+import java.sql.Statement;
+
+/**
+ * A type that contains either a {@link Result} or an update count.
+ *
+ * @author Lukas Eder
+ */
+public interface ResultOrRows {
+
+ /**
+ * The result or <code>null</code> if there was no result.
+ *
+ * @see Statement#getResultSet()
+ */
+ Result<Record> result();
+
+ /**
+ * The update count if applicable, or the number of rows in
+ * {@link #result()}.
+ *
+ * @see Statement#getUpdateCount()
+ */
+ int rows();
+}
View
30 jOOQ/src/main/java/org/jooq/Results.java
@@ -46,13 +46,41 @@
* A list of {@link Result} and update counts that can be returned by
* {@link ResultQuery#fetchMany()} calls and other calls that produce multiple
* cursors and update counts.
+ * <p>
+ * For backwards-compatibility (e.g. with {@link ResultQuery#fetchMany()}), this
+ * type extends {@link List} containing only the {@link Result}, not the rows /
+ * update counts of interleaved updates. In order to get both, call
+ * {@link #resultsOrRows()}.
*
* @author Lukas Eder
*/
public interface Results extends List<Result<Record>>, Attachable {
// ------------------------------------------------------------------------
- // Specialisations of Attachable methods
+ // XXX: Additional, Results-specific methods
+ // ------------------------------------------------------------------------
+
+ /**
+ * All the results or update counts in their order as fetched via JDBC.
+ * <p>
+ * While {@link #iterator()} and all the other methods inherited from the
+ * {@link List} API return the {@link Result} objects only, this method also
+ * includes update counts that may have occurred between two results.
+ * <p>
+ * It can be safely assumed that:
+ * <code><pre>
+ * result.resultsOrRows()
+ * .stream()
+ * .filter(r -> r.result() != null)
+ * .map(r -> r.result())
+ * .collect(Collectors.toList())
+ * .equals(result);
+ * </pre></code>
+ */
+ List<ResultOrRows> resultsOrRows();
+
+ // ------------------------------------------------------------------------
+ // XXX: Specialisations of Attachable methods
// ------------------------------------------------------------------------
/**
View
2  jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java
@@ -104,7 +104,7 @@
private transient boolean many;
private transient Cursor<R> cursor;
private Result<R> result;
- private Results results;
+ private ResultsImpl results;
// Some temp variables for String interning
private final Intern intern = new Intern();
View
2  jOOQ/src/main/java/org/jooq/impl/AbstractRoutine.java
@@ -119,7 +119,7 @@
private final List<Parameter<?>> outParameters;
private final DataType<T> type;
private Parameter<T> returnParameter;
- private Results results;
+ private ResultsImpl results;
private boolean overloaded;
private boolean hasDefaultedParameters;
View
185 jOOQ/src/main/java/org/jooq/impl/ResultsImpl.java
@@ -40,34 +40,42 @@
*/
package org.jooq.impl;
+import java.util.AbstractList;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Iterator;
import java.util.List;
-import java.util.ListIterator;
import org.jooq.AttachableInternal;
import org.jooq.Configuration;
import org.jooq.Record;
import org.jooq.Result;
+import org.jooq.ResultOrRows;
import org.jooq.Results;
/**
* @author Lukas Eder
*/
-class ResultsImpl implements Results, AttachableInternal {
+class ResultsImpl extends AbstractList<Result<Record>> implements Results, AttachableInternal {
/**
* Generated UID
*/
- private static final long serialVersionUID = 1744826140354980500L;
+ private static final long serialVersionUID = 1744826140354980500L;
- private Configuration configuration;
- private final List<Result<Record>> results;
+ private Configuration configuration;
+ private final List<ResultOrRows> results;
ResultsImpl(Configuration configuration) {
this.configuration = configuration;
- this.results = new ArrayList<Result<Record>>();
+ this.results = new ArrayList<ResultOrRows>();
+ }
+
+ // ------------------------------------------------------------------------
+ // XXX: Additional, Results-specific methods
+ // ------------------------------------------------------------------------
+
+ @Override
+ public final List<ResultOrRows> resultsOrRows() {
+ return results;
}
// -------------------------------------------------------------------------
@@ -78,7 +86,7 @@
public final void attach(Configuration c) {
this.configuration = c;
- for (Result<?> result : results)
+ for (Result<?> result : this)
if (result != null)
result.attach(c);
}
@@ -100,11 +108,13 @@ public final Configuration configuration() {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
-
String separator = "";
- for (Result<?> result : this) {
- sb.append(separator)
- .append(result);
+
+ for (ResultOrRows result : results) {
+ if (result.result() == null)
+ sb.append(separator).append("Update count: ").append(result.rows());
+ else
+ sb.append(separator).append("Result set:\n").append(result.result());
separator = "\n";
}
@@ -137,116 +147,103 @@ public boolean equals(Object obj) {
@Override
public final int size() {
- return results.size();
- }
-
- @Override
- public final boolean isEmpty() {
- return results.isEmpty();
- }
-
- @Override
- public final boolean contains(Object o) {
- return results.contains(o);
- }
-
- @Override
- public final Iterator<Result<Record>> iterator() {
- return results.iterator();
+ return list().size();
}
@Override
- public final Object[] toArray() {
- return results.toArray();
+ public final Result<Record> get(int index) {
+ return list().get(index);
}
@Override
- public final <T> T[] toArray(T[] a) {
- return results.toArray(a);
+ public Result<Record> set(int index, Result<Record> element) {
+ return results.set(translatedIndex(index), new ResultOrRowsImpl(element)).result();
}
@Override
- public final boolean add(Result<Record> e) {
- return results.add(e);
+ public void add(int index, Result<Record> element) {
+ results.add(translatedIndex(index), new ResultOrRowsImpl(element));
}
@Override
- public final boolean remove(Object o) {
- return results.remove(o);
+ public Result<Record> remove(int index) {
+ return results.remove(translatedIndex(index)).result();
}
- @Override
- public final boolean containsAll(Collection<?> c) {
- return results.containsAll(c);
- }
+ private final List<Result<Record>> list() {
+ List<Result<Record>> list = new ArrayList<Result<Record>>();
- @Override
- public final boolean addAll(Collection<? extends Result<Record>> c) {
- return results.addAll(c);
- }
+ for (ResultOrRows result : results)
+ if (result.result() != null)
+ list.add(result.result());
- @Override
- public final boolean addAll(int index, Collection<? extends Result<Record>> c) {
- return results.addAll(index, c);
+ return list;
}
- @Override
- public final boolean removeAll(Collection<?> c) {
- return results.removeAll(c);
- }
+ private final int translatedIndex(int index) {
+ int translated = 0;
- @Override
- public final boolean retainAll(Collection<?> c) {
- return results.retainAll(c);
- }
+ for (int i = 0; i < index; i++)
+ while (results.get(translated++).result() == null);
- @Override
- public final void clear() {
- results.clear();
+ return translated;
}
- @Override
- public final Result<Record> get(int index) {
- return results.get(index);
- }
+ static final class ResultOrRowsImpl implements ResultOrRows {
- @Override
- public final Result<Record> set(int index, Result<Record> element) {
- return results.set(index, element);
- }
+ private final Result<Record> result;
+ private final int rows;
- @Override
- public final void add(int index, Result<Record> element) {
- results.add(index, element);
- }
+ ResultOrRowsImpl(Result<Record> result) {
+ this(result, result != null ? result.size() : 0);
+ }
- @Override
- public final Result<Record> remove(int index) {
- return results.remove(index);
- }
+ ResultOrRowsImpl(int rows) {
+ this(null, rows);
+ }
- @Override
- public final int indexOf(Object o) {
- return results.indexOf(o);
- }
+ private ResultOrRowsImpl(Result<Record> result, int rows) {
+ this.result = result;
+ this.rows = rows;
+ }
- @Override
- public final int lastIndexOf(Object o) {
- return results.lastIndexOf(o);
- }
+ @Override
+ public final Result<Record> result() {
+ return result;
+ }
- @Override
- public final ListIterator<Result<Record>> listIterator() {
- return results.listIterator();
- }
+ @Override
+ public final int rows() {
+ return rows;
+ }
- @Override
- public final ListIterator<Result<Record>> listIterator(int index) {
- return results.listIterator(index);
- }
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int r = 1;
+ r = prime * r + ((this.result == null) ? 0 : this.result.hashCode());
+ r = prime * r + rows;
+ return r;
+ }
- @Override
- public final List<Result<Record>> subList(int fromIndex, int toIndex) {
- return results.subList(fromIndex, toIndex);
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ ResultOrRowsImpl other = (ResultOrRowsImpl) obj;
+ if (result == null) {
+ if (other.result != null)
+ return false;
+ }
+ else if (!result.equals(other.result))
+ return false;
+ if (rows != other.rows)
+ return false;
+ return true;
+ }
}
}
View
11 jOOQ/src/main/java/org/jooq/impl/Utils.java
@@ -2523,6 +2523,7 @@ static final void consumeWarnings(ExecuteContext ctx, ExecuteListener listener)
static void consumeResultSets(ExecuteContext ctx, ExecuteListener listener, Results results, Intern intern) throws SQLException {
boolean anyResults = false;
int i = 0;
+ int rows = (ctx.resultSet() == null) ? ctx.statement().getUpdateCount() : 0;
for (i = 0; i < maxConsumedResults; i++) {
if (ctx.resultSet() != null) {
@@ -2530,12 +2531,18 @@ static void consumeResultSets(ExecuteContext ctx, ExecuteListener listener, Resu
Field<?>[] fields = new MetaDataFieldProvider(ctx.configuration(), ctx.resultSet().getMetaData()).getFields();
Cursor<Record> c = new CursorImpl<Record>(ctx, listener, fields, intern != null ? intern.internIndexes(fields) : null, true, false);
- results.add(c.fetch());
+ results.resultsOrRows().add(new ResultsImpl.ResultOrRowsImpl(c.fetch()));
+ }
+ else {
+ if (rows != -1)
+ results.resultsOrRows().add(new ResultsImpl.ResultOrRowsImpl(rows));
+ else
+ break;
}
if (ctx.statement().getMoreResults())
ctx.resultSet(ctx.statement().getResultSet());
- else if (ctx.statement().getUpdateCount() != -1)
+ else if ((rows = ctx.statement().getUpdateCount()) != -1)
ctx.resultSet(null);
else
break;
Please sign in to comment.
Something went wrong with that request. Please try again.