Skip to content

Commit a8ba8a7

Browse files
committed
fixes handling empty results while using reader
1 parent 41cfa7d commit a8ba8a7

File tree

3 files changed

+61
-5
lines changed

3 files changed

+61
-5
lines changed

client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/AbstractBinaryFormatReader.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ public abstract class AbstractBinaryFormatReader implements ClickHouseBinaryForm
5454

5555
private volatile boolean hasNext = true;
5656

57+
58+
private volatile boolean initialState = true; // reader is in initial state, no records have been read yet
59+
5760
protected AbstractBinaryFormatReader(InputStream inputStream, QuerySettings querySettings, TableSchema schema,
5861
BinaryStreamReader.ByteBufferAllocator byteBufferAllocator) {
5962
this.input = inputStream;
@@ -148,11 +151,16 @@ public <T> T readValue(String colName) {
148151

149152
@Override
150153
public boolean hasNext() {
154+
if (initialState) {
155+
readNextRecord();
156+
}
157+
151158
return hasNext;
152159
}
153160

154161

155162
protected void readNextRecord() {
163+
initialState = false;
156164
try {
157165
nextRecordEmpty.set(true);
158166
if (!readRecord(nextRecord)) {
@@ -195,6 +203,7 @@ public Map<String, Object> next() {
195203
}
196204

197205
protected void endReached() {
206+
initialState = false;
198207
hasNext = false;
199208
}
200209

client-v2/src/main/java/com/clickhouse/client/api/query/Records.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ public Spliterator<GenericRecord> spliterator() {
5555

5656
/**
5757
* Returns {@code true} if this collection contains no elements.
58+
* Prefer this method over {@link #getResultRows()} == 0 because current method reflect actual state of the collection
59+
* while {@link #getResultRows()} is send from server before sending actual data.
5860
*
5961
* @return {@code true} if this collection contains no elements
6062
*/
61-
boolean isEmpty() {
63+
public boolean isEmpty() {
6264
return empty;
6365
}
6466

client-v2/src/test/java/com/clickhouse/client/query/QueryTests.java

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -261,14 +261,25 @@ public void testReadRecordsGetFirstRecord() throws Exception {
261261
Assert.assertFalse(iter.hasNext());
262262
}
263263

264-
@Test(groups = {"integration"})
265-
public void testReadRecordsNoResult() throws Exception {
266-
Records records = client.queryRecords("CREATE DATABASE IF NOT EXISTS test_db").get(3, TimeUnit.SECONDS);
264+
@Test(description = "Verifies correct handling of empty data set while column information is present", groups = {"integration"})
265+
public void testQueryRecordsOnEmptyDataset() throws Exception {
266+
Records records = client.queryRecords("SELECT 1 LIMIT 0").get(3, TimeUnit.SECONDS);
267267

268268
Iterator<GenericRecord> iter = records.iterator();
269269
Assert.assertFalse(iter.hasNext());
270270
}
271271

272+
@Test(description = "Verifies correct handling when no column information expected", groups = {"integration"})
273+
public void testQueryRecordsWithEmptyResult() throws Exception {
274+
// This test uses a query that returns no data and no column information
275+
try (Records records = client.queryRecords("CREATE DATABASE IF NOT EXISTS test_db").get(3, TimeUnit.SECONDS)) {
276+
Assert.assertTrue(records.isEmpty());
277+
for (GenericRecord record : records) {
278+
Assert.fail("unexpected record: " + record);
279+
}
280+
}
281+
}
282+
272283
@Test(groups = {"integration"})
273284
public void testQueryAll() throws Exception {
274285
List<Map<String, Object>> dataset = prepareDataSet(DATASET_TABLE, DATASET_COLUMNS, DATASET_VALUE_GENERATORS, 10);
@@ -298,7 +309,8 @@ public void testQueryAllSimple(int numberOfRecords) throws Exception {
298309

299310
@Test(groups = {"integration"})
300311
public void testQueryAllNoResult() throws Exception {
301-
List<GenericRecord> records = client.queryAll("CREATE DATABASE IF NOT EXISTS test_db");
312+
List<GenericRecord> records = client.queryAll("SELECT 1 LIMIT 0");
313+
Assert.assertEquals(records.size(), 0);
302314
Assert.assertTrue(records.isEmpty());
303315
}
304316

@@ -457,6 +469,14 @@ record = reader.next();
457469
}
458470
);
459471

472+
@Test(groups = {"integration"})
473+
public void testBinaryReaderOnQueryWithNoResult() throws Exception {
474+
try (QueryResponse response = client.query("SELECT 1 LIMIT 0").get(3, TimeUnit.SECONDS)) {
475+
ClickHouseBinaryFormatReader reader = client.newBinaryFormatReader(response);
476+
Assert.assertFalse(reader.hasNext());
477+
Assert.assertNull(reader.next());
478+
}
479+
}
460480

461481
@Test(groups = {"integration"})
462482
public void testArrayValues() throws Exception {
@@ -539,6 +559,31 @@ public void testQueryExceptionHandling() throws Exception {
539559
}
540560
}
541561

562+
@Test
563+
public void testQueryRecordsEmptyResult() throws Exception {
564+
try (Records records = client.queryRecords("SELECT 1 LIMIT 0").get(3, TimeUnit.SECONDS)) {
565+
Assert.assertTrue(records.isEmpty());
566+
for (GenericRecord record : records) {
567+
Assert.fail("unexpected record: " + record);
568+
}
569+
}
570+
}
571+
572+
@Test(description = "Verifies that queryRecords reads all values from the response", groups = {"integration"})
573+
public void testQueryRecordsReadsAllValues() throws Exception {
574+
try (Records records = client.queryRecords("SELECT toInt32(number) FROM system.numbers LIMIT 3").get(3, TimeUnit.SECONDS)) {
575+
Assert.assertFalse(records.isEmpty());
576+
Assert.assertEquals(records.getResultRows(), 3);
577+
578+
int expectedNumber = 0;
579+
for (GenericRecord record : records) {
580+
Assert.assertEquals(record.getInteger(1), expectedNumber);
581+
expectedNumber++;
582+
}
583+
584+
Assert.assertEquals(expectedNumber, 3);
585+
}
586+
}
542587

543588
private final static List<String> NULL_DATASET_COLUMNS = Arrays.asList(
544589
"id UInt32",

0 commit comments

Comments
 (0)