2828import io .r2dbc .spi .R2dbcException ;
2929
3030import io .r2dbc .spi .R2dbcType ;
31+ import io .r2dbc .spi .Result ;
3132import io .r2dbc .spi .Row ;
3233import io .r2dbc .spi .RowMetadata ;
3334import io .r2dbc .spi .Type ;
3738import oracle .r2dbc .impl .ReadablesMetadata .RowMetadataImpl ;
3839
3940import java .nio .ByteBuffer ;
41+ import java .sql .ResultSet ;
4042import java .sql .Timestamp ;
4143import java .time .LocalDateTime ;
4244import java .util .NoSuchElementException ;
@@ -65,19 +67,27 @@ class OracleReadableImpl implements io.r2dbc.spi.Readable {
6567 /** Metadata of the values of this {@code Readable}. */
6668 private final ReadablesMetadata <?> readablesMetadata ;
6769
70+ /**
71+ * A collection of results that depend on the JDBC statement which created
72+ * this readable to remain open until all results are consumed.
73+ */
74+ private final DependentCounter dependentCounter ;
75+
6876 /**
6977 * <p>
7078 * Constructs a new {@code Readable} that supplies values of a
7179 * {@code jdbcReadable} and obtains metadata of the values from
7280 * {@code resultMetadata}.
7381 * </p>
82+ *
7483 * @param jdbcReadable Readable values from a JDBC Driver. Not null.
7584 * @param readablesMetadata Metadata of each value. Not null.
7685 * @param adapter Adapts JDBC calls into reactive streams. Not null.
7786 */
7887 private OracleReadableImpl (
79- JdbcReadable jdbcReadable , ReadablesMetadata <?> readablesMetadata ,
80- ReactiveJdbcAdapter adapter ) {
88+ DependentCounter dependentCounter , JdbcReadable jdbcReadable ,
89+ ReadablesMetadata <?> readablesMetadata , ReactiveJdbcAdapter adapter ) {
90+ this .dependentCounter = dependentCounter ;
8191 this .jdbcReadable = jdbcReadable ;
8292 this .readablesMetadata = readablesMetadata ;
8393 this .adapter = adapter ;
@@ -96,9 +106,9 @@ private OracleReadableImpl(
96106 * {@code metadata}. Not null.
97107 */
98108 static Row createRow (
99- JdbcReadable jdbcReadable , RowMetadataImpl metadata ,
100- ReactiveJdbcAdapter adapter ) {
101- return new RowImpl (jdbcReadable , metadata , adapter );
109+ DependentCounter dependentCounter , JdbcReadable jdbcReadable ,
110+ RowMetadataImpl metadata , ReactiveJdbcAdapter adapter ) {
111+ return new RowImpl (dependentCounter , jdbcReadable , metadata , adapter );
102112 }
103113 /**
104114 * <p>
@@ -113,9 +123,10 @@ static Row createRow(
113123 * {@code metadata}. Not null.
114124 */
115125 static OutParameters createOutParameters (
116- JdbcReadable jdbcReadable , OutParametersMetadataImpl metadata ,
117- ReactiveJdbcAdapter adapter ) {
118- return new OutParametersImpl (jdbcReadable , metadata , adapter );
126+ DependentCounter dependentCounter , JdbcReadable jdbcReadable ,
127+ OutParametersMetadataImpl metadata , ReactiveJdbcAdapter adapter ) {
128+ return new OutParametersImpl (
129+ dependentCounter , jdbcReadable , metadata , adapter );
119130 }
120131
121132 /**
@@ -162,8 +173,8 @@ public <T> T get(String name, Class<T> type) {
162173 /**
163174 * Returns the 0-based index of the value identified by {@code name}. This
164175 * method implements a case-insensitive name match. If more than one
165- * value has a matching name, this method returns lowest index of all
166- * matching values .
176+ * value has a matching name, this method returns lowest of all indexes that
177+ * match .
167178 * @param name The name of a value. Not null.
168179 * @return The index of the named value within this {@code Readable}
169180 * @throws NoSuchElementException If no column has a matching name.
@@ -208,6 +219,9 @@ else if (io.r2dbc.spi.Clob.class.equals(type)) {
208219 else if (LocalDateTime .class .equals (type )) {
209220 value = getLocalDateTime (index );
210221 }
222+ else if (Result .class .equals (type )) {
223+ value = getResult (index );
224+ }
211225 else if (Object .class .equals (type )) {
212226 // Use the default type mapping if Object.class has been specified.
213227 // This method is invoked recursively with the default mapping, so long
@@ -327,6 +341,36 @@ private LocalDateTime getLocalDateTime(int index) {
327341 }
328342 }
329343
344+ /**
345+ * <p>
346+ * Converts the value of a column at the specified {@code index} to a
347+ * {@code Result}. This method is intended for mapping REF CURSOR values,
348+ * which JDBC will map to a {@link ResultSet}.
349+ * </p><p>
350+ * A REF CURSOR is closed when the JDBC statement that created it is closed.
351+ * To prevent the cursor from getting closed, the Result returned by this
352+ * method is immediately added to the collection of results that depend on the
353+ * JDBC statement.
354+ * </p><p>
355+ * The Result returned by this method is received by user code, and user code
356+ * MUST then fully consume it. The JDBC statement is not closed until the
357+ * result is fully consumed.
358+ * </p>
359+ * @param index 0 based column index
360+ * @return A column value as a {@code Result}, or null if the column value is
361+ * NULL.
362+ */
363+ private Result getResult (int index ) {
364+ ResultSet resultSet = jdbcReadable .getObject (index , ResultSet .class );
365+
366+ if (resultSet == null )
367+ return null ;
368+
369+ dependentCounter .increment ();
370+ return OracleResultImpl .createQueryResult (
371+ dependentCounter , resultSet , adapter );
372+ }
373+
330374 /**
331375 * Checks if the specified zero-based {@code index} is a valid column index
332376 * for this row. This method is used to verify index value parameters
@@ -368,10 +412,9 @@ private static final class RowImpl
368412 * @param adapter Adapts JDBC calls into reactive streams. Not null.
369413 */
370414 private RowImpl (
371- JdbcReadable jdbcReadable ,
372- RowMetadataImpl metadata ,
373- ReactiveJdbcAdapter adapter ) {
374- super (jdbcReadable , metadata , adapter );
415+ DependentCounter dependentCounter , JdbcReadable jdbcReadable ,
416+ RowMetadataImpl metadata , ReactiveJdbcAdapter adapter ) {
417+ super (dependentCounter , jdbcReadable , metadata , adapter );
375418 this .metadata = metadata ;
376419 }
377420
@@ -410,10 +453,9 @@ private static final class OutParametersImpl
410453 * @param adapter Adapts JDBC calls into reactive streams. Not null.
411454 */
412455 private OutParametersImpl (
413- JdbcReadable jdbcReadable ,
414- OutParametersMetadataImpl metadata ,
415- ReactiveJdbcAdapter adapter ) {
416- super (jdbcReadable , metadata , adapter );
456+ DependentCounter dependentCounter , JdbcReadable jdbcReadable ,
457+ OutParametersMetadataImpl metadata , ReactiveJdbcAdapter adapter ) {
458+ super (dependentCounter ,jdbcReadable , metadata , adapter );
417459 this .metadata = metadata ;
418460 }
419461
0 commit comments