|
23 | 23 |
|
24 | 24 | import io.r2dbc.spi.Connection;
|
25 | 25 | import io.r2dbc.spi.ConnectionFactories;
|
| 26 | +import io.r2dbc.spi.OutParameters; |
26 | 27 | import io.r2dbc.spi.Parameters;
|
27 | 28 | import io.r2dbc.spi.R2dbcException;
|
28 | 29 | import io.r2dbc.spi.R2dbcNonTransientException;
|
|
35 | 36 | import oracle.r2dbc.OracleR2dbcTypes;
|
36 | 37 | import oracle.r2dbc.OracleR2dbcWarning;
|
37 | 38 | import oracle.r2dbc.test.DatabaseConfig;
|
| 39 | +import oracle.sql.json.OracleJsonFactory; |
| 40 | +import oracle.sql.json.OracleJsonObject; |
38 | 41 | import org.junit.jupiter.api.Test;
|
39 | 42 | import org.reactivestreams.Publisher;
|
40 | 43 | import reactor.core.publisher.Flux;
|
|
66 | 69 | import static java.util.Arrays.asList;
|
67 | 70 | import static oracle.r2dbc.test.DatabaseConfig.connectTimeout;
|
68 | 71 | import static oracle.r2dbc.test.DatabaseConfig.connectionFactoryOptions;
|
| 72 | +import static oracle.r2dbc.test.DatabaseConfig.databaseVersion; |
69 | 73 | import static oracle.r2dbc.test.DatabaseConfig.newConnection;
|
70 | 74 | import static oracle.r2dbc.test.DatabaseConfig.sharedConnection;
|
71 | 75 | import static oracle.r2dbc.test.TestUtils.constructObject;
|
|
86 | 90 | import static org.junit.jupiter.api.Assertions.assertThrows;
|
87 | 91 | import static org.junit.jupiter.api.Assertions.assertTrue;
|
88 | 92 | import static org.junit.jupiter.api.Assertions.fail;
|
| 93 | +import static org.junit.jupiter.api.Assumptions.assumeTrue; |
89 | 94 |
|
90 | 95 | /**
|
91 | 96 | * Verifies that
|
@@ -2977,6 +2982,116 @@ public void testInOutObjectCall() {
|
2977 | 2982 | }
|
2978 | 2983 | }
|
2979 | 2984 |
|
| 2985 | + /** |
| 2986 | + * Verifies OUT parameter binds in a RETURNING INTO clause. |
| 2987 | + */ |
| 2988 | + @Test |
| 2989 | + public void testReturnParameter() { |
| 2990 | + Connection connection = awaitOne(sharedConnection()); |
| 2991 | + try { |
| 2992 | + awaitExecution(connection.createStatement( |
| 2993 | + "CREATE TABLE testReturnParameter(id NUMBER, value VARCHAR(100))")); |
| 2994 | + |
| 2995 | + TestRow insertRow = new TestRow(1, "a"); |
| 2996 | + Statement returnStatement = connection.createStatement( |
| 2997 | + "BEGIN" + |
| 2998 | + " INSERT INTO testReturnParameter" + |
| 2999 | + " VALUES (?, ?)" + |
| 3000 | + " RETURNING id, value" + |
| 3001 | + " INTO ?, ?;" + |
| 3002 | + " END;"); |
| 3003 | + returnStatement.bind(0, insertRow.id); |
| 3004 | + returnStatement.bind(1, insertRow.value); |
| 3005 | + returnStatement.bind(2, Parameters.out(R2dbcType.NUMERIC)); |
| 3006 | + returnStatement.bind(3, Parameters.out(R2dbcType.VARCHAR)); |
| 3007 | + |
| 3008 | + Result returnResult = awaitOne(returnStatement.execute()); |
| 3009 | + TestRow returnRow = awaitOne(returnResult.map(outParameters -> |
| 3010 | + new TestRow( |
| 3011 | + outParameters.get(0, Integer.class), |
| 3012 | + outParameters.get(1, String.class)))); |
| 3013 | + assertEquals(insertRow, returnRow); |
| 3014 | + } |
| 3015 | + finally { |
| 3016 | + tryAwaitExecution(connection.createStatement( |
| 3017 | + "DROP TABLE testReturnParameter")); |
| 3018 | + tryAwaitNone(connection.close()); |
| 3019 | + } |
| 3020 | + } |
| 3021 | + |
| 3022 | + /** |
| 3023 | + * Verifies OUT parameter binds in a RETURNING INTO clause with a JSON |
| 3024 | + * Duality View. |
| 3025 | + */ |
| 3026 | + @Test |
| 3027 | + public void testReturnParameterJsonDualityView() { |
| 3028 | + // JSON Duality Views were introduced in Oracle Database version 23c, so |
| 3029 | + // this test is skipped if the version is older than 23c. |
| 3030 | + assumeTrue(databaseVersion() >= 23, |
| 3031 | + "JSON Duality Views are not supported by database versions older than" + |
| 3032 | + " 23"); |
| 3033 | + |
| 3034 | + Connection connection = awaitOne(sharedConnection()); |
| 3035 | + try { |
| 3036 | + awaitExecution(connection.createStatement( |
| 3037 | + "CREATE TABLE testReturnParameterJsonDualityViewTable(" + |
| 3038 | + "id NUMBER PRIMARY KEY, value VARCHAR(100))")); |
| 3039 | + awaitExecution(connection.createStatement( |
| 3040 | + "CREATE JSON DUALITY VIEW testReturnParameterJsonDualityView AS" + |
| 3041 | + " SELECT JSON {'id' : t.id, 'value' : t.value}" + |
| 3042 | + " FROM testReturnParameterJsonDualityViewTable t" + |
| 3043 | + " WITH INSERT UPDATE DELETE")); |
| 3044 | + |
| 3045 | + // Verify returning the "data" column |
| 3046 | + OracleJsonObject insertObject = new OracleJsonFactory().createObject(); |
| 3047 | + insertObject.put("id", 1); |
| 3048 | + insertObject.put("value", "a"); |
| 3049 | + Statement returnStatement = connection.createStatement( |
| 3050 | + "BEGIN" + |
| 3051 | + " INSERT INTO testReturnParameterJsonDualityView" + |
| 3052 | + " VALUES (?)" + |
| 3053 | + " RETURNING data" + |
| 3054 | + " INTO ?;" + |
| 3055 | + " END;"); |
| 3056 | + returnStatement.bind(0, insertObject); |
| 3057 | + returnStatement.bind(1, Parameters.out(OracleR2dbcTypes.JSON)); |
| 3058 | + |
| 3059 | + Result returnResult = awaitOne(returnStatement.execute()); |
| 3060 | + OracleJsonObject returnObject = |
| 3061 | + awaitOne(returnResult.map(outParameters -> |
| 3062 | + outParameters.get(0, OracleJsonObject.class))); |
| 3063 | + insertObject.put("_metadata", returnObject.get("_metadata")); |
| 3064 | + assertEquals(insertObject, returnObject); |
| 3065 | + |
| 3066 | + // Verify returning a JSON_VALUE expression |
| 3067 | + OracleJsonObject insertObjectB = new OracleJsonFactory().createObject(); |
| 3068 | + insertObjectB.put("id", 2); |
| 3069 | + insertObjectB.put("value", "b"); |
| 3070 | + Statement returnStatementB = connection.createStatement( |
| 3071 | + "BEGIN" + |
| 3072 | + " INSERT INTO testReturnParameterJsonDualityView" + |
| 3073 | + " VALUES (?)" + |
| 3074 | + " RETURNING JSON_VALUE(DATA, '$.id')" + |
| 3075 | + " INTO ?;" + |
| 3076 | + " END;"); |
| 3077 | + returnStatementB.bind(0, insertObjectB); |
| 3078 | + returnStatementB.bind(1, Parameters.out(R2dbcType.NUMERIC)); |
| 3079 | + |
| 3080 | + Result returnResultB = awaitOne(returnStatementB.execute()); |
| 3081 | + int returnId = |
| 3082 | + awaitOne(returnResultB.map(outParameters -> |
| 3083 | + outParameters.get(0, Integer.class))); |
| 3084 | + assertEquals(insertObjectB.getInt("id"), returnId); |
| 3085 | + } |
| 3086 | + finally { |
| 3087 | + tryAwaitExecution(connection.createStatement( |
| 3088 | + "DROP TABLE testReturnParameterJsonDualityViewTable")); |
| 3089 | + tryAwaitExecution(connection.createStatement( |
| 3090 | + "DROP VIEW testReturnParameterJsonDualityView")); |
| 3091 | + tryAwaitNone(connection.close()); |
| 3092 | + } |
| 3093 | + } |
| 3094 | + |
2980 | 3095 | /**
|
2981 | 3096 | * Connect to the database configured by {@link DatabaseConfig}, with a
|
2982 | 3097 | * the connection configured to use a given {@code executor} for async
|
|
0 commit comments