Skip to content

Commit

Permalink
[#7430] ResultQuery.fetchOne() should not fetch second record on a LI…
Browse files Browse the repository at this point in the history
…MIT 1 query
  • Loading branch information
lukaseder committed Apr 27, 2018
1 parent 0b917a5 commit c2c125b
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 5 deletions.
14 changes: 12 additions & 2 deletions jOOQ/src/main/java/org/jooq/impl/AbstractResultQuery.java
Expand Up @@ -532,7 +532,7 @@ public final <U> U fetchOne(Name fieldName, Converter<?, ? extends U> converter)

@Override
public final R fetchOne() {
return Tools.fetchOne(fetchLazy());
return Tools.fetchOne(fetchLazy(), hasLimit1());
}

@Override
Expand Down Expand Up @@ -627,7 +627,7 @@ public final <U> U fetchSingle(Name fieldName, Converter<?, ? extends U> convert

@Override
public final R fetchSingle() {
return Tools.fetchSingle(fetchLazy());
return Tools.fetchSingle(fetchLazy(), hasLimit1());
}

@Override
Expand Down Expand Up @@ -1475,4 +1475,14 @@ public final Result<R> call() throws Exception {
return fetch();
}
}

@SuppressWarnings("rawtypes")
private final boolean hasLimit1() {
if (this instanceof SelectQueryImpl) {
Limit l = ((SelectQueryImpl) this).getLimit();
return !l.withTies() && l.limitOne();
}

return false;
}
}
13 changes: 12 additions & 1 deletion jOOQ/src/main/java/org/jooq/impl/Limit.java
Expand Up @@ -360,12 +360,23 @@ public final Clause[] clauses(Context<?> ctx) {
}

/**
* Whether this limit has an offset of zero
* Whether this limit has a limit of zero
*/
final boolean limitZero() {
return numberOfRows == null;
}

/**
* Whether this limit has a limit of one
*/
final boolean limitOne() {
return !limitZero()
&& !withTies()

&& numberOfRows instanceof Param
&& Integer.valueOf(1).equals(((Param<?>) numberOfRows).getValue());
}

/**
* Whether this limit has an offset of zero
*/
Expand Down
44 changes: 42 additions & 2 deletions jOOQ/src/main/java/org/jooq/impl/Tools.java
Expand Up @@ -1705,11 +1705,31 @@ else if (size == 1)
* element
*/
static final <R extends Record> R fetchOne(Cursor<R> cursor) throws TooManyRowsException {
return fetchOne(cursor, false);
}

/**
* Get the only element from a cursor or <code>null</code>, or throw an
* exception.
* <p>
* [#2373] This method will always close the argument cursor, as it is
* supposed to be completely consumed by this method.
*
* @param cursor The cursor
* @param hasLimit1 Whether a LIMIT clause is present that guarantees at
* most one row
* @return The only element from the cursor or <code>null</code>
* @throws TooManyRowsException Thrown if the cursor returns more than one
* element
*/
static final <R extends Record> R fetchOne(Cursor<R> cursor, boolean hasLimit1) throws TooManyRowsException {
try {

// [#7001] Fetching at most two rows rather than at most one row
// (and then checking of additional rows) improves debug logs
Result<R> result = cursor.fetchNext(2);
// [#7430] Avoid fetching the second row (additional overhead) if
// there is a guarantee of at most one row
Result<R> result = cursor.fetchNext(hasLimit1 ? 1 : 2);
int size = result.size();

if (size == 0)
Expand Down Expand Up @@ -1737,11 +1757,31 @@ else if (size == 1)
* element
*/
static final <R extends Record> R fetchSingle(Cursor<R> cursor) throws NoDataFoundException, TooManyRowsException {
return fetchSingle(cursor, false);
}

/**
* Get the only element from a cursor, or throw an exception.
* <p>
* [#2373] This method will always close the argument cursor, as it is
* supposed to be completely consumed by this method.
*
* @param cursor The cursor
* @param hasLimit1 Whether a LIMIT clause is present that guarantees at
* most one row
* @return The only element from the cursor
* @throws NoDataFoundException Thrown if the cursor did not return any rows
* @throws TooManyRowsException Thrown if the cursor returns more than one
* element
*/
static final <R extends Record> R fetchSingle(Cursor<R> cursor, boolean hasLimit1) throws NoDataFoundException, TooManyRowsException {
try {

// [#7001] Fetching at most two rows rather than at most one row
// (and then checking of additional rows) improves debug logs
Result<R> result = cursor.fetchNext(2);
// [#7430] Avoid fetching the second row (additional overhead) if
// there is a guarantee of at most one row
Result<R> result = cursor.fetchNext(hasLimit1 ? 1 : 2);
int size = result.size();

if (size == 0)
Expand Down

0 comments on commit c2c125b

Please sign in to comment.