Skip to content

Commit 9846327

Browse files
committed
Oct 20th AoJ (ADBA over JDBC)n push
1 parent 046636c commit 9846327

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+7023
-2780
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.oracle.adbaoverjdbc;
17+
18+
import java.lang.reflect.Array;
19+
import jdk.incubator.sql2.SqlException;
20+
import jdk.incubator.sql2.SqlType;
21+
import java.sql.PreparedStatement;
22+
import java.sql.SQLException;
23+
import java.time.Duration;
24+
import java.util.List;
25+
import java.util.concurrent.CompletionStage;
26+
import java.util.concurrent.Executor;
27+
import java.util.function.Consumer;
28+
import java.util.logging.Level;
29+
import java.util.stream.Collector;
30+
import jdk.incubator.sql2.ArrayRowCountOperation;
31+
import jdk.incubator.sql2.Result;
32+
33+
/**
34+
*
35+
* @param <T>
36+
*/
37+
class ArrayCountOperation<T> extends ParameterizedOperation<T>
38+
implements ArrayRowCountOperation<T> {
39+
40+
private static final Collector DEFAULT_COLLECTOR = Collector.of(
41+
() -> null,
42+
(a, v) -> {},
43+
(a, b) -> null,
44+
a -> null);
45+
46+
47+
/**
48+
* Factory method to create ArrayCountOperations.
49+
*
50+
* @param <S> the type of the value of the ArrayCountOperation
51+
* @param session the Session the ArrayCountOperation belongs to
52+
* @param grp the GroupOperation the ArrayCountOperation is a member of
53+
* @param sql the SQL string to execute. Must return a count.
54+
* @return a new ArrayCountOperation that will execute sql.
55+
*/
56+
static <S> ArrayCountOperation<S> newArrayCountOperation(Session session, OperationGroup grp, String sql) {
57+
return new ArrayCountOperation<>(session, grp, sql);
58+
}
59+
60+
// attributes
61+
private final String sqlString;
62+
private Collector<? super Result.RowCount, Object , ? extends T> countCollector;
63+
64+
PreparedStatement jdbcStatement;
65+
66+
ArrayCountOperation(Session session, OperationGroup operationGroup, String sql) {
67+
super(session, operationGroup);
68+
countCollector = DEFAULT_COLLECTOR;
69+
sqlString = sql;
70+
}
71+
72+
@Override
73+
public <A, S extends T> ArrayRowCountOperation<T> collect(Collector<? super Result.RowCount, A, S> c) {
74+
if (isImmutable() || countCollector != DEFAULT_COLLECTOR) throw new IllegalStateException("TODO");
75+
if (c == null) throw new IllegalArgumentException("TODO");
76+
countCollector = (Collector<? super Result.RowCount, Object , ? extends T>) c;
77+
return this;
78+
}
79+
80+
@Override
81+
CompletionStage<T> follows(CompletionStage<?> predecessor, Executor executor) {
82+
predecessor = attachFutureParameters(predecessor);
83+
return predecessor
84+
.thenApplyAsync(this::executeQuery, executor);
85+
}
86+
87+
/**
88+
* Execute the SQL query, process the returned count, and return the result of
89+
* processing the returned count.
90+
*
91+
* @param ignore not used
92+
* @return the result of processing the count
93+
*/
94+
private T executeQuery(Object ignore) {
95+
checkCanceled();
96+
try {
97+
jdbcStatement = session.prepareStatement(sqlString);
98+
99+
// Get parameter ids
100+
String[] keys = (String[])setParameters.keySet().toArray(new String[setParameters.size()]);
101+
102+
// Get parameter values
103+
ParameterValue[] paramVals = (ParameterValue[]) setParameters.values().toArray(new ParameterValue[setParameters.size()]);
104+
105+
int paramIndex;
106+
int batchSize;
107+
108+
// Get the batch size from first parameter list/array size
109+
// TODO: Need to check all parameter value list or value array of same size
110+
Object paramVal = paramVals[0].value;
111+
if(paramVal instanceof List)
112+
batchSize = ((List)paramVal).size();
113+
else
114+
batchSize = Array.getLength(paramVal);
115+
116+
// Loop for each value in the list or an array
117+
for(int i = 0; i < batchSize; i++) {
118+
// Loop for each parameter to add a batch
119+
for(paramIndex = 0; paramIndex < keys.length; paramIndex++) {
120+
ParameterValue v = paramVals[paramIndex];
121+
Object val = getParamVal(v, i);
122+
v = new ParameterValue(val, v.type);
123+
v.set(jdbcStatement, keys[paramIndex]);
124+
}
125+
126+
// Add batch
127+
jdbcStatement.addBatch();
128+
}
129+
130+
// Execute batch
131+
group.logger.log(Level.FINE, () -> "executeLargeBatch(\"" + sqlString + "\")");
132+
long[] counts = jdbcStatement.executeLargeBatch();
133+
134+
// Get final count using the collector
135+
Object container = countCollector.supplier().get();
136+
for (long c : counts)
137+
countCollector.accumulator().accept(container, com.oracle.adbaoverjdbc.Result.newRowCount(c));
138+
return countCollector.finisher().apply(container);
139+
}
140+
catch (SQLException ex) {
141+
throw new SqlException(ex.getMessage(), ex, ex.getSQLState(), ex.getErrorCode(), sqlString, -1);
142+
}
143+
}
144+
145+
// Get parameter value from list or an array
146+
private Object getParamVal(ParameterValue paramVal, int index) {
147+
if(paramVal.value instanceof List)
148+
return ((List)(paramVal.value)).get(index);
149+
else
150+
return Array.get(paramVal.value, index);
151+
}
152+
153+
// Covariant overrides
154+
155+
@Override
156+
public ArrayCountOperation<T> set(String id, List<?> values) {
157+
return (ArrayCountOperation<T>)super.set(id, values);
158+
}
159+
160+
@Override
161+
public ArrayCountOperation<T> set(String id, List<?> values, SqlType type) {
162+
return (ArrayCountOperation<T>)super.set(id, values, type);
163+
}
164+
165+
@Override
166+
public <S> ArrayRowCountOperation<T> set(String id, S[] values, SqlType type) {
167+
return (ArrayCountOperation<T>)super.set(id, values, type);
168+
}
169+
170+
@Override
171+
public <S> ArrayRowCountOperation<T> set(String id, S[] values) {
172+
return (ArrayCountOperation<T>)super.set(id, values);
173+
}
174+
175+
176+
@Override
177+
public ArrayCountOperation<T> set(String id, CompletionStage<?> source) {
178+
return (ArrayCountOperation<T>)super.set(id, source);
179+
}
180+
181+
@Override
182+
public ArrayCountOperation<T> set(String id, CompletionStage<?> source, SqlType type) {
183+
return (ArrayCountOperation<T>)super.set(id, source, type);
184+
}
185+
186+
@Override
187+
public ArrayCountOperation<T> timeout(Duration minTime) {
188+
return (ArrayCountOperation<T>)super.timeout(minTime);
189+
}
190+
191+
@Override
192+
public ArrayCountOperation<T> onError(Consumer<Throwable> handler) {
193+
return (ArrayCountOperation<T>)super.onError(handler);
194+
}
195+
196+
}

java/AoJ/src/com/oracle/adbaoverjdbc/com/oracle/adbaoverjdbc/CountOperation.java

Lines changed: 112 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,10 @@
1919
import jdk.incubator.sql2.SqlException;
2020
import jdk.incubator.sql2.SqlType;
2121
import java.sql.PreparedStatement;
22+
import java.sql.ResultSet;
2223
import java.sql.SQLException;
2324
import java.time.Duration;
25+
import java.util.concurrent.CompletableFuture;
2426
import java.util.concurrent.CompletionStage;
2527
import java.util.concurrent.Executor;
2628
import java.util.function.Consumer;
@@ -29,10 +31,6 @@
2931
import jdk.incubator.sql2.ParameterizedRowCountOperation;
3032
import jdk.incubator.sql2.Result;
3133

32-
/**
33-
*
34-
* @param <T>
35-
*/
3634
class CountOperation<T> extends ParameterizedOperation<T>
3735
implements ParameterizedRowCountOperation<T> {
3836

@@ -53,19 +51,25 @@ static <S> CountOperation<S> newCountOperation(Session session, OperationGroup g
5351

5452
// attributes
5553
private final String sqlString;
56-
private Function<? super Result.RowCount, ? extends T> countProcessor;
54+
protected Function<? super Result.RowCount, ? extends T> countProcessor;
5755

58-
PreparedStatement jdbcStatement;
56+
private PreparedStatement jdbcStatement;
57+
private GeneratedKeysRowOperation rowOperation;
58+
private String autoKeyColNames[];
5959

6060
CountOperation(Session session, OperationGroup operationGroup, String sql) {
6161
super(session, operationGroup);
6262
countProcessor = DEFAULT_PROCESSOR;
6363
sqlString = sql;
64+
autoKeyColNames = null;
65+
rowOperation = null;
6466
}
6567

6668
@Override
6769
public RowOperation<T> returning(String... keys) {
68-
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
70+
rowOperation = new GeneratedKeysRowOperation(session, group);
71+
autoKeyColNames = keys;
72+
return group.addMember(rowOperation);
6973
}
7074

7175
@Override
@@ -93,13 +97,27 @@ CompletionStage<T> follows(CompletionStage<?> predecessor, Executor executor) {
9397
private T executeQuery(Object ignore) {
9498
checkCanceled();
9599
try {
96-
jdbcStatement = session.prepareStatement(sqlString);
100+
if(autoKeyColNames != null)
101+
jdbcStatement = session.prepareStatement(sqlString, autoKeyColNames);
102+
else
103+
jdbcStatement = session.prepareStatement(sqlString);
104+
97105
setParameters.forEach((String k, ParameterValue v) -> {
98106
v.set(jdbcStatement, k);
99107
});
100-
group.logger.log(Level.FINE, () -> "executeUpdate(\"" + sqlString + "\")");
108+
group.logger.log(Level.FINE, () -> "executeLargeUpdate(\"" + sqlString + "\")");
101109
long c = jdbcStatement.executeLargeUpdate();
102-
return countProcessor.apply(new RowCount(c));
110+
111+
if(autoKeyColNames != null) {
112+
113+
// Get the DML Returning resultset
114+
ResultSet rs = jdbcStatement.getGeneratedKeys();
115+
116+
// Set the resultset and complete the future, so RowOperation process the result
117+
rowOperation.setResultSet(rs);
118+
}
119+
120+
return countProcessor.apply(com.oracle.adbaoverjdbc.Result.newRowCount(c));
103121
}
104122
catch (SQLException ex) {
105123
throw new SqlException(ex.getMessage(), ex, ex.getSQLState(), ex.getErrorCode(), sqlString, -1);
@@ -138,28 +156,94 @@ public CountOperation<T> onError(Consumer<Throwable> handler) {
138156
return (CountOperation<T>)super.onError(handler);
139157
}
140158

159+
/**
160+
* Represents the result of a SQL execution that is an update count.
161+
*
162+
* ISSUE: It's not obvious this type is more valuable than just using
163+
* java.lang.Long. Result.Count exists to clearly express that the input arg
164+
* to the processor Function is a count. Could rely on documentation but this
165+
* seems like it might be important enough to capture in the type system. There
166+
* also may be non-numeric return values that Result.Count could express, eg
167+
* success but number unknown.
168+
*/
169+
static class RowCount implements Result.RowCount {
170+
private long count = -1;
171+
172+
RowCount(long c) {
173+
count = c;
174+
}
175+
176+
@Override
177+
public long getCount() {
178+
return count;
179+
}
180+
}
181+
141182
/**
142-
* Represents the result of a SQL execution that is an update count.
143-
*
144-
* ISSUE: It's not obvious this type is more valuable than just using
145-
* java.lang.Long. Result.Count exists to clearly express that the input arg
146-
* to the processor Function is a count. Could rely on documentation but this
147-
* seems like it might be important enough to capture in the type system. There
148-
* also may be non-numeric return values that Result.Count could express, eg
149-
* success but number unknown.
183+
* This inner class represents DML generated keys as a RowOperation. The
184+
* underlying ResultSet is obtained during execution of the CountOperation.
150185
*/
151-
static class RowCount implements Result.RowCount {
152-
153-
private long count = -1;
154-
155-
private RowCount(long c) {
156-
count = c;
186+
private class GeneratedKeysRowOperation
187+
extends com.oracle.adbaoverjdbc.RowOperation<T> {
188+
189+
private final CompletableFuture<T> resultCF;
190+
191+
GeneratedKeysRowOperation(Session session, OperationGroup<T, ?> operationGroup) {
192+
super(session, operationGroup, null);
193+
resultCF = new CompletableFuture<>();
157194
}
158-
195+
159196
@Override
160-
public long getCount() {
161-
return count;
197+
CompletionStage<T> follows(CompletionStage<?> predecessor, Executor executor) {
198+
predecessor = attachFutureParameters(predecessor);
199+
predecessor
200+
.thenComposeAsync(this::resultExist, executor)
201+
.thenCompose(this::moreRows);
202+
return (CompletionStage<T>) predecessor;
203+
}
204+
205+
206+
// Wait until countOperation generate the DML returning result
207+
private CompletionStage<T> resultExist(Object x) {
208+
checkCanceled();
209+
return resultCF;
210+
}
211+
212+
213+
/**
214+
* Register the ResultSet returned by
215+
* {@link java.sql.Statement#getGeneratedKeys()}
216+
* during execution of the associated CountOperation.
217+
* @param resultSet The generated keys of the associated CountOperation.
218+
*/
219+
void setResultSet(ResultSet resultSet) {
220+
checkCanceled();
221+
initRowOperationResultSet(jdbcStatement, resultSet);
222+
// Trigger DML returning result is ready to process
223+
resultCF.complete(null);
162224
}
163225

164-
}
226+
@Override
227+
protected void JdbcClose() {
228+
try {
229+
jdbcStatement.close();
230+
}
231+
catch (SQLException ex) {
232+
throw new SqlException(ex.getMessage(), ex, ex.getSQLState(), ex.getErrorCode(), sqlString, -1);
233+
}
234+
}
235+
236+
@Override
237+
protected void JdbcCancel() {
238+
try {
239+
if (jdbcStatement != null) {
240+
jdbcStatement.cancel();
241+
}
242+
}
243+
catch (SQLException ex) {
244+
throw new SqlException(ex.getMessage(), ex, ex.getSQLState(), ex.getErrorCode(), sqlString, -1);
245+
}
246+
}
247+
} // GeneratedKeysRowOperation
248+
165249
}

0 commit comments

Comments
 (0)