Skip to content

Commit e30de88

Browse files
Merge branch 'main' of https://github.com/oracle/oracle-r2dbc into async-lock-2
2 parents 42060aa + 938b999 commit e30de88

File tree

4 files changed

+33
-25
lines changed

4 files changed

+33
-25
lines changed

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

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,16 @@
2727
import io.r2dbc.spi.IsolationLevel;
2828
import io.r2dbc.spi.Lifecycle;
2929
import io.r2dbc.spi.R2dbcException;
30+
import io.r2dbc.spi.Result;
3031
import io.r2dbc.spi.Statement;
3132
import io.r2dbc.spi.TransactionDefinition;
3233
import io.r2dbc.spi.ValidationDepth;
3334
import org.reactivestreams.Publisher;
35+
import reactor.core.publisher.Flux;
3436
import reactor.core.publisher.Mono;
3537

3638
import java.sql.SQLException;
39+
import java.sql.Savepoint;
3740
import java.time.Duration;
3841

3942
import static io.r2dbc.spi.IsolationLevel.READ_COMMITTED;
@@ -475,21 +478,23 @@ public ConnectionMetadata getMetadata() {
475478
/**
476479
* {@inheritDoc}
477480
* <p>
478-
* This SPI method is not yet implemented.
481+
* This SPI method is implemented to execute a "SAVEPOINT ..." command.
482+
* This is the same as how Oracle JDBC implements
483+
* {@link java.sql.Connection#setSavepoint(String)}, except that JDBC uses a
484+
* blocking call to {@code java.sql.Statement.executeUpdate(String)}. This
485+
* method uses a non-blocking call.
479486
* </p>
480-
* @throws UnsupportedOperationException In this release of Oracle
481-
* R2DBC
482487
* @throws IllegalStateException If this {@code Connection} is closed
483488
*/
484489
@Override
485490
public Publisher<Void> createSavepoint(String name) {
486491
requireNonNull(name, "name is null");
487492
requireOpenConnection(jdbcConnection);
488-
// TODO: Execute SQL to create a savepoint. Examine and understand the
489-
// Oracle JDBC driver's implementation of
490-
// OracleConnection.oracleSetSavepoint(), and replicate it without
491-
// blocking a thread. Consider adding a ReactiveJDBCAdapter API to do this.
492-
throw new UnsupportedOperationException("createSavepoint not supported");
493+
return Mono.from(setAutoCommit(false))
494+
.then(Flux.from(createStatement("SAVEPOINT " + name)
495+
.execute())
496+
.flatMap(Result::getRowsUpdated)
497+
.then());
493498
}
494499

495500
/**
@@ -535,20 +540,22 @@ public Publisher<Void> rollbackTransaction() {
535540
/**
536541
* {@inheritDoc}
537542
* <p>
538-
* This SPI method is not yet implemented.
543+
* This SPI method is implemented to execute a "ROLLBACK TO " command. This
544+
* is the same as how Oracle JDBC implements
545+
* {@link java.sql.Connection#rollback(Savepoint)}, except that JDBC uses a
546+
* blocking call to {@code java.sql.Statement.executeUpdate(String)}. This
547+
* method uses a non-blocking call.
539548
* </p>
540549
* @throws IllegalStateException If this {@code Connection} is closed
541-
* @throws UnsupportedOperationException In version this release of Oracle
542-
* R2DBC
543550
*/
544551
@Override
545552
public Publisher<Void> rollbackTransactionToSavepoint(String name) {
546553
requireNonNull(name, "name is null");
547554
requireOpenConnection(jdbcConnection);
548-
// TODO: Use the JDBC connection to rollback to a savepoint without blocking
549-
// a thread.
550-
throw new UnsupportedOperationException(
551-
"rollbackTransactionToSavepoint not supported");
555+
return Flux.from(createStatement("ROLLBACK TO " + name)
556+
.execute())
557+
.flatMap(Result::getRowsUpdated)
558+
.then();
552559
}
553560

554561
/**

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

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

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+
}
299305
if (type == R2dbcType.BLOB
300306
|| type == R2dbcType.CLOB
301307
|| type == R2dbcType.NCLOB

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,11 @@ public void testNumericTypes() {
158158
connection, "NUMBER(5,3)", JDBCType.NUMERIC, R2dbcType.NUMERIC, 5, 3,
159159
BigDecimal.class, BigDecimal.valueOf(12.345));
160160

161+
// Expect getScale() to return 0 for NUMBER .
162+
verifyColumnMetadata(
163+
connection, "NUMBER(5,0)", JDBCType.NUMERIC, R2dbcType.NUMERIC, 5, 0,
164+
BigDecimal.class, BigDecimal.valueOf(12345));
165+
161166
// Expect FLOAT and Double to map.
162167
verifyColumnMetadata(
163168
connection, "FLOAT(6)", JDBCType.FLOAT, R2dbcType.FLOAT, 6, null,

src/test/java/oracle/r2dbc/test/OracleTestKit.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -307,16 +307,6 @@ public void prepareStatement() {
307307
@Override
308308
public void compoundStatement() {}
309309

310-
@Disabled("Disabled until savepoint is implemented")
311-
@Test
312-
@Override
313-
public void savePoint() {}
314-
315-
@Disabled("Disabled until savepoint is implemented")
316-
@Test
317-
@Override
318-
public void savePointStartsTransaction() {}
319-
320310
static <T> Mono<T> close(Connection connection) {
321311
return Mono.from(connection.close())
322312
.then(Mono.empty());

0 commit comments

Comments
 (0)