From cedc054a90378a7ca7fb8741eb9ac464c9fa2223 Mon Sep 17 00:00:00 2001
From: Michael-A-McMahon
Date: Fri, 5 Nov 2021 17:16:18 -0700
Subject: [PATCH 1/9] Update pom. Throw IndexOutOfBoundsException
---
pom.xml | 2 +-
src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/pom.xml b/pom.xml
index d81d899..e52eb29 100755
--- a/pom.xml
+++ b/pom.xml
@@ -66,7 +66,7 @@
1121.3.0.0
- 0.9.0.M2
+ 0.9.0.RC13.3.0.RELEASE1.0.35.7.0
diff --git a/src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java b/src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java
index 7fe09f6..cb9808f 100755
--- a/src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java
+++ b/src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java
@@ -131,10 +131,10 @@ static OutParametersMetadataImpl createOutParametersMetadata(
*/
protected final T get(int index) {
if (index < 0) {
- throw new ArrayIndexOutOfBoundsException("Negative index: " + index);
+ throw new IndexOutOfBoundsException("Negative index: " + index);
}
else if (index >= metadataList.size()) {
- throw new ArrayIndexOutOfBoundsException(
+ throw new IndexOutOfBoundsException(
"Index " + index + " exceeds the maximum index: "
+ metadataList.size());
}
From 5327d4681d68581c42996f8d708a2c352a9ce639 Mon Sep 17 00:00:00 2001
From: Michael-A-McMahon
Date: Wed, 10 Nov 2021 15:52:13 -0800
Subject: [PATCH 2/9] Support R2dbcException.getSql()
---
.../r2dbc/impl/OracleR2dbcExceptions.java | 71 +++++++++++++------
.../r2dbc/impl/OracleReactiveJdbcAdapter.java | 11 ++-
.../oracle/r2dbc/impl/OracleResultImpl.java | 9 +++
.../r2dbc/impl/ReactiveJdbcAdapter.java | 4 +-
.../oracle/r2dbc/impl/ReadablesMetadata.java | 2 +-
.../r2dbc/impl/OracleR2dbcExceptionsTest.java | 3 +-
6 files changed, 67 insertions(+), 33 deletions(-)
diff --git a/src/main/java/oracle/r2dbc/impl/OracleR2dbcExceptions.java b/src/main/java/oracle/r2dbc/impl/OracleR2dbcExceptions.java
index 0819801..7afc72a 100755
--- a/src/main/java/oracle/r2dbc/impl/OracleR2dbcExceptions.java
+++ b/src/main/java/oracle/r2dbc/impl/OracleR2dbcExceptions.java
@@ -30,6 +30,7 @@
import io.r2dbc.spi.R2dbcTimeoutException;
import io.r2dbc.spi.R2dbcTransientException;
import io.r2dbc.spi.R2dbcTransientResourceException;
+import oracle.jdbc.OracleDatabaseException;
import java.sql.SQLException;
import java.sql.SQLIntegrityConstraintViolationException;
@@ -166,41 +167,42 @@ static R2dbcException toR2dbcException(SQLException sqlException) {
final String message = sqlException.getMessage();
final String sqlState = sqlException.getSQLState();
final int errorCode = sqlException.getErrorCode();
+ final String sql = getSql(sqlException);
if (sqlException instanceof SQLNonTransientException) {
if (sqlException instanceof SQLSyntaxErrorException) {
return new R2dbcBadGrammarException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
else if (sqlException instanceof SQLIntegrityConstraintViolationException) {
return new R2dbcDataIntegrityViolationException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
else if (sqlException instanceof SQLNonTransientConnectionException) {
return new R2dbcNonTransientResourceException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
else {
return new OracleR2dbcNonTransientException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
}
else if (sqlException instanceof SQLTransientException) {
if (sqlException instanceof SQLTimeoutException) {
return new R2dbcTimeoutException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
else if (sqlException instanceof SQLTransactionRollbackException) {
return new R2dbcRollbackException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
else if (sqlException instanceof SQLTransientConnectionException) {
return new R2dbcTransientResourceException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
else {
return new OracleR2dbcTransientException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
}
else if (sqlException instanceof SQLRecoverableException) {
@@ -209,11 +211,11 @@ else if (sqlException instanceof SQLRecoverableException) {
// the connection is no longer valid. The R2dbcTransientResourceException
// expresses the same conditions.
return new R2dbcTransientResourceException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
else {
return new OracleR2dbcException(
- message, sqlState, errorCode, sqlException);
+ message, sqlState, errorCode, sql, sqlException);
}
}
@@ -293,8 +295,30 @@ static T fromJdbc(ThrowingSupplier supplier)
* @return A new non-transient exception.
*/
static R2dbcNonTransientException newNonTransientException(
- String message, Throwable cause) {
- return new OracleR2dbcNonTransientException(message, null, 0, cause);
+ String message, String sql, Throwable cause) {
+ return new OracleR2dbcNonTransientException(message, null, 0, sql, cause);
+ }
+
+ /**
+ * Returns the SQL command that caused a {@code sqlException}, if it is
+ * available. This method is only implemented to support the case where the
+ * exception is caused by a {@link oracle.jdbc.OracleDatabaseException}.
+ * @param sqlException Exception to extract SQL from. Not null.
+ * @return The SQL that caused the {@code sqlException}, of {@code null} if
+ * the SQL is not available.
+ */
+ private static String getSql(SQLException sqlException) {
+ Throwable cause = sqlException.getCause();
+
+ while (cause != null) {
+
+ if (cause instanceof OracleDatabaseException)
+ return ((OracleDatabaseException)cause).getSql();
+
+ cause = cause.getCause();
+ }
+
+ return null;
}
/**
@@ -368,17 +392,17 @@ default T get() throws R2dbcException {
* concrete subclass must be defined. This subclass does not implement any
* behavior that is specific to the Oracle driver.
*
- * This subclass is defined so that {@link #toR2dbcException(SQLException)}
- * can throw an instance of {@code R2dbcException} when mapping a
- * {@link SQLException}.
+ * This subclass is defined so that
+ * {@link #toR2dbcException(SQLException)} can throw an instance of
+ * {@code R2dbcException} when mapping a {@link SQLException}.
*
*/
private static final class OracleR2dbcException
extends R2dbcException {
private OracleR2dbcException(
- String message, String sqlState, int errorCode,
+ String message, String sqlState, int errorCode, String sql,
SQLException sqlException) {
- super(message, sqlState, errorCode, sqlException);
+ super(message, sqlState, errorCode, sql, sqlException);
}
}
@@ -390,17 +414,18 @@ private OracleR2dbcException(
* This subclass does implement any behavior that is specific to the
* Oracle driver.
*
- * This subclass is defined so that {@link #toR2dbcException(SQLException)}
- * can throw an instance of {@code R2dbcTransientException} when mapping a
+ * This subclass is defined so that
+ * {@link #toR2dbcException(SQLException)} can throw an instance of
+ * {@code R2dbcTransientException} when mapping a
* {@link SQLTransientException}.
*
*/
private static final class OracleR2dbcTransientException
extends R2dbcTransientException {
private OracleR2dbcTransientException(
- String message, String sqlState, int errorCode,
+ String message, String sqlState, int errorCode, String sql,
SQLException sqlException) {
- super(message, sqlState, errorCode, sqlException);
+ super(message, sqlState, errorCode, sql, sqlException);
}
}
@@ -420,9 +445,9 @@ private OracleR2dbcTransientException(
private static final class OracleR2dbcNonTransientException
extends R2dbcNonTransientException {
private OracleR2dbcNonTransientException(
- String message, String sqlState, int errorCode,
+ String message, String sqlState, int errorCode, String sql,
Throwable cause) {
- super(message, sqlState, errorCode, cause);
+ super(message, sqlState, errorCode, sql, cause);
}
}
diff --git a/src/main/java/oracle/r2dbc/impl/OracleReactiveJdbcAdapter.java b/src/main/java/oracle/r2dbc/impl/OracleReactiveJdbcAdapter.java
index 36ac0f7..d0f299b 100755
--- a/src/main/java/oracle/r2dbc/impl/OracleReactiveJdbcAdapter.java
+++ b/src/main/java/oracle/r2dbc/impl/OracleReactiveJdbcAdapter.java
@@ -194,7 +194,7 @@ final class OracleReactiveJdbcAdapter implements ReactiveJdbcAdapter {
// may need to be disabled when connecting to an 18.x database. Starting
// in 19.x, the database can detect when it's running on a system where
// OOB is not supported and automatically disable OOB. This automated
- // detection is not impleneted in 18.x.
+ // detection is not implemented in 18.x.
OracleR2dbcOptions.DISABLE_OUT_OF_BAND_BREAK,
// Allow the client-side ResultSet cache to be disabled. It is
@@ -247,7 +247,7 @@ static OracleReactiveJdbcAdapter getInstance() {
* When the "descriptor" option is provided, it is invalid to specify any
* other options that might conflict with values also specified in the
* descriptor. For instance, the descriptor element of
- * {@code (ADDRESSS=(HOST=...)(PORT=...)(PROTOCOL=...))} specifies values
+ * {@code (ADDRESS=(HOST=...)(PORT=...)(PROTOCOL=...))} specifies values
* that overlap with the standard {@code Option}s of {@code HOST}, {@code
* PORT}, and {@code SSL}. An {@code IllegalArgumentException} is thrown
* when the descriptor is provided with any overlapping {@code Option}s.
@@ -1136,7 +1136,7 @@ private T castAsType(Object object, Class type) {
}
else {
throw OracleR2dbcExceptions.newNonTransientException(
- object.getClass() + " is not an instance of " + type, null);
+ object.getClass() + " is not an instance of " + type, null, null);
}
}
@@ -1468,9 +1468,8 @@ private static final class AsyncLock {
new ConcurrentLinkedDeque<>();
/**
- * Returns a {@code Publisher} that emits {@code onComplete} when
- * this lock is acquired.
- * @return
+ * Executes a {@code callback} with exclusive access to the guarded
+ * resource.
*/
void lock(Runnable callback) {
assert waitCount.get() >= 0 : "Wait count is less than 0: " + waitCount;
diff --git a/src/main/java/oracle/r2dbc/impl/OracleResultImpl.java b/src/main/java/oracle/r2dbc/impl/OracleResultImpl.java
index 5f58c3a..5c8af89 100644
--- a/src/main/java/oracle/r2dbc/impl/OracleResultImpl.java
+++ b/src/main/java/oracle/r2dbc/impl/OracleResultImpl.java
@@ -586,9 +586,18 @@ Publisher publishSegments(Function mappingFunction) {
*/
private static final class WarningResult extends OracleResultImpl {
+ /** The warning of this result */
private final SQLWarning warning;
+
+ /** The result that follows this result */
private final OracleResultImpl result;
+ /**
+ * Constructs a result that publishes a {@code warning} as a
+ * {@link Message}, and then publishes the segments of a {@code result}.
+ * @param warning Warning to publish
+ * @param result Result of segments to publish after the warning
+ */
private WarningResult(SQLWarning warning, OracleResultImpl result) {
this.warning = warning;
this.result = result;
diff --git a/src/main/java/oracle/r2dbc/impl/ReactiveJdbcAdapter.java b/src/main/java/oracle/r2dbc/impl/ReactiveJdbcAdapter.java
index 3bef388..1bb9e78 100755
--- a/src/main/java/oracle/r2dbc/impl/ReactiveJdbcAdapter.java
+++ b/src/main/java/oracle/r2dbc/impl/ReactiveJdbcAdapter.java
@@ -95,7 +95,7 @@ static ReactiveJdbcAdapter getOracleAdapter() throws R2dbcException {
}
catch (SQLException getDriverException) {
throw OracleR2dbcExceptions.newNonTransientException(
- "Failed to locate the Oracle JDBC Driver", getDriverException);
+ "Failed to locate the Oracle JDBC Driver", null, getDriverException);
}
return OracleReactiveJdbcAdapter.getInstance();
@@ -107,7 +107,7 @@ static ReactiveJdbcAdapter getOracleAdapter() throws R2dbcException {
* the {@code options} parameter. Adapters implementing this method return a
* {@code DataSource} that is supported as an argument to their
* implementation of
- * {@link ReactiveJdbcAdapter#publishConnection(DataSource)}.
+ * {@link ReactiveJdbcAdapter#publishConnection(DataSource, Executor)}.
*
* Adapters implementing this method must specify each supported value
* of {@link ConnectionFactoryOptions}, how the value of each option is
diff --git a/src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java b/src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java
index cb9808f..eeb3192 100755
--- a/src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java
+++ b/src/main/java/oracle/r2dbc/impl/ReadablesMetadata.java
@@ -123,7 +123,7 @@ static OutParametersMetadataImpl createOutParametersMetadata(
* @param index the value index starting at 0
* @return the {@link ReadableMetadata} for one value in this result. Not
* null.
- * @throws ArrayIndexOutOfBoundsException if the {@code index} is less than
+ * @throws IndexOutOfBoundsException if the {@code index} is less than
* zero or greater than the number of available values.
* @implSpec This method implements common behavior specified for both
* {@link RowMetadata#getColumnMetadata(int)} and
diff --git a/src/test/java/oracle/r2dbc/impl/OracleR2dbcExceptionsTest.java b/src/test/java/oracle/r2dbc/impl/OracleR2dbcExceptionsTest.java
index ce22af1..b0ae67f 100644
--- a/src/test/java/oracle/r2dbc/impl/OracleR2dbcExceptionsTest.java
+++ b/src/test/java/oracle/r2dbc/impl/OracleR2dbcExceptionsTest.java
@@ -145,7 +145,8 @@ public void testNewNonTransientException() {
"SQL-MESSAGE", "SQL-STATE", 9, ioException);
String message = "MESSAGE";
R2dbcNonTransientException r2dbcException =
- OracleR2dbcExceptions.newNonTransientException(message, sqlException);
+ OracleR2dbcExceptions.newNonTransientException(
+ message, null, sqlException);
// Expect the R2dbcException to have the same message
assertSame(message, r2dbcException.getMessage());
From ea93daf00515265397d8cf5ffde5fda5fc127187 Mon Sep 17 00:00:00 2001
From: Michael-A-McMahon
Date: Wed, 10 Nov 2021 16:05:08 -0800
Subject: [PATCH 3/9] Add test for R2dbcException.getSql()
---
.../r2dbc/impl/OracleR2dbcExceptionsTest.java | 2 +-
.../r2dbc/impl/OracleStatementImplTest.java | 19 +++++++++++++++++++
2 files changed, 20 insertions(+), 1 deletion(-)
diff --git a/src/test/java/oracle/r2dbc/impl/OracleR2dbcExceptionsTest.java b/src/test/java/oracle/r2dbc/impl/OracleR2dbcExceptionsTest.java
index b0ae67f..178dbc9 100644
--- a/src/test/java/oracle/r2dbc/impl/OracleR2dbcExceptionsTest.java
+++ b/src/test/java/oracle/r2dbc/impl/OracleR2dbcExceptionsTest.java
@@ -136,7 +136,7 @@ public void testRunOrHandleSqlException() {
/**
* Verifies the implementation of
- * {@link OracleR2dbcExceptions#newNonTransientException(String, Throwable)}
+ * {@link OracleR2dbcExceptions#newNonTransientException(String, String, Throwable)}
*/
@Test
public void testNewNonTransientException() {
diff --git a/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java b/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java
index 06d341a..b6794ef 100644
--- a/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java
+++ b/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java
@@ -2211,6 +2211,25 @@ public void testUsingWhenCancel() {
}
}
+ /**
+ * Verifies that {@link R2dbcException#getSql()} returns the SQL command
+ * that caused an exception.
+ */
+ @Test
+ public void testGetSql() {
+ Connection connection = awaitOne(sharedConnection());
+ try {
+ String badSql = "SELECT 0 FROM dooool";
+ Result result = awaitOne(connection.createStatement(badSql).execute());
+ R2dbcException r2dbcException = assertThrows(R2dbcException.class, () ->
+ awaitOne(result.getRowsUpdated()));
+ assertEquals(badSql, r2dbcException.getSql());
+ }
+ finally {
+ tryAwaitNone(connection.close());
+ }
+ }
+
// TODO: Repalce with Parameters.inOut when that's available
private static final class InOutParameter
implements Parameter, Parameter.In, Parameter.Out {
From bfca03898d37c6d378e2edf9ebf7cb414815238c Mon Sep 17 00:00:00 2001
From: Michael-A-McMahon
Date: Wed, 10 Nov 2021 18:03:30 -0800
Subject: [PATCH 4/9] Fix metadata for JSON columns
---
src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java | 8 +++++++-
src/main/java/oracle/r2dbc/impl/SqlTypeMap.java | 3 ++-
2 files changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java b/src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java
index 88c8d2e..ae4b048 100755
--- a/src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java
+++ b/src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java
@@ -206,7 +206,13 @@ else if (LocalDateTime.class.equals(type)) {
value = getLocalDateTime(index);
}
else if (Object.class.equals(type)) {
- value = convert(index, readablesMetadata.get(index).getJavaType());
+ // Use the default type mapping if Object.class has been specified.
+ // This method is invoked recursively with the default mapping, so long
+ // as Object.class is not also the default mapping.
+ Class> defaultType = readablesMetadata.get(index).getJavaType();
+ value = Object.class.equals(defaultType)
+ ? jdbcReadable.getObject(index, Object.class)
+ : convert(index, defaultType);
}
else {
value = jdbcReadable.getObject(index, type);
diff --git a/src/main/java/oracle/r2dbc/impl/SqlTypeMap.java b/src/main/java/oracle/r2dbc/impl/SqlTypeMap.java
index 5d8f862..b0ecd74 100644
--- a/src/main/java/oracle/r2dbc/impl/SqlTypeMap.java
+++ b/src/main/java/oracle/r2dbc/impl/SqlTypeMap.java
@@ -55,6 +55,7 @@ final class SqlTypeMap {
*/
private static final Map JDBC_TO_R2DBC_TYPE_MAP =
Map.ofEntries(
+ entry(JDBCType.ARRAY, R2dbcType.COLLECTION),
entry(JDBCType.BIGINT, R2dbcType.BIGINT),
entry(JDBCType.BINARY, R2dbcType.BINARY),
entry(OracleType.BINARY_DOUBLE, OracleR2dbcTypes.BINARY_DOUBLE),
@@ -63,7 +64,6 @@ final class SqlTypeMap {
entry(JDBCType.BOOLEAN, R2dbcType.BOOLEAN),
entry(JDBCType.CHAR, R2dbcType.CHAR),
entry(JDBCType.CLOB, R2dbcType.CLOB),
- entry(JDBCType.ARRAY, R2dbcType.COLLECTION),
entry(JDBCType.DATE, R2dbcType.DATE),
entry(JDBCType.DECIMAL, R2dbcType.DECIMAL),
entry(JDBCType.DOUBLE, R2dbcType.DOUBLE),
@@ -75,6 +75,7 @@ final class SqlTypeMap {
entry(
OracleType.INTERVAL_YEAR_TO_MONTH,
OracleR2dbcTypes.INTERVAL_YEAR_TO_MONTH),
+ entry(OracleType.JSON, OracleR2dbcTypes.JSON),
entry(JDBCType.LONGVARBINARY, OracleR2dbcTypes.LONG_RAW),
entry(JDBCType.LONGVARCHAR, OracleR2dbcTypes.LONG),
entry(JDBCType.NCHAR, R2dbcType.NCHAR),
From 1e90b9df50c5c4cf19e34e7f4c5da76fbc4ca22e Mon Sep 17 00:00:00 2001
From: Michael-A-McMahon
Date: Wed, 10 Nov 2021 18:57:19 -0800
Subject: [PATCH 5/9] Update exception types.
---
.../oracle/r2dbc/impl/OracleReadableImpl.java | 13 +++---
.../impl/OracleReadableMetadataImpl.java | 8 ++--
.../r2dbc/impl/OracleStatementImpl.java | 5 ++-
.../r2dbc/impl/OracleReadableImplTest.java | 45 ++++++++++---------
.../r2dbc/impl/OracleRowMetadataImplTest.java | 4 +-
.../r2dbc/impl/OracleStatementImplTest.java | 26 +++++------
6 files changed, 51 insertions(+), 50 deletions(-)
diff --git a/src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java b/src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java
index ae4b048..3288860 100755
--- a/src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java
+++ b/src/main/java/oracle/r2dbc/impl/OracleReadableImpl.java
@@ -39,6 +39,7 @@
import java.nio.ByteBuffer;
import java.sql.Timestamp;
import java.time.LocalDateTime;
+import java.util.NoSuchElementException;
import static oracle.r2dbc.impl.OracleR2dbcExceptions.requireNonNull;
@@ -121,8 +122,6 @@ static OutParameters createOutParameters(
* into the specified {@code type}.
*
* @throws IllegalArgumentException {@inheritDoc}
- * @throws IllegalArgumentException If the {@code index} is less than 0,
- * or greater than the maximum value index.
* @throws IllegalArgumentException If conversion to the specified
* {@code type} is not supported.
*/
@@ -163,14 +162,14 @@ public T get(String name, Class type) {
* matching values.
* @param name The name of a value
* @return The index of the named value within this {@code Readable}
- * @throws IllegalArgumentException If no column has a matching name.
+ * @throws NoSuchElementException If no column has a matching name.
*/
private int indexOf(String name) {
int columnIndex = readablesMetadata.getColumnIndex(name);
if (columnIndex != -1)
return columnIndex;
else
- throw new IllegalArgumentException("Unrecognized name: " + name);
+ throw new NoSuchElementException("Unrecognized name: " + name);
}
/**
@@ -329,14 +328,14 @@ private LocalDateTime getLocalDateTime(int index) {
* for this row. This method is used to verify index value parameters
* supplied by user code.
* @param index 0-based column index
- * @throws IllegalStateException if the index is not valid.
+ * @throws IndexOutOfBoundsException if the index is not valid.
*/
private void requireValidIndex(int index) {
if (index < 0) {
- throw new IllegalArgumentException("Index is less than zero: " + index);
+ throw new IndexOutOfBoundsException("Index is less than zero: " + index);
}
else if (index >= readablesMetadata.getList().size()) {
- throw new IllegalArgumentException(
+ throw new IndexOutOfBoundsException(
"Index " + index + " is greater than or equal to column count: "
+ readablesMetadata.getList().size());
}
diff --git a/src/main/java/oracle/r2dbc/impl/OracleReadableMetadataImpl.java b/src/main/java/oracle/r2dbc/impl/OracleReadableMetadataImpl.java
index da3c942..5f2d493 100755
--- a/src/main/java/oracle/r2dbc/impl/OracleReadableMetadataImpl.java
+++ b/src/main/java/oracle/r2dbc/impl/OracleReadableMetadataImpl.java
@@ -320,7 +320,7 @@ else if (type == R2dbcType.TIMESTAMP
else if (type == R2dbcType.TIMESTAMP_WITH_TIME_ZONE) {
// For the TIMESTAMP WITH TIMEZONE types, use the length of
// OffsetDateTime.toString() as the precision. Use the scale from JDBC,
- // even if it's 0 because a TIMESTAMP may 0 decimal digits.
+ // even if it's 0 because a TIMESTAMP may have 0 decimal digits.
return new OracleColumnMetadataImpl(type, name, nullability,
OFFSET_DATE_TIME_PRECISION,
fromJdbc(() -> resultSetMetaData.getScale(jdbcIndex)));
@@ -352,10 +352,10 @@ else if (type == R2dbcType.VARBINARY) {
return new OracleColumnMetadataImpl(
type, name, nullability,
- // The getPrecision and getScale methods return 0 for types where
+ // The getPrecision and getScale methods return 0 or -1 for types where
// precision and scale are not applicable.
- precision == 0 ? null : precision,
- scale == 0 ? null : scale);
+ precision < 1 ? null : precision,
+ scale < 1 ? null : scale);
}
}
diff --git a/src/main/java/oracle/r2dbc/impl/OracleStatementImpl.java b/src/main/java/oracle/r2dbc/impl/OracleStatementImpl.java
index 74e2cd4..9d9bd00 100755
--- a/src/main/java/oracle/r2dbc/impl/OracleStatementImpl.java
+++ b/src/main/java/oracle/r2dbc/impl/OracleStatementImpl.java
@@ -45,6 +45,7 @@
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
+import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -533,7 +534,7 @@ else if (generatedColumns != null)
* {@code name}. The match is case-sensitive.
* @param name A parameter name. Not null.
* @param value A value to bind. May be null.
- * @throws IllegalArgumentException if no named parameter matches the
+ * @throws NoSuchElementException if no named parameter matches the
* {@code identifier}
*/
private void bindNamedParameter(String name, Object value) {
@@ -547,7 +548,7 @@ private void bindNamedParameter(String name, Object value) {
}
if (! isMatched) {
- throw new IllegalArgumentException(
+ throw new NoSuchElementException(
"Unrecognized parameter identifier: " + name);
}
}
diff --git a/src/test/java/oracle/r2dbc/impl/OracleReadableImplTest.java b/src/test/java/oracle/r2dbc/impl/OracleReadableImplTest.java
index 49f9b44..f8b06fc 100644
--- a/src/test/java/oracle/r2dbc/impl/OracleReadableImplTest.java
+++ b/src/test/java/oracle/r2dbc/impl/OracleReadableImplTest.java
@@ -26,6 +26,7 @@
import reactor.core.publisher.Mono;
import java.math.BigDecimal;
+import java.util.NoSuchElementException;
import static java.util.Arrays.asList;
import static oracle.r2dbc.test.DatabaseConfig.connectTimeout;
@@ -61,17 +62,17 @@ public void testGetByIndex() {
awaitUpdate(1, connection.createStatement(
"INSERT INTO testGetByIndex (x,y) VALUES (0,1)"));
- // Expect IllegalArgumentException for an index less than 0
- awaitError(IllegalArgumentException.class,
+ // Expect IndexOutOfBoundsException for an index less than 0
+ awaitError(IndexOutOfBoundsException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByIndex")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get(-1))));
- // Expect IllegalArgumentException for an index greater than or equal
+ // Expect IndexOutOfBoundsException for an index greater than or equal
// to the number of columns
- awaitError(IllegalArgumentException.class,
+ awaitError(IndexOutOfBoundsException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByIndex")
.execute())
@@ -137,38 +138,38 @@ public void testGetByName() {
.concatMap(result ->
result.map((row, metadata) -> row.get(null))));
- // Expect IllegalArgumentException for unmatched names
- awaitError(IllegalArgumentException.class,
+ // Expect NoSuchElementException for unmatched names
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByName")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get("z"))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByName")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get("xx"))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByName")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get("x "))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByName")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get(" x"))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByName")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get(" "))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByName")
.execute())
@@ -303,17 +304,17 @@ class Unsupported {}
result.map((row, metadata) ->
row.get(0, Unsupported.class))));
- // Expect IllegalArgumentException for an index less than 0
- awaitError(IllegalArgumentException.class,
+ // Expect IndexOutOfBoundsException for an index less than 0
+ awaitError(IndexOutOfBoundsException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByIndexAndType")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get(-1, Integer.class))));
- // Expect IllegalArgumentException for an index greater than or equal
+ // Expect IndexOutOfBoundsException for an index greater than or equal
// to the number of columns
- awaitError(IllegalArgumentException.class,
+ awaitError(IndexOutOfBoundsException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByIndexAndType")
.execute())
@@ -400,38 +401,38 @@ class Unsupported {}
.concatMap(result ->
result.map((row, metadata) -> row.get(null, Integer.class))));
- // Expect IllegalArgumentException for unmatched names
- awaitError(IllegalArgumentException.class,
+ // Expect NoSuchElementException for unmatched names
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByNameAndType")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get("z", Integer.class))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByNameAndType")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get("xx", Integer.class))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByNameAndType")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get("x ", Integer.class))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByNameAndType")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get(" x", Integer.class))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByNameAndType")
.execute())
.concatMap(result ->
result.map((row, metadata) -> row.get(" ", Integer.class))));
- awaitError(IllegalArgumentException.class,
+ awaitError(NoSuchElementException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetByNameAndType")
.execute())
diff --git a/src/test/java/oracle/r2dbc/impl/OracleRowMetadataImplTest.java b/src/test/java/oracle/r2dbc/impl/OracleRowMetadataImplTest.java
index 33c2beb..06211a4 100644
--- a/src/test/java/oracle/r2dbc/impl/OracleRowMetadataImplTest.java
+++ b/src/test/java/oracle/r2dbc/impl/OracleRowMetadataImplTest.java
@@ -80,7 +80,7 @@ public void testGetColumnMetadataByIndex() {
"INSERT INTO testGetColumnMetadataByIndex (x,y) VALUES (0,0)"));
// Expect IllegalArgumentException for an index less than 0
- awaitError(ArrayIndexOutOfBoundsException.class,
+ awaitError(IndexOutOfBoundsException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetColumnMetadataByIndex")
.execute())
@@ -90,7 +90,7 @@ public void testGetColumnMetadataByIndex() {
// Expect IllegalArgumentException for an index greater than or equal
// to the number of columns
- awaitError(ArrayIndexOutOfBoundsException.class,
+ awaitError(IndexOutOfBoundsException.class,
Flux.from(connection.createStatement(
"SELECT x, y FROM testGetColumnMetadataByIndex")
.execute())
diff --git a/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java b/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java
index b6794ef..e1a7160 100644
--- a/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java
+++ b/src/test/java/oracle/r2dbc/impl/OracleStatementImplTest.java
@@ -36,11 +36,11 @@
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
-import java.math.BigDecimal;
import java.sql.RowId;
import java.sql.SQLWarning;
import java.util.Collections;
import java.util.List;
+import java.util.NoSuchElementException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
@@ -264,21 +264,21 @@ class UnsupportedType {
IllegalArgumentException.class,
() -> statement.bind("x", new UnsupportedType()));
- // Expect IllegalArgumentException for an unmatched identifier
+ // Expect NoSuchElementException for an unmatched identifier
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() -> statement.bind("z", 1));
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() -> statement.bind("xx", 1));
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() -> statement.bind("", 1));
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() -> statement.bind("X", 1));
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() ->
connection.createStatement("SELECT x FROM testBindByIndex")
.bind("x", 0));
@@ -544,21 +544,21 @@ public void testBindNullByName() {
IllegalArgumentException.class,
() -> selectStatement.bindNull(null, Integer.class));
- // Expect IllegalArgumentException for an unmatched identifier
+ // Expect NoSuchElementException for an unmatched identifier
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() -> selectStatement.bindNull("z", Integer.class));
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() -> selectStatement.bindNull("xx", Integer.class));
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() -> selectStatement.bindNull("", Integer.class));
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() -> selectStatement.bindNull("X", Integer.class));
assertThrows(
- IllegalArgumentException.class,
+ NoSuchElementException.class,
() ->
connection.createStatement("SELECT x FROM testBindByIndex")
.bind("x", 0));
From 546a35ba486350e0ca2efae27a8a98878e6a5979 Mon Sep 17 00:00:00 2001
From: Michael-A-McMahon
Date: Thu, 11 Nov 2021 13:23:37 -0800
Subject: [PATCH 6/9] Remove support for trailing add()s
---
.../r2dbc/impl/OracleStatementImpl.java | 16 +++++++-------
.../r2dbc/impl/OracleConnectionImplTest.java | 6 +++--
.../r2dbc/impl/OracleResultImplTest.java | 2 +-
.../r2dbc/impl/OracleStatementImplTest.java | 22 ++++++++++---------
.../oracle/r2dbc/impl/TypeMappingTest.java | 2 +-
.../java/oracle/r2dbc/test/OracleTestKit.java | 14 ++++++++++--
6 files changed, 38 insertions(+), 24 deletions(-)
diff --git a/src/main/java/oracle/r2dbc/impl/OracleStatementImpl.java b/src/main/java/oracle/r2dbc/impl/OracleStatementImpl.java
index 9d9bd00..0555090 100755
--- a/src/main/java/oracle/r2dbc/impl/OracleStatementImpl.java
+++ b/src/main/java/oracle/r2dbc/impl/OracleStatementImpl.java
@@ -1092,10 +1092,9 @@ private Publisher executeGeneratingValues() {
/**
*
* Executes this {@code Statement} as a batch DML command. The returned
- * {@code Publisher} emits 1 {@code Result} for each set of bind values in
- * this {@code Statement}'s {@link #batch}. Each {@code Result} has an
- * update count and no row data. Update counts are floored to a maximum of
- * {@link Integer#MAX_VALUE}.
+ * {@code Publisher} emits 1 {@code Result} having a
+ * {@link io.r2dbc.spi.Result.UpdateCount} segment for each set of bind
+ * values in the {@link #batch}.
*
* This method copies any mutable state of this {@code Statement} needed to
* execute the batch; Any mutations that occur after this method returns will
@@ -1108,14 +1107,14 @@ private Publisher executeGeneratingValues() {
* subscriber subscribes, before the subscriber emits a {@code request}
* signal.
*
- * @return {@code Publisher} that the {@code Result}s of executing this
+ * @return {@code Publisher} that emits the {@code Result}s of executing this
* {@code Statement} as a batch DML command.
* @throws IllegalStateException If this {@code Statement} has been
* configured to return generated values with
* {@link #returnGeneratedValues(String...)}. Oracle JDBC does not support
* batch execution that returns generated keys.
- * @throws IllegalStateException If at least one parameter has been set
- * since the last call to {@link #add()}, but not all parameters have been set
+ * @throws IllegalStateException If not all parameters have been set since the
+ * last call to {@link #add()}
* @throws IllegalStateException If all parameters have been set since the
* last call to {@link #add()}, and an out parameter is present. JDBC does
* not support batch execution with out parameters.
@@ -1127,7 +1126,8 @@ Publisher executeBatch() {
"Batch execution with generated values is not supported");
}
- addImplicit();
+
+ add(); // TODO: Catch and emit IllegalStateException as R2dbcException?
Queue