/*
 * 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.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.Iterator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collector;
import java.util.stream.Stream;

import org.jooq.conf.Settings;
import org.jooq.exception.DataAccessException;
import org.jooq.exception.MappingException;
import org.jooq.impl.DefaultRecordMapper;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

Cursors allow for lazy, sequential access to an underlying JDBC ResultSet. Unlike Result, data can only be accessed sequentially, using an Iterator, or the cursor's hasNext() and fetch() methods.

Client code must close this Cursor in order to close the underlying PreparedStatement and ResultSet

The cursor can be consumed in two ways:

  • Record by record: Such methods can be recognised by the term "Next" in the method name, e.g. fetchNext(int).
  • Completely in one go: Such methods do not have the term "Next" in their method names, e.g. fetch().

Note: Unlike usual implementations of Iterable, a Cursor can only provide one Iterator!

Author:Lukas Eder
Type parameters:
  • <R> – The cursor's record type
/** * Cursors allow for lazy, sequential access to an underlying JDBC * {@link ResultSet}. Unlike {@link Result}, data can only be accessed * sequentially, using an {@link Iterator}, or the cursor's {@link #hasNext()} * and {@link #fetch()} methods. * <p> * Client code must close this {@link Cursor} in order to close the underlying * {@link PreparedStatement} and {@link ResultSet} * <p> * The cursor can be consumed in two ways: * <ul> * <li>Record by record: Such methods can be recognised by the term "Next" in * the method name, e.g. {@link #fetchNext(int)}.</li> * <li>Completely in one go: Such methods do not have the term "Next" in their * method names, e.g. {@link #fetch()}.</li> * </ul> * <p> * Note: Unlike usual implementations of {@link Iterable}, a <code>Cursor</code> * can only provide one {@link Iterator}! * * @param <R> The cursor's record type * @author Lukas Eder */
public interface Cursor<R extends Record> extends Iterable<R>, Formattable , AutoCloseable {
Get this cursor's row type.
/** * Get this cursor's row type. */
@NotNull RecordType<R> recordType();
Get this cursor's fields as a Row.
/** * Get this cursor's fields as a {@link Row}. */
@NotNull Row fieldsRow();
Get a specific field from this Cursor.

This will return:

  • A field that is the same as the argument field (by identity comparison).
  • A field that is equal to the argument field (exact matching fully qualified name).
  • A field that is equal to the argument field (partially matching qualified name).
  • A field whose name is equal to the name of the argument field.
  • null otherwise.
If several fields have the same name, the first one is returned and a warning is logged.
See Also:
  • field.field(Field)
/** * Get a specific field from this Cursor. * <p> * This will return: * <ul> * <li>A field that is the same as the argument field (by identity * comparison).</li> * <li>A field that is equal to the argument field (exact matching fully * qualified name).</li> * <li>A field that is equal to the argument field (partially matching * qualified name).</li> * <li>A field whose name is equal to the name of the argument field.</li> * <li><code>null</code> otherwise. * </ul> * If several fields have the same name, the first one is returned and a * warning is logged. * * @see Row#field(Field) */
@Nullable <T> Field<T> field(Field<T> field);
Get a specific field from this Cursor.
See Also:
  • field.field(String)
/** * Get a specific field from this Cursor. * * @see Row#field(String) */
@Nullable Field<?> field(String name);
Get a specific qualified field from this Cursor.
See Also:
  • field.field(Name)
/** * Get a specific qualified field from this Cursor. * * @see Row#field(Name) */
@Nullable Field<?> field(Name name);
Get a specific field from this Cursor.
See Also:
  • field.field(int)
/** * Get a specific field from this Cursor. * * @see Row#field(int) */
@Nullable Field<?> field(int index);
Get all fields from this Cursor.
See Also:
  • fields.fields()
/** * Get all fields from this Cursor. * * @see Row#fields() */
@NotNull Field<?>[] fields();
Get all fields from this Cursor, providing some fields.
See Also:
Returns:All available fields
/** * Get all fields from this Cursor, providing some fields. * * @return All available fields * @see Row#fields(Field...) */
@NotNull Field<?>[] fields(Field<?>... fields);
Get all fields from this Cursor, providing some field names.
See Also:
Returns:All available fields
/** * Get all fields from this Cursor, providing some field names. * * @return All available fields * @see Row#fields(String...) */
@NotNull Field<?>[] fields(String... fieldNames);
Get all fields from this Cursor, providing some field names.
See Also:
Returns:All available fields
/** * Get all fields from this Cursor, providing some field names. * * @return All available fields * @see Row#fields(Name...) */
@NotNull Field<?>[] fields(Name... fieldNames);
Get all fields from this Cursor, providing some field indexes.
See Also:
Returns:All available fields
/** * Get all fields from this Cursor, providing some field indexes. * * @return All available fields * @see Row#fields(int...) */
@NotNull Field<?>[] fields(int... fieldIndexes);
Get a field's index from this cursor.
Params:
  • field – The field to look for
Returns:The field's index or -1 if the field is not contained in this cursor.
/** * Get a field's index from this cursor. * * @param field The field to look for * @return The field's index or <code>-1</code> if the field is not * contained in this cursor. */
int indexOf(Field<?> field);
Get a field's index from this cursor.
Params:
  • fieldName – The field name to look for
Returns:The field's index or -1 if the field is not contained in this cursor.
/** * Get a field's index from this cursor. * * @param fieldName The field name to look for * @return The field's index or <code>-1</code> if the field is not * contained in this cursor. */
int indexOf(String fieldName);
Get a field's index from this cursor.
Params:
  • fieldName – The field name to look for
Returns:The field's index or -1 if the field is not contained in this cursor
/** * Get a field's index from this cursor. * * @param fieldName The field name to look for * @return The field's index or <code>-1</code> if the field is not * contained in this cursor */
int indexOf(Name fieldName);
Check whether this cursor has a next record.

This will conveniently close the Cursor, after the last Record was fetched.

Throws:
  • DataAccessException – if something went wrong executing the query
/** * Check whether this cursor has a next record. * <p> * This will conveniently close the <code>Cursor</code>, after the last * <code>Record</code> was fetched. * * @throws DataAccessException if something went wrong executing the query */
boolean hasNext() throws DataAccessException;
Fetch all remaining records as a result.

This will conveniently close the Cursor, after the last Record was fetched.

The result and its contained records are attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Throws:
/** * Fetch all remaining records as a result. * <p> * This will conveniently close the <code>Cursor</code>, after the last * <code>Record</code> was fetched. * <p> * The result and its contained records are attached to the original * {@link Configuration} by default. Use {@link Settings#isAttachRecords()} * to override this behaviour. * * @throws DataAccessException if something went wrong executing the query */
@NotNull Result<R> fetch() throws DataAccessException;
Deprecated:- 3.10 - [#6363] - Use fetchNext(int) instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNext(int)} instead. */
@NotNull @Deprecated Result<R> fetch(int number) throws DataAccessException;
Fetch the next couple of records from the cursor.

This will conveniently close the Cursor, after the last Record was fetched.

The result and its contained records are attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Params:
  • number – The number of records to fetch. If this is 0 or negative an empty list is returned, the cursor is untouched. If this is greater than the number of remaining records, then all remaining records are returned.
Throws:
/** * Fetch the next couple of records from the cursor. * <p> * This will conveniently close the <code>Cursor</code>, after the last * <code>Record</code> was fetched. * <p> * The result and its contained records are attached to the original * {@link Configuration} by default. Use {@link Settings#isAttachRecords()} * to override this behaviour. * * @param number The number of records to fetch. If this is <code>0</code> * or negative an empty list is returned, the cursor is * untouched. If this is greater than the number of remaining * records, then all remaining records are returned. * @throws DataAccessException if something went wrong executing the query */
@NotNull Result<R> fetchNext(int number) throws DataAccessException;
Fetch results into a custom handler callback.

The resulting records are attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Params:
  • handler – The handler callback
Throws:
Returns:Convenience result, returning the parameter handler itself
/** * Fetch results into a custom handler callback. * <p> * The resulting records are attached to the original {@link Configuration} * by default. Use {@link Settings#isAttachRecords()} to override this * behaviour. * * @param handler The handler callback * @return Convenience result, returning the parameter handler itself * @throws DataAccessException if something went wrong executing the query */
@NotNull <H extends RecordHandler<? super R>> H fetchInto(H handler) throws DataAccessException;
Fetch results into a custom mapper callback.
Params:
  • mapper – The mapper callback
Throws:
Returns:The custom mapped records
/** * Fetch results into a custom mapper callback. * * @param mapper The mapper callback * @return The custom mapped records * @throws DataAccessException if something went wrong executing the query */
@NotNull <E> List<E> fetch(RecordMapper<? super R, E> mapper) throws DataAccessException;
Map resulting records onto a custom type.

This is the same as calling fetch().into(type). See Record.into(Class<? extends Object>) for more details

Params:
  • type – The entity type.
Type parameters:
  • <E> – The generic entity type.
Throws:
  • DataAccessException – if something went wrong executing the query
  • MappingException – wrapping any reflection or data type conversion exception that might have occurred while mapping records
See Also:
/** * Map resulting records onto a custom type. * <p> * This is the same as calling <code>fetch().into(type)</code>. See * {@link Record#into(Class)} for more details * * @param <E> The generic entity type. * @param type The entity type. * @see Record#into(Class) * @see Result#into(Class) * @throws DataAccessException if something went wrong executing the query * @throws MappingException wrapping any reflection or data type conversion * exception that might have occurred while mapping records * @see DefaultRecordMapper */
@NotNull <E> List<E> fetchInto(Class<? extends E> type) throws DataAccessException, MappingException;
Map resulting records onto a custom record.

This is the same as calling fetch().into(table). See Record.into(Class<? extends Object>) for more details

The result and its contained records are attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Params:
  • table – The table type.
Type parameters:
  • <Z> – The generic table record type.
Throws:
  • DataAccessException – if something went wrong executing the query
  • MappingException – wrapping any reflection or data type conversion exception that might have occurred while mapping records
See Also:
/** * Map resulting records onto a custom record. * <p> * This is the same as calling <code>fetch().into(table)</code>. See * {@link Record#into(Class)} for more details * <p> * The result and its contained records are attached to the original * {@link Configuration} by default. Use {@link Settings#isAttachRecords()} * to override this behaviour. * * @param <Z> The generic table record type. * @param table The table type. * @see Record#into(Class) * @see Result#into(Class) * @throws DataAccessException if something went wrong executing the query * @throws MappingException wrapping any reflection or data type conversion * exception that might have occurred while mapping records */
@NotNull <Z extends Record> Result<Z> fetchInto(Table<Z> table) throws DataAccessException, MappingException;
Deprecated:- 3.10 - [#6363] - Use fetchNext() instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNext()} instead. */
@Nullable @Deprecated R fetchOne() throws DataAccessException;
Deprecated:- 3.10 - [#6363] - Use fetchNextInto(RecordHandler) instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNextInto(RecordHandler)} instead. */
@NotNull @Deprecated <H extends RecordHandler<? super R>> H fetchOneInto(H handler) throws DataAccessException;
Deprecated:- 3.10 - [#6363] - Use fetchNext(RecordMapper) instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNext(RecordMapper)} instead. */
@Nullable @Deprecated <E> E fetchOne(RecordMapper<? super R, E> mapper) throws DataAccessException;
Deprecated:- 3.10 - [#6363] - Use fetchNextInto(Table) instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNextInto(Table)} instead. */
@Nullable @Deprecated <Z extends Record> Z fetchOneInto(Table<Z> table) throws DataAccessException, MappingException;
Fetch the next record from the cursor.

This will conveniently close the Cursor, after the last Record was fetched.

The resulting record is attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Throws:
Returns:The next record from the cursor, or null if there is no next record.
/** * Fetch the next record from the cursor. * <p> * This will conveniently close the <code>Cursor</code>, after the last * <code>Record</code> was fetched. * <p> * The resulting record is attached to the original {@link Configuration} by * default. Use {@link Settings#isAttachRecords()} to override this * behaviour. * * @return The next record from the cursor, or <code>null</code> if there is * no next record. * @throws DataAccessException if something went wrong executing the query */
@Nullable R fetchNext() throws DataAccessException;
Fetch the next record into a custom handler callback.

This will conveniently close the Cursor, after the last Record was fetched.

The resulting record is attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Params:
  • handler – The handler callback
Throws:
Returns:Convenience result, returning the parameter handler itself
/** * Fetch the next record into a custom handler callback. * <p> * This will conveniently close the <code>Cursor</code>, after the last * <code>Record</code> was fetched. * <p> * The resulting record is attached to the original {@link Configuration} by * default. Use {@link Settings#isAttachRecords()} to override this * behaviour. * * @param handler The handler callback * @return Convenience result, returning the parameter handler itself * @throws DataAccessException if something went wrong executing the query */
@NotNull <H extends RecordHandler<? super R>> H fetchNextInto(H handler) throws DataAccessException;
Deprecated:- 3.10 - [#6363] - Use fetchNextInto(Class) instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNextInto(Class)} instead. */
@Nullable @Deprecated <E> E fetchOneInto(Class<? extends E> type) throws DataAccessException, MappingException;
Map the next resulting record onto a custom type.

This is the same as calling fetchOne().into(type). See Record.into(Class<? extends Object>) for more details

Params:
  • type – The entity type.
Type parameters:
  • <E> – The generic entity type.
Throws:
  • DataAccessException – if something went wrong executing the query
  • MappingException – wrapping any reflection or data type conversion exception that might have occurred while mapping records
See Also:
/** * Map the next resulting record onto a custom type. * <p> * This is the same as calling <code>fetchOne().into(type)</code>. See * {@link Record#into(Class)} for more details * * @param <E> The generic entity type. * @param type The entity type. * @see Record#into(Class) * @see Result#into(Class) * @throws DataAccessException if something went wrong executing the query * @throws MappingException wrapping any reflection or data type conversion * exception that might have occurred while mapping records * @see DefaultRecordMapper */
@Nullable <E> E fetchNextInto(Class<? extends E> type) throws DataAccessException, MappingException;
Fetch the next record into a custom mapper callback.

This will conveniently close the Cursor, after the last Record was fetched.

Params:
  • mapper – The mapper callback
Throws:
Returns:The custom mapped record
/** * Fetch the next record into a custom mapper callback. * <p> * This will conveniently close the <code>Cursor</code>, after the last * <code>Record</code> was fetched. * * @param mapper The mapper callback * @return The custom mapped record * @throws DataAccessException if something went wrong executing the query */
@Nullable <E> E fetchNext(RecordMapper<? super R, E> mapper) throws DataAccessException;
Map the next resulting record onto a custom record.

This is the same as calling fetchOne().into(table). See Record.into(Class<? extends Object>) for more details

The resulting record is attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Params:
  • table – The table type.
Type parameters:
  • <Z> – The generic table record type.
Throws:
  • DataAccessException – if something went wrong executing the query
  • MappingException – wrapping any reflection or data type conversion exception that might have occurred while mapping records
See Also:
/** * Map the next resulting record onto a custom record. * <p> * This is the same as calling <code>fetchOne().into(table)</code>. See * {@link Record#into(Class)} for more details * <p> * The resulting record is attached to the original {@link Configuration} by * default. Use {@link Settings#isAttachRecords()} to override this * behaviour. * * @param <Z> The generic table record type. * @param table The table type. * @see Record#into(Class) * @see Result#into(Class) * @throws DataAccessException if something went wrong executing the query * @throws MappingException wrapping any reflection or data type conversion * exception that might have occurred while mapping records */
@Nullable <Z extends Record> Z fetchNextInto(Table<Z> table) throws DataAccessException, MappingException;
Deprecated:- 3.10 - [#6363] - Use fetchNextOptional() instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNextOptional()} instead. */
@NotNull @Deprecated Optional<R> fetchOptional() throws DataAccessException;
Deprecated:- 3.10 - [#6363] - Use fetchNextOptionalInto(Class) instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNextOptionalInto(Class)} instead. */
@NotNull @Deprecated <E> Optional<E> fetchOptionalInto(Class<? extends E> type) throws DataAccessException, MappingException;
Deprecated:- 3.10 - [#6363] - Use fetchNextOptional(RecordMapper) instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNextOptional(RecordMapper)} instead. */
@NotNull @Deprecated <E> Optional<E> fetchOptional(RecordMapper<? super R, E> mapper) throws DataAccessException;
Deprecated:- 3.10 - [#6363] - Use fetchNextOptionalInto(Table) instead.
/** * @deprecated - 3.10 - [#6363] - Use {@link #fetchNextOptionalInto(Table)} instead. */
@NotNull @Deprecated <Z extends Record> Optional<Z> fetchOptionalInto(Table<Z> table) throws DataAccessException, MappingException;
Fetch the next record from the cursor.

This will conveniently close the Cursor, after the last Record was fetched.

The resulting record is attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Throws:
Returns:The next record from the cursor
/** * Fetch the next record from the cursor. * <p> * This will conveniently close the <code>Cursor</code>, after the last * <code>Record</code> was fetched. * <p> * The resulting record is attached to the original {@link Configuration} by * default. Use {@link Settings#isAttachRecords()} to override this * behaviour. * * @return The next record from the cursor * @throws DataAccessException if something went wrong executing the query */
@NotNull Optional<R> fetchNextOptional() throws DataAccessException;
Map the next resulting record onto a custom type.

This is the same as calling fetchOne().into(type). See Record.into(Class<? extends Object>) for more details

Params:
  • type – The entity type.
Type parameters:
  • <E> – The generic entity type.
Throws:
  • DataAccessException – if something went wrong executing the query
  • MappingException – wrapping any reflection or data type conversion exception that might have occurred while mapping records
See Also:
/** * Map the next resulting record onto a custom type. * <p> * This is the same as calling <code>fetchOne().into(type)</code>. See * {@link Record#into(Class)} for more details * * @param <E> The generic entity type. * @param type The entity type. * @see Record#into(Class) * @see Result#into(Class) * @throws DataAccessException if something went wrong executing the query * @throws MappingException wrapping any reflection or data type conversion * exception that might have occurred while mapping records * @see DefaultRecordMapper */
@NotNull <E> Optional<E> fetchNextOptionalInto(Class<? extends E> type) throws DataAccessException, MappingException;
Fetch the next record into a custom mapper callback.

This will conveniently close the Cursor, after the last Record was fetched.

Params:
  • mapper – The mapper callback
Throws:
Returns:The custom mapped record
/** * Fetch the next record into a custom mapper callback. * <p> * This will conveniently close the <code>Cursor</code>, after the last * <code>Record</code> was fetched. * * @param mapper The mapper callback * @return The custom mapped record * @throws DataAccessException if something went wrong executing the query */
@NotNull <E> Optional<E> fetchNextOptional(RecordMapper<? super R, E> mapper) throws DataAccessException;
Map the next resulting record onto a custom record.

This is the same as calling fetchOne().into(table). See Record.into(Class<? extends Object>) for more details

The resulting record is attached to the original Configuration by default. Use Settings.isAttachRecords() to override this behaviour.

Params:
  • table – The table type.
Type parameters:
  • <Z> – The generic table record type.
Throws:
  • DataAccessException – if something went wrong executing the query
  • MappingException – wrapping any reflection or data type conversion exception that might have occurred while mapping records
See Also:
/** * Map the next resulting record onto a custom record. * <p> * This is the same as calling <code>fetchOne().into(table)</code>. See * {@link Record#into(Class)} for more details * <p> * The resulting record is attached to the original {@link Configuration} by * default. Use {@link Settings#isAttachRecords()} to override this * behaviour. * * @param <Z> The generic table record type. * @param table The table type. * @see Record#into(Class) * @see Result#into(Class) * @throws DataAccessException if something went wrong executing the query * @throws MappingException wrapping any reflection or data type conversion * exception that might have occurred while mapping records */
@NotNull <Z extends Record> Optional<Z> fetchNextOptionalInto(Table<Z> table) throws DataAccessException, MappingException;
Turn this Cursor into a Stream.
Throws:
/** * Turn this <code>Cursor</code> into a {@link Stream}. * * @throws DataAccessException if something went wrong executing the query */
@NotNull Stream<R> stream() throws DataAccessException;
Reduce the execution results of this query using a Collector.

This works in the same way as calling the following code:


cursor.stream().collect(collector);

Params:
  • collector – The collector that collects all records and accumulates them into a result type.
Throws:
Returns:The result of the collection.
/** * Reduce the execution results of this query using a {@link Collector}. * <p> * This works in the same way as calling the following code: * * <pre> * <code> * cursor.stream().collect(collector); * </code> * </pre> * * @param collector The collector that collects all records and accumulates * them into a result type. * @return The result of the collection. * @throws DataAccessException if something went wrong executing the query */
<X, A> X collect(Collector<? super R, A, X> collector) throws DataAccessException;
Explicitly close the underlying PreparedStatement and ResultSet.

If you fetch all records from the underlying ResultSet, jOOQ Cursor implementations will close themselves for you. Calling close() again will have no effect.

Throws:
/** * Explicitly close the underlying {@link PreparedStatement} and * {@link ResultSet}. * <p> * If you fetch all records from the underlying {@link ResultSet}, jOOQ * <code>Cursor</code> implementations will close themselves for you. * Calling <code>close()</code> again will have no effect. * * @throws DataAccessException if something went wrong executing the query */
@Override void close() throws DataAccessException;
Check whether this Cursor has been explicitly or "conveniently" closed.

Explicit closing can be achieved by calling close() from client code. "Convenient" closing is done by any of the other methods, when the last record was fetched.

/** * Check whether this <code>Cursor</code> has been explicitly or * "conveniently" closed. * <p> * Explicit closing can be achieved by calling {@link #close()} from client * code. "Convenient" closing is done by any of the other methods, when the * last record was fetched. */
boolean isClosed();
Get the Cursor's underlying ResultSet.

This will return a ResultSet wrapping the JDBC driver's ResultSet. Closing this ResultSet may close the producing Statement or PreparedStatement, depending on your setting for ResultQuery.keepStatement(boolean).

Modifying this ResultSet will affect this Cursor.

Returns:The underlying ResultSet. May be null, for instance when the Cursor is closed.
/** * Get the <code>Cursor</code>'s underlying {@link ResultSet}. * <p> * This will return a {@link ResultSet} wrapping the JDBC driver's * <code>ResultSet</code>. Closing this <code>ResultSet</code> may close the * producing {@link Statement} or {@link PreparedStatement}, depending on * your setting for {@link ResultQuery#keepStatement(boolean)}. * <p> * Modifying this <code>ResultSet</code> will affect this * <code>Cursor</code>. * * @return The underlying <code>ResultSet</code>. May be <code>null</code>, * for instance when the <code>Cursor</code> is closed. */
@Nullable ResultSet resultSet(); }