Skip to content

Commit 7c5ccbe

Browse files
authored
Merge pull request #1343 from zhicwu/main
Add object mapping
2 parents 5dddbf5 + c459721 commit 7c5ccbe

30 files changed

+1639
-34
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
## 0.4.6, 2023-04-26
22
### New Features
33
* ClickHouseStatement.setMirroredOutput() for dumping ResultSet.
4+
* ClickHouseResponse.records(Class<?>) for object mapping.
5+
* Two new options(use_compilation & max_mapper_cache) reserved for future usage.
46

57
### Bug Fixes
68
* NoClassDefFoundError with clickhouse-apache-http-client-jdbc. [#1319](https://github.com/ClickHouse/clickhouse-java/issues/1319)

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseConfig.java

+14
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ public static Map<ClickHouseOption, Serializable> toClientOptions(Map<?, ?> prop
204204
private final ClickHouseBufferingMode requestBuffering;
205205
private final ClickHouseBufferingMode responseBuffering;
206206
private final int maxExecutionTime;
207+
private final int maxMapperCache;
207208
private final int maxQueuedBuffers;
208209
private final int maxQueuedRequests;
209210
private final long maxResultRows;
@@ -229,6 +230,7 @@ public static Map<ClickHouseOption, Serializable> toClientOptions(Map<?, ?> prop
229230
private final boolean widenUnsignedTypes;
230231
private final boolean useBinaryString;
231232
private final boolean useBlockingQueue;
233+
private final boolean useCompilation;
232234
private final boolean useObjectsInArray;
233235
private final boolean useNoProxy;
234236
private final boolean useServerTimeZone;
@@ -312,6 +314,7 @@ public ClickHouseConfig(Map<ClickHouseOption, Serializable> options, ClickHouseC
312314
this.responseBuffering = (ClickHouseBufferingMode) getOption(ClickHouseClientOption.RESPONSE_BUFFERING,
313315
ClickHouseDefaults.BUFFERING);
314316
this.maxExecutionTime = getIntOption(ClickHouseClientOption.MAX_EXECUTION_TIME);
317+
this.maxMapperCache = getIntOption(ClickHouseClientOption.MAX_MAPPER_CACHE);
315318
this.maxQueuedBuffers = getIntOption(ClickHouseClientOption.MAX_QUEUED_BUFFERS);
316319
this.maxQueuedRequests = getIntOption(ClickHouseClientOption.MAX_QUEUED_REQUESTS);
317320
this.maxResultRows = getLongOption(ClickHouseClientOption.MAX_RESULT_ROWS);
@@ -340,6 +343,7 @@ public ClickHouseConfig(Map<ClickHouseOption, Serializable> options, ClickHouseC
340343
this.widenUnsignedTypes = getBoolOption(ClickHouseClientOption.WIDEN_UNSIGNED_TYPES);
341344
this.useBinaryString = getBoolOption(ClickHouseClientOption.USE_BINARY_STRING);
342345
this.useBlockingQueue = getBoolOption(ClickHouseClientOption.USE_BLOCKING_QUEUE);
346+
this.useCompilation = getBoolOption(ClickHouseClientOption.USE_COMPILATION);
343347
this.useObjectsInArray = getBoolOption(ClickHouseClientOption.USE_OBJECTS_IN_ARRAYS);
344348
this.useNoProxy = getBoolOption(ClickHouseClientOption.USE_NO_PROXY);
345349
this.useServerTimeZone = getBoolOption(ClickHouseClientOption.USE_SERVER_TIME_ZONE);
@@ -458,6 +462,11 @@ public int getMaxBufferSize() {
458462
return maxBufferSize;
459463
}
460464

465+
@Override
466+
public int getMaxMapperCache() {
467+
return maxMapperCache;
468+
}
469+
461470
@Override
462471
public int getBufferSize() {
463472
return bufferSize;
@@ -615,6 +624,11 @@ public boolean isUseBlockingQueue() {
615624
return useBlockingQueue;
616625
}
617626

627+
@Override
628+
public boolean isUseCompilation() {
629+
return useCompilation;
630+
}
631+
618632
@Override
619633
public boolean isUseObjectsInArray() {
620634
return useObjectsInArray;

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseParameterizedQuery.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -548,11 +548,11 @@ public List<String[]> getQueryParts() {
548548
*/
549549
public ClickHouseValue[] getParameterTemplates() {
550550
int i = 0;
551-
ClickHouseValue[] tempaltes = new ClickHouseValue[names.size()];
551+
ClickHouseValue[] templates = new ClickHouseValue[names.size()];
552552
for (ClickHouseValue v : names.values()) {
553-
tempaltes[i++] = v;
553+
templates[i++] = v;
554554
}
555-
return tempaltes;
555+
return templates;
556556
}
557557

558558
/**

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseResponse.java

+43-2
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,19 @@ public ClickHouseResponseSummary getSummary() {
5252

5353
@Override
5454
public ClickHouseInputStream getInputStream() {
55-
return null;
55+
return ClickHouseInputStream.empty();
5656
}
5757

5858
@Override
5959
public Iterable<ClickHouseRecord> records() {
6060
return Collections.emptyList();
6161
}
6262

63+
@Override
64+
public <T> Iterable<T> records(Class<T> objClass) {
65+
return Collections.emptyList();
66+
}
67+
6368
@Override
6469
public void close() {
6570
// do nothing
@@ -93,7 +98,7 @@ public boolean isClosed() {
9398
* also means additional work is required for deserialization, especially when
9499
* using a binary format.
95100
*
96-
* @return input stream for getting raw data returned from server
101+
* @return non-null input stream for getting raw data returned from server
97102
*/
98103
ClickHouseInputStream getInputStream();
99104

@@ -109,6 +114,20 @@ default ClickHouseRecord firstRecord() {
109114
return records().iterator().next();
110115
}
111116

117+
/**
118+
* Gets the first record as mapped object. Please use {@link #records(Class)}
119+
* instead if you need to access the rest of records.
120+
*
121+
* @param <T> type of the mapped object
122+
* @param objClass non-null class of the mapped object
123+
* @return mapped object of the first record
124+
* @throws NoSuchElementException when there's no record at all
125+
* @throws UncheckedIOException when failed to read data(e.g. deserialization)
126+
*/
127+
default <T> T firstRecord(Class<T> objClass) {
128+
return records(objClass).iterator().next();
129+
}
130+
112131
/**
113132
* Returns an iterable collection of records which can be walked through in a
114133
* foreach loop. Please pay attention that: 1) {@link UncheckedIOException}
@@ -120,6 +139,18 @@ default ClickHouseRecord firstRecord() {
120139
*/
121140
Iterable<ClickHouseRecord> records();
122141

142+
/**
143+
* Returns an iterable collection of mapped objects which can be walked through
144+
* in a foreach loop. When {@code objClass} is null or {@link ClickHouseRecord},
145+
* it's same as calling {@link #records()}.
146+
*
147+
* @param <T> type of the mapped object
148+
* @param objClass non-null class of the mapped object
149+
* @return non-null iterable collection
150+
* @throws UncheckedIOException when failed to read data(e.g. deserialization)
151+
*/
152+
<T> Iterable<T> records(Class<T> objClass);
153+
123154
/**
124155
* Pipes the contents of this response into the given output stream. Keep in
125156
* mind that it's caller's responsibility to flush and close the output stream.
@@ -146,6 +177,16 @@ default Stream<ClickHouseRecord> stream() {
146177
Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED), false);
147178
}
148179

180+
/**
181+
* Gets stream of mapped objects to process.
182+
*
183+
* @return stream of mapped objects
184+
*/
185+
default <T> Stream<T> stream(Class<T> objClass) {
186+
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(records(objClass).iterator(),
187+
Spliterator.IMMUTABLE | Spliterator.NONNULL | Spliterator.ORDERED), false);
188+
}
189+
149190
@Override
150191
void close();
151192

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseSimpleResponse.java

+11
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import com.clickhouse.data.ClickHouseColumn;
99
import com.clickhouse.data.ClickHouseInputStream;
1010
import com.clickhouse.data.ClickHouseRecord;
11+
import com.clickhouse.data.ClickHouseRecordMapper;
1112
import com.clickhouse.data.ClickHouseRecordTransformer;
1213
import com.clickhouse.data.ClickHouseSimpleRecord;
1314
import com.clickhouse.data.ClickHouseValue;
@@ -169,6 +170,16 @@ public Iterable<ClickHouseRecord> records() {
169170
return records;
170171
}
171172

173+
@SuppressWarnings("unchecked")
174+
@Override
175+
public <T> Iterable<T> records(Class<T> objClass) {
176+
if (objClass == null || objClass == ClickHouseRecord.class) {
177+
return (Iterable<T>) records();
178+
}
179+
180+
return () -> ClickHouseRecordMapper.wrap(null, columns, records().iterator(), objClass, null);
181+
}
182+
172183
@Override
173184
public void close() {
174185
// nothing to close

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseStreamResponse.java

+9-1
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,15 @@ public Iterable<ClickHouseRecord> records() {
141141
throw new UnsupportedOperationException(
142142
"No data processor available for deserialization, please consider to use getInputStream instead");
143143
}
144-
145144
return processor.records();
146145
}
146+
147+
@Override
148+
public <T> Iterable<T> records(Class<T> objClass) {
149+
if (processor == null) {
150+
throw new UnsupportedOperationException(
151+
"No data processor available for deserialization, please consider to use getInputStream instead");
152+
}
153+
return processor.records(objClass, null);
154+
}
147155
}

clickhouse-client/src/main/java/com/clickhouse/client/config/ClickHouseClientOption.java

+11
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,11 @@ public enum ClickHouseClientOption implements ClickHouseOption {
182182
*/
183183
MAX_BUFFER_SIZE("max_buffer_size", ClickHouseDataConfig.DEFAULT_MAX_BUFFER_SIZE,
184184
"Maximum buffer size in byte can be used for streaming."),
185+
/**
186+
* Maximum number of mappers can be cached.
187+
*/
188+
MAX_MAPPER_CACHE("max_mapper_cache", ClickHouseDataConfig.DEFAULT_MAX_MAPPER_CACHE,
189+
"Maximum number of mappers can be cached."),
185190
/**
186191
* Maximum query execution time in seconds.
187192
*/
@@ -350,6 +355,12 @@ public enum ClickHouseClientOption implements ClickHouseOption {
350355
*/
351356
USE_BLOCKING_QUEUE("use_blocking_queue", ClickHouseDataConfig.DEFAULT_USE_BLOCKING_QUEUE,
352357
"Whether to use blocking queue for buffering."),
358+
/**
359+
* Whether to use compilation(generated byte code) in object mapping and
360+
* serialization.
361+
*/
362+
USE_COMPILATION("use_compilation", ClickHouseDataConfig.DEFAULT_USE_COMPILATION,
363+
"Whether to use compilation(generated byte code) in object mapping and serialization."),
353364
/**
354365
* Whether Object[] should be used instead of primitive arrays.
355366
*/

clickhouse-data/pom.xml

+5
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@
8585
<artifactId>msgpack-core</artifactId>
8686
<optional>true</optional>
8787
</dependency>
88+
<dependency>
89+
<groupId>org.ow2.asm</groupId>
90+
<artifactId>asm</artifactId>
91+
<optional>true</optional>
92+
</dependency>
8893
<dependency>
8994
<groupId>org.slf4j</groupId>
9095
<artifactId>slf4j-api</artifactId>

clickhouse-data/src/main/java/com/clickhouse/data/ClickHouseByteBuffer.java

+24
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
package com.clickhouse.data;
22

33
import java.io.Serializable;
4+
import java.math.BigDecimal;
45
import java.math.BigInteger;
56
import java.nio.Buffer;
67
import java.nio.ByteBuffer;
78
import java.nio.charset.Charset;
89
import java.nio.charset.StandardCharsets;
10+
import java.time.LocalDate;
11+
import java.time.LocalDateTime;
912
import java.util.Arrays;
1013
import java.util.List;
1114
import java.util.UUID;
@@ -144,6 +147,14 @@ public BigInteger asBigInteger() {
144147
return getBigInteger(0, length, false);
145148
}
146149

150+
public BigDecimal asBigDecimal() {
151+
return asBigDecimal(0);
152+
}
153+
154+
public BigDecimal asBigDecimal(int scale) {
155+
return new BigDecimal(asBigInteger(), scale);
156+
}
157+
147158
public boolean asBoolean() {
148159
return getBoolean(0);
149160
}
@@ -171,6 +182,19 @@ public double[] asDoubleArray() {
171182
return values;
172183
}
173184

185+
public LocalDate asDate() {
186+
return LocalDate.ofEpochDay(asUnsignedInteger());
187+
}
188+
189+
public LocalDateTime asDateTime() {
190+
return asDateTime(0);
191+
}
192+
193+
public LocalDateTime asDateTime(int scale) {
194+
return ClickHouseValues
195+
.convertToDateTime(asBigDecimal(ClickHouseChecker.between(scale, ClickHouseValues.PARAM_SCALE, 0, 9)));
196+
}
197+
174198
public float asFloat() {
175199
return getFloat(0);
176200
}

clickhouse-data/src/main/java/com/clickhouse/data/ClickHouseDataConfig.java

+30
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@ public ClickHouseRenameMethod getColumnRenameMethod() {
7777
return config.getColumnRenameMethod();
7878
}
7979

80+
@Override
81+
public int getMaxMapperCache() {
82+
return config.getMaxMapperCache();
83+
}
84+
8085
@Override
8186
public int getMaxQueuedBuffers() {
8287
return config.getMaxQueuedBuffers();
@@ -107,6 +112,11 @@ public boolean isUseBlockingQueue() {
107112
return config.isUseBlockingQueue();
108113
}
109114

115+
@Override
116+
public boolean isUseCompilation() {
117+
return config.isUseCompilation();
118+
}
119+
110120
@Override
111121
public boolean isUseObjectsInArray() {
112122
return config.isUseObjectsInArray();
@@ -128,6 +138,7 @@ public boolean isWidenUnsignedTypes() {
128138
static final int DEFAULT_READ_BUFFER_SIZE = DEFAULT_BUFFER_SIZE;
129139
static final int DEFAULT_WRITE_BUFFER_SIZE = DEFAULT_BUFFER_SIZE;
130140
static final int DEFAULT_MAX_BUFFER_SIZE = 128 * 1024;
141+
static final int DEFAULT_MAX_MAPPER_CACHE = 100;
131142
static final int DEFAULT_MAX_QUEUED_BUFFERS = 512;
132143
static final int DEFAULT_BUFFER_QUEUE_VARIATION = 100;
133144

@@ -138,6 +149,7 @@ public boolean isWidenUnsignedTypes() {
138149
static final boolean DEFAULT_REUSE_VALUE_WRAPPER = true;
139150
static final boolean DEFAULT_USE_BINARY_STRING = false;
140151
static final boolean DEFAULT_USE_BLOCKING_QUEUE = false;
152+
static final boolean DEFAULT_USE_COMPILATION = false;
141153
static final boolean DEFAULT_USE_OBJECT_IN_ARRAY = false;
142154
static final boolean DEFAULT_WIDEN_UNSIGNED_TYPE = false;
143155

@@ -255,6 +267,15 @@ default int getWriteBufferSize() {
255267
return DEFAULT_WRITE_BUFFER_SIZE;
256268
}
257269

270+
/**
271+
* Gets maximum number of mappers can be cached.
272+
*
273+
* @return maximum number of mappers can be cached
274+
*/
275+
default int getMaxMapperCache() {
276+
return DEFAULT_MAX_MAPPER_CACHE;
277+
}
278+
258279
/**
259280
* Gets maximum number of buffers can be queued for processing.
260281
*
@@ -328,6 +349,15 @@ default boolean isUseBlockingQueue() {
328349
return DEFAULT_USE_BLOCKING_QUEUE;
329350
}
330351

352+
/**
353+
* Checks whether compilation is used in object mapping and serialization.
354+
*
355+
* @return true if compilation is used; false otherwise
356+
*/
357+
default boolean isUseCompilation() {
358+
return DEFAULT_USE_COMPILATION;
359+
}
360+
331361
/**
332362
* Checks whether object(instead of primitive) is used in array.
333363
*

0 commit comments

Comments
 (0)