Skip to content

Commit 938b999

Browse files
Merge pull request #53 from oracle/0-9-0-RC1-update
0.9.0.RC1 SPI Update
2 parents 8f02724 + 89dfaef commit 938b999

19 files changed

+231
-119
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
<properties>
6767
<java.version>11</java.version>
6868
<ojdbc.version>21.3.0.0</ojdbc.version>
69-
<r2dbc.version>0.9.0.M2</r2dbc.version>
69+
<r2dbc.version>0.9.0.RC1</r2dbc.version>
7070
<reactor.version>3.3.0.RELEASE</reactor.version>
7171
<reactive-streams.version>1.0.3</reactive-streams.version>
7272
<junit.version>5.7.0</junit.version>

src/main/java/oracle/r2dbc/impl/OracleR2dbcExceptions.java

Lines changed: 48 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import io.r2dbc.spi.R2dbcTimeoutException;
3131
import io.r2dbc.spi.R2dbcTransientException;
3232
import io.r2dbc.spi.R2dbcTransientResourceException;
33+
import oracle.jdbc.OracleDatabaseException;
3334

3435
import java.sql.SQLException;
3536
import java.sql.SQLIntegrityConstraintViolationException;
@@ -166,41 +167,42 @@ static R2dbcException toR2dbcException(SQLException sqlException) {
166167
final String message = sqlException.getMessage();
167168
final String sqlState = sqlException.getSQLState();
168169
final int errorCode = sqlException.getErrorCode();
170+
final String sql = getSql(sqlException);
169171

170172
if (sqlException instanceof SQLNonTransientException) {
171173
if (sqlException instanceof SQLSyntaxErrorException) {
172174
return new R2dbcBadGrammarException(
173-
message, sqlState, errorCode, sqlException);
175+
message, sqlState, errorCode, sql, sqlException);
174176
}
175177
else if (sqlException instanceof SQLIntegrityConstraintViolationException) {
176178
return new R2dbcDataIntegrityViolationException(
177-
message, sqlState, errorCode, sqlException);
179+
message, sqlState, errorCode, sql, sqlException);
178180
}
179181
else if (sqlException instanceof SQLNonTransientConnectionException) {
180182
return new R2dbcNonTransientResourceException(
181-
message, sqlState, errorCode, sqlException);
183+
message, sqlState, errorCode, sql, sqlException);
182184
}
183185
else {
184186
return new OracleR2dbcNonTransientException(
185-
message, sqlState, errorCode, sqlException);
187+
message, sqlState, errorCode, sql, sqlException);
186188
}
187189
}
188190
else if (sqlException instanceof SQLTransientException) {
189191
if (sqlException instanceof SQLTimeoutException) {
190192
return new R2dbcTimeoutException(
191-
message, sqlState, errorCode, sqlException);
193+
message, sqlState, errorCode, sql, sqlException);
192194
}
193195
else if (sqlException instanceof SQLTransactionRollbackException) {
194196
return new R2dbcRollbackException(
195-
message, sqlState, errorCode, sqlException);
197+
message, sqlState, errorCode, sql, sqlException);
196198
}
197199
else if (sqlException instanceof SQLTransientConnectionException) {
198200
return new R2dbcTransientResourceException(
199-
message, sqlState, errorCode, sqlException);
201+
message, sqlState, errorCode, sql, sqlException);
200202
}
201203
else {
202204
return new OracleR2dbcTransientException(
203-
message, sqlState, errorCode, sqlException);
205+
message, sqlState, errorCode, sql, sqlException);
204206
}
205207
}
206208
else if (sqlException instanceof SQLRecoverableException) {
@@ -209,11 +211,11 @@ else if (sqlException instanceof SQLRecoverableException) {
209211
// the connection is no longer valid. The R2dbcTransientResourceException
210212
// expresses the same conditions.
211213
return new R2dbcTransientResourceException(
212-
message, sqlState, errorCode, sqlException);
214+
message, sqlState, errorCode, sql, sqlException);
213215
}
214216
else {
215217
return new OracleR2dbcException(
216-
message, sqlState, errorCode, sqlException);
218+
message, sqlState, errorCode, sql, sqlException);
217219
}
218220
}
219221

@@ -293,8 +295,30 @@ static <T> T fromJdbc(ThrowingSupplier<T> supplier)
293295
* @return A new non-transient exception.
294296
*/
295297
static R2dbcNonTransientException newNonTransientException(
296-
String message, Throwable cause) {
297-
return new OracleR2dbcNonTransientException(message, null, 0, cause);
298+
String message, String sql, Throwable cause) {
299+
return new OracleR2dbcNonTransientException(message, null, 0, sql, cause);
300+
}
301+
302+
/**
303+
* Returns the SQL command that caused a {@code sqlException}, if it is
304+
* available. This method is only implemented to support the case where the
305+
* exception is caused by a {@link oracle.jdbc.OracleDatabaseException}.
306+
* @param sqlException Exception to extract SQL from. Not null.
307+
* @return The SQL that caused the {@code sqlException}, of {@code null} if
308+
* the SQL is not available.
309+
*/
310+
private static String getSql(SQLException sqlException) {
311+
Throwable cause = sqlException.getCause();
312+
313+
while (cause != null) {
314+
315+
if (cause instanceof OracleDatabaseException)
316+
return ((OracleDatabaseException)cause).getSql();
317+
318+
cause = cause.getCause();
319+
}
320+
321+
return null;
298322
}
299323

300324
/**
@@ -368,17 +392,17 @@ default T get() throws R2dbcException {
368392
* concrete subclass must be defined. This subclass does not implement any
369393
* behavior that is specific to the Oracle driver.
370394
* </p><p>
371-
* This subclass is defined so that {@link #toR2dbcException(SQLException)}
372-
* can throw an instance of {@code R2dbcException} when mapping a
373-
* {@link SQLException}.
395+
* This subclass is defined so that
396+
* {@link #toR2dbcException(SQLException)} can throw an instance of
397+
* {@code R2dbcException} when mapping a {@link SQLException}.
374398
* </p>
375399
*/
376400
private static final class OracleR2dbcException
377401
extends R2dbcException {
378402
private OracleR2dbcException(
379-
String message, String sqlState, int errorCode,
403+
String message, String sqlState, int errorCode, String sql,
380404
SQLException sqlException) {
381-
super(message, sqlState, errorCode, sqlException);
405+
super(message, sqlState, errorCode, sql, sqlException);
382406
}
383407
}
384408

@@ -390,17 +414,18 @@ private OracleR2dbcException(
390414
* This subclass does implement any behavior that is specific to the
391415
* Oracle driver.
392416
* </p><p>
393-
* This subclass is defined so that {@link #toR2dbcException(SQLException)}
394-
* can throw an instance of {@code R2dbcTransientException} when mapping a
417+
* This subclass is defined so that
418+
* {@link #toR2dbcException(SQLException)} can throw an instance of
419+
* {@code R2dbcTransientException} when mapping a
395420
* {@link SQLTransientException}.
396421
* </p>
397422
*/
398423
private static final class OracleR2dbcTransientException
399424
extends R2dbcTransientException {
400425
private OracleR2dbcTransientException(
401-
String message, String sqlState, int errorCode,
426+
String message, String sqlState, int errorCode, String sql,
402427
SQLException sqlException) {
403-
super(message, sqlState, errorCode, sqlException);
428+
super(message, sqlState, errorCode, sql, sqlException);
404429
}
405430
}
406431

@@ -420,9 +445,9 @@ private OracleR2dbcTransientException(
420445
private static final class OracleR2dbcNonTransientException
421446
extends R2dbcNonTransientException {
422447
private OracleR2dbcNonTransientException(
423-
String message, String sqlState, int errorCode,
448+
String message, String sqlState, int errorCode, String sql,
424449
Throwable cause) {
425-
super(message, sqlState, errorCode, cause);
450+
super(message, sqlState, errorCode, sql, cause);
426451
}
427452
}
428453

src/main/java/oracle/r2dbc/impl/OracleReactiveJdbcAdapter.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ final class OracleReactiveJdbcAdapter implements ReactiveJdbcAdapter {
194194
// may need to be disabled when connecting to an 18.x database. Starting
195195
// in 19.x, the database can detect when it's running on a system where
196196
// OOB is not supported and automatically disable OOB. This automated
197-
// detection is not impleneted in 18.x.
197+
// detection is not implemented in 18.x.
198198
OracleR2dbcOptions.DISABLE_OUT_OF_BAND_BREAK,
199199

200200
// Allow the client-side ResultSet cache to be disabled. It is
@@ -247,7 +247,7 @@ static OracleReactiveJdbcAdapter getInstance() {
247247
* When the "descriptor" option is provided, it is invalid to specify any
248248
* other options that might conflict with values also specified in the
249249
* descriptor. For instance, the descriptor element of
250-
* {@code (ADDRESSS=(HOST=...)(PORT=...)(PROTOCOL=...))} specifies values
250+
* {@code (ADDRESS=(HOST=...)(PORT=...)(PROTOCOL=...))} specifies values
251251
* that overlap with the standard {@code Option}s of {@code HOST}, {@code
252252
* PORT}, and {@code SSL}. An {@code IllegalArgumentException} is thrown
253253
* when the descriptor is provided with any overlapping {@code Option}s.
@@ -1136,7 +1136,7 @@ private <T> T castAsType(Object object, Class<T> type) {
11361136
}
11371137
else {
11381138
throw OracleR2dbcExceptions.newNonTransientException(
1139-
object.getClass() + " is not an instance of " + type, null);
1139+
object.getClass() + " is not an instance of " + type, null, null);
11401140
}
11411141
}
11421142

@@ -1468,9 +1468,8 @@ private static final class AsyncLock {
14681468
new ConcurrentLinkedDeque<>();
14691469

14701470
/**
1471-
* Returns a {@code Publisher} that emits {@code onComplete} when
1472-
* this lock is acquired.
1473-
* @return
1471+
* Executes a {@code callback} with exclusive access to the guarded
1472+
* resource.
14741473
*/
14751474
void lock(Runnable callback) {
14761475
assert waitCount.get() >= 0 : "Wait count is less than 0: " + waitCount;

src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.nio.ByteBuffer;
4040
import java.sql.Timestamp;
4141
import java.time.LocalDateTime;
42+
import java.util.NoSuchElementException;
4243

4344
import static oracle.r2dbc.impl.OracleR2dbcExceptions.requireNonNull;
4445

@@ -121,8 +122,6 @@ static OutParameters createOutParameters(
121122
* into the specified {@code type}.
122123
* </p>
123124
* @throws IllegalArgumentException {@inheritDoc}
124-
* @throws IllegalArgumentException If the {@code index} is less than 0,
125-
* or greater than the maximum value index.
126125
* @throws IllegalArgumentException If conversion to the specified
127126
* {@code type} is not supported.
128127
*/
@@ -163,14 +162,14 @@ public <T> T get(String name, Class<T> type) {
163162
* matching values.
164163
* @param name The name of a value
165164
* @return The index of the named value within this {@code Readable}
166-
* @throws IllegalArgumentException If no column has a matching name.
165+
* @throws NoSuchElementException If no column has a matching name.
167166
*/
168167
private int indexOf(String name) {
169168
int columnIndex = readablesMetadata.getColumnIndex(name);
170169
if (columnIndex != -1)
171170
return columnIndex;
172171
else
173-
throw new IllegalArgumentException("Unrecognized name: " + name);
172+
throw new NoSuchElementException("Unrecognized name: " + name);
174173
}
175174

176175
/**
@@ -206,7 +205,13 @@ else if (LocalDateTime.class.equals(type)) {
206205
value = getLocalDateTime(index);
207206
}
208207
else if (Object.class.equals(type)) {
209-
value = convert(index, readablesMetadata.get(index).getJavaType());
208+
// Use the default type mapping if Object.class has been specified.
209+
// This method is invoked recursively with the default mapping, so long
210+
// as Object.class is not also the default mapping.
211+
Class<?> defaultType = readablesMetadata.get(index).getJavaType();
212+
value = Object.class.equals(defaultType)
213+
? jdbcReadable.getObject(index, Object.class)
214+
: convert(index, defaultType);
210215
}
211216
else {
212217
value = jdbcReadable.getObject(index, type);
@@ -323,14 +328,14 @@ private LocalDateTime getLocalDateTime(int index) {
323328
* for this row. This method is used to verify index value parameters
324329
* supplied by user code.
325330
* @param index 0-based column index
326-
* @throws IllegalStateException if the index is not valid.
331+
* @throws IndexOutOfBoundsException if the index is not valid.
327332
*/
328333
private void requireValidIndex(int index) {
329334
if (index < 0) {
330-
throw new IllegalArgumentException("Index is less than zero: " + index);
335+
throw new IndexOutOfBoundsException("Index is less than zero: " + index);
331336
}
332337
else if (index >= readablesMetadata.getList().size()) {
333-
throw new IllegalArgumentException(
338+
throw new IndexOutOfBoundsException(
334339
"Index " + index + " is greater than or equal to column count: "
335340
+ readablesMetadata.getList().size());
336341
}

src/main/java/oracle/r2dbc/impl/OracleReadableMetadataImpl.java

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -296,8 +296,16 @@ static ColumnMetadata createColumnMetadata(
296296
Nullability nullability = getNullability(fromJdbc(() ->
297297
resultSetMetaData.isNullable(jdbcIndex)));
298298

299-
if (type == R2dbcType.BLOB || type == R2dbcType.CLOB
300-
|| type == R2dbcType.NCLOB) {
299+
if (type == R2dbcType.NUMERIC) {
300+
// For NUMBER, allow the scale to be 0
301+
return new OracleColumnMetadataImpl(type, name, nullability,
302+
fromJdbc(() -> resultSetMetaData.getPrecision(jdbcIndex)),
303+
fromJdbc(() -> resultSetMetaData.getScale(jdbcIndex)));
304+
}
305+
if (type == R2dbcType.BLOB
306+
|| type == R2dbcType.CLOB
307+
|| type == R2dbcType.NCLOB
308+
|| type == OracleR2dbcTypes.JSON) {
301309
// For LOB types, use null as the precision. The actual maximum length
302310
// is (4GB x database-block-size), which can not be stored as an Integer
303311
return new OracleColumnMetadataImpl(type, name, nullability, null, null);
@@ -320,7 +328,7 @@ else if (type == R2dbcType.TIMESTAMP
320328
else if (type == R2dbcType.TIMESTAMP_WITH_TIME_ZONE) {
321329
// For the TIMESTAMP WITH TIMEZONE types, use the length of
322330
// OffsetDateTime.toString() as the precision. Use the scale from JDBC,
323-
// even if it's 0 because a TIMESTAMP may 0 decimal digits.
331+
// even if it's 0 because a TIMESTAMP may have 0 decimal digits.
324332
return new OracleColumnMetadataImpl(type, name, nullability,
325333
OFFSET_DATE_TIME_PRECISION,
326334
fromJdbc(() -> resultSetMetaData.getScale(jdbcIndex)));

src/main/java/oracle/r2dbc/impl/OracleResultImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,9 +586,18 @@ <T> Publisher<T> publishSegments(Function<Segment, T> mappingFunction) {
586586
*/
587587
private static final class WarningResult extends OracleResultImpl {
588588

589+
/** The warning of this result */
589590
private final SQLWarning warning;
591+
592+
/** The result that follows this result */
590593
private final OracleResultImpl result;
591594

595+
/**
596+
* Constructs a result that publishes a {@code warning} as a
597+
* {@link Message}, and then publishes the segments of a {@code result}.
598+
* @param warning Warning to publish
599+
* @param result Result of segments to publish after the warning
600+
*/
592601
private WarningResult(SQLWarning warning, OracleResultImpl result) {
593602
this.warning = warning;
594603
this.result = result;

0 commit comments

Comments
 (0)