Skip to content

Commit 45bc3bf

Browse files
Adding OracleR2dbcWarning
1 parent e8fc172 commit 45bc3bf

File tree

3 files changed

+153
-0
lines changed

3 files changed

+153
-0
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package oracle.r2dbc;
2+
3+
import io.r2dbc.spi.R2dbcException;
4+
import io.r2dbc.spi.Result;
5+
6+
import java.sql.SQLWarning;
7+
import java.util.function.Function;
8+
import java.util.function.Predicate;
9+
10+
import static io.r2dbc.spi.Result.*;
11+
12+
/**
13+
* <p>
14+
* An exception that provides information on warnings raised by Oracle Database.
15+
* </p><p>
16+
* When a SQL command results in a warning, Oracle R2DBC generates
17+
* {@link Message} segments having an {@code OracleR2dbcWarning} as the
18+
* {@linkplain Message#exception() exception}. These segments may be consumed
19+
* with {@link Result#flatMap(Function)}:
20+
* </p><pre>{@code
21+
* result.flatMap(segment -> {
22+
* if (OracleR2dbcWarning.isWarning(segment)) {
23+
* logWarning(OracleR2dbcWarning.getWarning(segment));
24+
* return emptyPublisher();
25+
* }
26+
* else {
27+
* ... handle other segment types ...
28+
* }
29+
* })
30+
* }</pre><p>
31+
* Alternatively, these segments may be ignored using
32+
* {@link Result#filter(Predicate)}:
33+
* </p> <pre>{@code
34+
* result.filter(segment -> !OracleR2dbcWarning.isWarning(segment))
35+
* }</pre>
36+
* If these segments are not flat-mapped or filtered from a {@code Result}, then
37+
* an {@code onError} signal with the {@code OracleR2dbcWarning} is emitted
38+
* </p>
39+
*/
40+
public class OracleR2dbcWarning extends R2dbcException {
41+
42+
/**
43+
* Constructs a new warning having a {@code SQLWarning} from JDBC as its
44+
* cause. The constructed warning has the same message, SQL state, and error
45+
* code as the given {@code SQLWarning}.
46+
* @param sql The SQL command that resulted in a warning. May be null.
47+
* @param sqlWarning The SQLWarning thrown by JDBC. Not null.
48+
*/
49+
public OracleR2dbcWarning(String sql, SQLWarning sqlWarning) {
50+
super(sqlWarning.getMessage(), sqlWarning.getSQLState(),
51+
sqlWarning.getErrorCode(), sql, sqlWarning);
52+
}
53+
54+
/**
55+
* Checks if a segment is a {@link Message} having an
56+
* {@code OracleR2dbcException} as an
57+
* {@linkplain Message#exception() exception}.
58+
* @param segment Segment to check. May be null, in which case {@code false}
59+
* is returned.
60+
* @return {@code true} if the segment is a {@code Message} with an
61+
* {@code OracleR2dbcException}, or {@code false} if not.
62+
*/
63+
public static boolean isWarning(Segment segment) {
64+
return segment instanceof Message
65+
&& ((Message)segment).exception() instanceof OracleR2dbcWarning;
66+
}
67+
68+
/**
69+
* Returns the {@code OracleR2dbcWarning} of a {@link Message} segment. This
70+
* method should only be called if {@link #isWarning(Segment)} returned
71+
* {@code true} for the given segment.
72+
* @param segment A {@code Message} segment with an
73+
* {@code OracleR2dbcWarning}. Not null.
74+
* @return The {@code OracleR2dbcWarning} of the {@code Message} segment.
75+
* @throws IllegalArgumentException If the segment is not a {@code Message}
76+
* with an {@code OracleR2dbcWarning}.
77+
*/
78+
public static OracleR2dbcWarning getWarning(Segment segment) {
79+
if (!isWarning(segment)) {
80+
throw new IllegalArgumentException(
81+
"Not a Message segment with an OracleR2dbcWarning: " + segment);
82+
}
83+
84+
return (OracleR2dbcWarning)((Message)segment).exception();
85+
}
86+
87+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import io.r2dbc.spi.R2dbcTransientException;
3232
import io.r2dbc.spi.R2dbcTransientResourceException;
3333
import oracle.jdbc.OracleDatabaseException;
34+
import oracle.r2dbc.OracleR2dbcWarning;
3435

3536
import java.sql.SQLException;
3637
import java.sql.SQLIntegrityConstraintViolationException;
@@ -42,6 +43,7 @@
4243
import java.sql.SQLTransactionRollbackException;
4344
import java.sql.SQLTransientConnectionException;
4445
import java.sql.SQLTransientException;
46+
import java.sql.SQLWarning;
4547
import java.util.function.Supplier;
4648

4749
/**
@@ -214,6 +216,9 @@ else if (sqlException instanceof SQLRecoverableException) {
214216
return new R2dbcTransientResourceException(
215217
message, sqlState, errorCode, sql, sqlException);
216218
}
219+
else if (sqlException instanceof SQLWarning) {
220+
return new OracleR2dbcWarning(sql, (SQLWarning)sqlException);
221+
}
217222
else {
218223
return new OracleR2dbcException(
219224
message, sqlState, errorCode, sql, sqlException);

src/test/java/oracle/r2dbc/impl/OracleResultImplTest.java

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
import io.r2dbc.spi.Result.UpdateCount;
2929
import io.r2dbc.spi.Row;
3030
import io.r2dbc.spi.RowMetadata;
31+
import io.r2dbc.spi.Statement;
32+
import oracle.r2dbc.OracleR2dbcWarning;
3133
import org.junit.jupiter.api.Test;
3234
import org.reactivestreams.Publisher;
3335
import reactor.core.publisher.Flux;
@@ -55,6 +57,9 @@
5557
import static oracle.r2dbc.util.Awaits.tryAwaitExecution;
5658
import static oracle.r2dbc.util.Awaits.tryAwaitNone;
5759
import static org.junit.jupiter.api.Assertions.assertEquals;
60+
import static org.junit.jupiter.api.Assertions.assertFalse;
61+
import static org.junit.jupiter.api.Assertions.assertInstanceOf;
62+
import static org.junit.jupiter.api.Assertions.assertSame;
5863
import static org.junit.jupiter.api.Assertions.assertThrows;
5964
import static org.junit.jupiter.api.Assertions.assertTrue;
6065
import static org.junit.jupiter.api.Assertions.fail;
@@ -624,4 +629,60 @@ else if (index == 1) {
624629
}
625630
}
626631

632+
/**
633+
* Verifies that a warnings are emitted as {@code Message} segments with an
634+
* {@link oracle.r2dbc.OracleR2dbcWarning}.
635+
*/
636+
@Test
637+
public void testOracleR2dbcWarning() {
638+
Connection connection = awaitOne(sharedConnection());
639+
try {
640+
641+
// Expect a warning for forcing a view that references a non-existant
642+
// table
643+
String sql = "CREATE OR REPLACE FORCE VIEW testOracleR2dbcWarning AS" +
644+
" SELECT x FROM thisdoesnotexist";
645+
Statement warningStatement = connection.createStatement(sql);
646+
647+
// Collect the segments
648+
List<Result.Segment> segments =
649+
awaitMany(Flux.from(warningStatement.execute())
650+
.flatMap(result -> result.flatMap(Mono::just)));
651+
652+
// Expect the update count segment first. Warnings are always emitted
653+
// after any result values.
654+
Result.Segment firstSegment = segments.get(0);
655+
assertEquals(0,
656+
assertInstanceOf(UpdateCount.class, firstSegment).value());
657+
assertFalse(OracleR2dbcWarning.isWarning(firstSegment));
658+
assertThrows(IllegalArgumentException.class, () ->
659+
OracleR2dbcWarning.getWarning(firstSegment));
660+
661+
// Expect the message segment next. Expect it to have the fixed message
662+
// and error number used by Oracle JDBC for all warnings.
663+
Result.Segment secondSegment = segments.get(1);
664+
Message message = assertInstanceOf(Message.class, secondSegment);
665+
assertEquals(
666+
message.message(), "Warning: execution completed with warning");
667+
assertEquals(message.errorCode(), 17110);
668+
assertEquals("", message.sqlState());
669+
OracleR2dbcWarning warning =
670+
assertInstanceOf(OracleR2dbcWarning.class, message.exception());
671+
assertEquals(message.message(), warning.getMessage());
672+
assertEquals(message.errorCode(), warning.getErrorCode());
673+
assertEquals(message.sqlState(), warning.getSqlState());
674+
assertEquals(sql, warning.getSql());
675+
assertTrue(OracleR2dbcWarning.isWarning(secondSegment));
676+
assertSame(warning, OracleR2dbcWarning.getWarning(secondSegment));
677+
678+
// Verify that there are not any more segments
679+
assertEquals(2, segments.size());
680+
}
681+
finally {
682+
tryAwaitExecution(
683+
connection.createStatement("DROP VIEW testOracleR2dbcWarning"));
684+
tryAwaitNone(connection.close());
685+
}
686+
}
687+
627688
}

0 commit comments

Comments
 (0)