This is an automated email from the ASF dual-hosted git repository.
virajjasani pushed a commit to branch 5.3
in repository https://gitbox.apache.org/repos/asf/phoenix.git
The following commit(s) were added to refs/heads/5.3 by this push:
new 56cf07cd7a PHOENIX-7267 CsvBulkLoadTool fails job due to a bad record
with "(startline 1) EOF reached before encapsulated token finished" (#2399)
56cf07cd7a is described below
commit 56cf07cd7a549a29b83e7198a335ebd7e9e1dc37
Author: Xavier Fernandis <[email protected]>
AuthorDate: Sat Jun 13 04:06:20 2026 +0530
PHOENIX-7267 CsvBulkLoadTool fails job due to a bad record with "(startline
1) EOF reached before encapsulated token finished" (#2399)
---
.../org/apache/phoenix/util/CSVCommonsLoader.java | 19 ++--
phoenix-core-server/pom.xml | 4 +
.../phoenix/mapreduce/CsvToKeyValueMapper.java | 13 ++-
.../mapreduce/FormatToBytesWritableMapper.java | 11 ++-
.../apache/phoenix/end2end/CSVCommonsLoaderIT.java | 31 +++---
.../phoenix/mapreduce/CsvToKeyValueMapperTest.java | 104 +++++++++++++++++++++
.../phoenix/util/csv/CsvUpsertExecutorTest.java | 4 +-
.../pherf/result/impl/CSVFileResultHandler.java | 10 +-
.../phoenix/pherf/util/GoogleChartGenerator.java | 38 ++++----
pom.xml | 2 +-
10 files changed, 185 insertions(+), 51 deletions(-)
diff --git
a/phoenix-core-client/src/main/java/org/apache/phoenix/util/CSVCommonsLoader.java
b/phoenix-core-client/src/main/java/org/apache/phoenix/util/CSVCommonsLoader.java
index 3ec34088f6..89300c6860 100644
---
a/phoenix-core-client/src/main/java/org/apache/phoenix/util/CSVCommonsLoader.java
+++
b/phoenix-core-client/src/main/java/org/apache/phoenix/util/CSVCommonsLoader.java
@@ -105,12 +105,12 @@ public class CSVCommonsLoader {
* @return CSVFormat based on constructor settings.
*/
private CSVFormat buildFormat() {
- CSVFormat format =
-
CSVFormat.DEFAULT.withIgnoreEmptyLines(true).withDelimiter(asControlCharacter(fieldDelimiter))
- .withQuote(asControlCharacter(quoteCharacter));
+ CSVFormat.Builder builder =
CSVFormat.DEFAULT.builder().setIgnoreEmptyLines(true)
+ .setDelimiter(asControlCharacter(fieldDelimiter))
+ .setQuote(asControlCharacter(quoteCharacter));
if (escapeCharacter != null) {
- format = format.withEscape(asControlCharacter(escapeCharacter));
+ builder.setEscape(asControlCharacter(escapeCharacter));
}
switch (headerSource) {
@@ -119,17 +119,17 @@ public class CSVCommonsLoader {
break;
case IN_LINE:
// an empty string array triggers csv loader to grab the first line as
the header
- format = format.withHeader(new String[0]);
+ builder.setHeader(new String[0]);
break;
case SUPPLIED_BY_USER:
// a populated string array supplied by the user
- format = format.withHeader(columns.toArray(new
String[columns.size()]));
+ builder.setHeader(columns.toArray(new String[columns.size()]));
break;
default:
throw new RuntimeException("Header source was unable to be inferred.");
}
- return format;
+ return builder.get();
}
/**
@@ -146,12 +146,13 @@ public class CSVCommonsLoader {
* constructor determines the format for the CSV files.
*/
public void upsert(String fileName) throws Exception {
- CSVParser parser = CSVParser.parse(new File(fileName), Charsets.UTF_8,
format);
+ CSVParser parser =
CSVParser.builder().setFormat(format).setCharset(Charsets.UTF_8)
+ .setFile(new File(fileName)).get();
upsert(parser);
}
public void upsert(Reader reader) throws Exception {
- CSVParser parser = new CSVParser(reader, format);
+ CSVParser parser =
CSVParser.builder().setFormat(format).setReader(reader).get();
upsert(parser);
}
diff --git a/phoenix-core-server/pom.xml b/phoenix-core-server/pom.xml
index 92ee57d742..499522b7f5 100644
--- a/phoenix-core-server/pom.xml
+++ b/phoenix-core-server/pom.xml
@@ -30,6 +30,10 @@
<groupId>org.apache.phoenix</groupId>
<artifactId>phoenix-core-client</artifactId>
</dependency>
+ <dependency>
+ <groupId>commons-io</groupId>
+ <artifactId>commons-io</artifactId>
+ </dependency>
<!-- shaded thirdparty dependencies -->
<dependency>
diff --git
a/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/CsvToKeyValueMapper.java
b/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/CsvToKeyValueMapper.java
index 68e694e33f..c116b109d6 100644
---
a/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/CsvToKeyValueMapper.java
+++
b/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/CsvToKeyValueMapper.java
@@ -19,6 +19,7 @@ package org.apache.phoenix.mapreduce;
import java.io.IOException;
import java.io.StringReader;
+import java.io.UncheckedIOException;
import java.util.List;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
@@ -89,8 +90,8 @@ public class CsvToKeyValueMapper extends
FormatToBytesWritableMapper<CSVRecord>
private final CSVFormat csvFormat;
CsvLineParser(Character fieldDelimiter, Character quote, Character escape)
{
- this.csvFormat =
CSVFormat.DEFAULT.withIgnoreEmptyLines(true).withDelimiter(fieldDelimiter)
- .withEscape(escape).withQuote(quote);
+ this.csvFormat = CSVFormat.DEFAULT.builder().setIgnoreEmptyLines(true)
+ .setDelimiter(fieldDelimiter).setEscape(escape).setQuote(quote).get();
}
@Override
@@ -98,8 +99,12 @@ public class CsvToKeyValueMapper extends
FormatToBytesWritableMapper<CSVRecord>
// TODO Creating a new parser for each line seems terribly inefficient
but
// there's no public way to parse single lines via commons-csv. We
should update
// it to create a LineParser class like this one.
- CSVParser csvParser = new CSVParser(new StringReader(input), csvFormat);
- return Iterables.getFirst(csvParser, null);
+ try (CSVParser csvParser =
+ CSVParser.builder().setFormat(csvFormat).setReader(new
StringReader(input)).get()) {
+ return Iterables.getFirst(csvParser, null);
+ } catch (UncheckedIOException e) {
+ throw new IOException(e.getMessage(), e.getCause());
+ }
}
}
}
diff --git
a/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/FormatToBytesWritableMapper.java
b/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/FormatToBytesWritableMapper.java
index d99f76371b..2e0c0daa49 100644
---
a/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/FormatToBytesWritableMapper.java
+++
b/phoenix-core-server/src/main/java/org/apache/phoenix/mapreduce/FormatToBytesWritableMapper.java
@@ -110,6 +110,7 @@ public abstract class FormatToBytesWritableMapper<RECORD>
protected List<String> tableNames;
protected List<String> logicalNames;
protected MapperUpsertListener<RECORD> upsertListener;
+ protected boolean ignoreInvalidRows;
/*
* lookup table for column index. Index in the List matches to the index in
tableNames List
@@ -147,8 +148,8 @@ public abstract class FormatToBytesWritableMapper<RECORD>
throw new RuntimeException(e);
}
- upsertListener =
- new MapperUpsertListener<RECORD>(context,
conf.getBoolean(IGNORE_INVALID_ROW_CONFKEY, true));
+ ignoreInvalidRows = conf.getBoolean(IGNORE_INVALID_ROW_CONFKEY, true);
+ upsertListener = new MapperUpsertListener<RECORD>(context,
ignoreInvalidRows);
upsertExecutor = buildUpsertExecutor(conf);
preUpdateProcessor = PhoenixConfigurationUtil.loadPreUpsertProcessor(conf);
}
@@ -164,7 +165,13 @@ public abstract class FormatToBytesWritableMapper<RECORD>
try {
record = getLineParser().parse(value.toString());
} catch (IOException e) {
+ // When --ignore-errors (-g) is not set, a malformed record (e.g.
unterminated quote)
+ // fails the mapper and hence the entire job. When --ignore-errors is
set, the bad
+ // record is skipped and counted via the "Parser errors" counter.
context.getCounter(COUNTER_GROUP_NAME, "Parser errors").increment(1L);
+ if (!ignoreInvalidRows) {
+ throw new IOException("Error parsing input: " + e.getMessage(), e);
+ }
return;
}
diff --git
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java
index 2579f31c7a..2b477a691a 100644
---
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java
+++
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/CSVCommonsLoaderIT.java
@@ -117,7 +117,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
PreparedStatement statement =
conn.prepareStatement("SELECT SYMBOL, COMPANY FROM " + stockTableName);
ResultSet phoenixResultSet = statement.executeQuery();
- parser = new CSVParser(new StringReader(STOCK_CSV_VALUES_WITH_HEADER),
csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new StringReader(STOCK_CSV_VALUES_WITH_HEADER)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
int i = 0;
@@ -161,7 +162,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
PreparedStatement statement =
tenantConn.prepareStatement("SELECT SYMBOL, COMPANY FROM " +
stockTableMultiName);
ResultSet phoenixResultSet = statement.executeQuery();
- parser = new CSVParser(new StringReader(STOCK_CSV_VALUES_WITH_HEADER),
csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new StringReader(STOCK_CSV_VALUES_WITH_HEADER)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
int i = 0;
@@ -200,7 +202,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
PreparedStatement statement =
conn.prepareStatement("SELECT SYMBOL, COMPANY FROM " + stockTableName);
ResultSet phoenixResultSet = statement.executeQuery();
- parser = new CSVParser(new StringReader(STOCK_TDV_VALUES_WITH_HEADER),
csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new StringReader(STOCK_TDV_VALUES_WITH_HEADER)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
int i = 0;
@@ -239,8 +242,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
PreparedStatement statement =
conn.prepareStatement("SELECT SYMBOL, COMPANY FROM " + stockTableName);
ResultSet phoenixResultSet = statement.executeQuery();
- parser =
- new CSVParser(new StringReader(STOCK_CSV_VALUES_WITH_DELIMITER),
csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new StringReader(STOCK_CSV_VALUES_WITH_DELIMITER)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
int i = 0;
@@ -279,7 +282,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
PreparedStatement statement =
conn.prepareStatement("SELECT SYMBOL, COMPANY FROM " + stockTableName);
ResultSet phoenixResultSet = statement.executeQuery();
- parser = new CSVParser(new StringReader(STOCK_CSV_VALUES),
csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new StringReader(STOCK_CSV_VALUES)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
int i = 0;
@@ -317,7 +321,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
PreparedStatement statement =
conn.prepareStatement("SELECT SYMBOL, COMPANY FROM " + stockTableName);
ResultSet phoenixResultSet = statement.executeQuery();
- parser = new CSVParser(new StringReader(STOCK_CSV_VALUES),
csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new StringReader(STOCK_CSV_VALUES)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
int i = 0;
@@ -356,7 +361,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
PreparedStatement statement =
conn.prepareStatement("SELECT SYMBOL, COMPANY FROM " + stockTableName);
ResultSet phoenixResultSet = statement.executeQuery();
- parser = new CSVParser(new StringReader(STOCK_CSV_VALUES),
csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new StringReader(STOCK_CSV_VALUES)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
assertEquals(record.get(0), phoenixResultSet.getString(1));
@@ -483,7 +489,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
"SELECT CKEY, CVARCHAR, CCHAR, CINTEGER, CDECIMAL, CUNSIGNED_INT,
CBOOLEAN, CBIGINT, CUNSIGNED_LONG, CTIME, CDATE FROM "
+ DATATYPE_TABLE);
ResultSet phoenixResultSet = statement.executeQuery();
- parser = new CSVParser(new StringReader(DATATYPES_CSV_VALUES),
csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new StringReader(DATATYPES_CSV_VALUES)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
@@ -531,8 +538,8 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
PreparedStatement statement =
conn.prepareStatement("SELECT MYKEY, MYVALUE FROM " +
ENCAPSULATED_CHARS_TABLE);
ResultSet phoenixResultSet = statement.executeQuery();
- parser = new CSVParser(new
StringReader(CSV_VALUES_ENCAPSULATED_CONTROL_CHARS_WITH_HEADER),
- csvUtil.getFormat());
+ parser = CSVParser.builder().setFormat(csvUtil.getFormat())
+ .setReader(new
StringReader(CSV_VALUES_ENCAPSULATED_CONTROL_CHARS_WITH_HEADER)).get();
for (CSVRecord record : parser) {
assertTrue(phoenixResultSet.next());
int i = 0;
@@ -568,7 +575,7 @@ public class CSVCommonsLoaderIT extends
ParallelStatsDisabledIT {
fail();
} catch (RuntimeException e) {
assertTrue(e.getMessage(),
- e.getMessage().contains("invalid char between encapsulated token and
delimiter"));
+ e.getMessage().contains("Invalid character between encapsulated
token and delimiter"));
}
} finally {
if (parser != null) parser.close();
diff --git
a/phoenix-core/src/test/java/org/apache/phoenix/mapreduce/CsvToKeyValueMapperTest.java
b/phoenix-core/src/test/java/org/apache/phoenix/mapreduce/CsvToKeyValueMapperTest.java
index 242166ceb1..4247361ea3 100644
---
a/phoenix-core/src/test/java/org/apache/phoenix/mapreduce/CsvToKeyValueMapperTest.java
+++
b/phoenix-core/src/test/java/org/apache/phoenix/mapreduce/CsvToKeyValueMapperTest.java
@@ -18,9 +18,15 @@
package org.apache.phoenix.mapreduce;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import java.io.IOException;
+import java.io.StringReader;
+import java.io.UncheckedIOException;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
import org.junit.Test;
@@ -49,4 +55,102 @@ public class CsvToKeyValueMapperTest {
assertTrue(parsed.isConsistent());
assertEquals(1, parsed.getRecordNumber());
}
+
+ @Test(expected = IOException.class)
+ public void testCsvLineParserUnterminatedQuoteThrowsIOException() throws
IOException {
+ CsvToKeyValueMapper.CsvLineParser lineParser =
+ new CsvToKeyValueMapper.CsvLineParser(',', '"', '\\');
+ // Unterminated quoted field should throw IOException
+ lineParser.parse("1,\"unterminated quote,3");
+ }
+
+ @Test(expected = IOException.class)
+ public void testCsvLineParserEOFInEncapsulatedToken() throws IOException {
+ CsvToKeyValueMapper.CsvLineParser lineParser =
+ new CsvToKeyValueMapper.CsvLineParser(',', '"', '\\');
+ // This simulates the exact error: "EOF reached before encapsulated token
finished"
+ lineParser.parse("3,\"Charlie,Sales");
+ }
+
+ @Test
+ public void testCsvLineParserEmptyLineReturnsNull() throws IOException {
+ CsvToKeyValueMapper.CsvLineParser lineParser =
+ new CsvToKeyValueMapper.CsvLineParser(',', '"', '\\');
+ CSVRecord parsed = lineParser.parse("");
+ assertNull(parsed);
+ }
+
+ @Test
+ public void testCsvLineParserValidRecordAfterBadRecord() throws IOException {
+ CsvToKeyValueMapper.CsvLineParser lineParser =
+ new CsvToKeyValueMapper.CsvLineParser(',', '"', '\\');
+
+ // Bad record throws
+ try {
+ lineParser.parse("3,\"Charlie,Sales");
+ fail("Expected IOException for unterminated quote");
+ } catch (IOException e) {
+ // expected
+ }
+
+ // Valid record still parses fine (parser is stateless per line)
+ CSVRecord parsed = lineParser.parse("4,Diana,Finance");
+ assertEquals("4", parsed.get(0));
+ assertEquals("Diana", parsed.get(1));
+ assertEquals("Finance", parsed.get(2));
+ }
+
+ @Test
+ public void testCsvLineParserEmbeddedCommaInQuotedField() throws IOException
{
+ CsvToKeyValueMapper.CsvLineParser lineParser =
+ new CsvToKeyValueMapper.CsvLineParser(',', '"', '\\');
+ // Valid: comma inside quoted field
+ CSVRecord parsed = lineParser.parse("1,\"Sales, Marketing\",HR");
+ assertEquals("1", parsed.get(0));
+ assertEquals("Sales, Marketing", parsed.get(1));
+ assertEquals("HR", parsed.get(2));
+ }
+
+ @Test
+ public void testCsvLineParserOnlyDelimiters() throws IOException {
+ CsvToKeyValueMapper.CsvLineParser lineParser =
+ new CsvToKeyValueMapper.CsvLineParser(',', '"', '\\');
+ // Valid: three empty fields
+ CSVRecord parsed = lineParser.parse(",,");
+ assertEquals("", parsed.get(0));
+ assertEquals("", parsed.get(1));
+ assertEquals("", parsed.get(2));
+ }
+
+ @Test(expected = IOException.class)
+ public void testCsvLineParserSingleDanglingQuote() throws IOException {
+ CsvToKeyValueMapper.CsvLineParser lineParser =
+ new CsvToKeyValueMapper.CsvLineParser(',', '"', '\\');
+ // Single dangling quote - unterminated encapsulated token
+ lineParser.parse("\"");
+ }
+
+ @Test(expected = IOException.class)
+ public void testCsvLineParserInvalidCharAfterQuotedField() throws
IOException {
+ CsvToKeyValueMapper.CsvLineParser lineParser =
+ new CsvToKeyValueMapper.CsvLineParser(',', '"', '\\');
+ // Invalid char between closing quote and delimiter: "Eve,"Bad
+ lineParser.parse("5,\"Eve,\"Bad quote handling");
+ }
+
+ @Test
+ public void testCsvParserIteratorThrowsUncheckedIOException() throws
IOException {
+ // Proves that the CSVParser iterator throws UncheckedIOException on
malformed input.
+ // This is WHY CsvLineParser.parse() needs to catch UncheckedIOException.
+ CSVFormat format =
CSVFormat.DEFAULT.builder().setIgnoreEmptyLines(true).get();
+ try (CSVParser parser = CSVParser.builder().setFormat(format)
+ .setReader(new StringReader("1,\"unterminated quote")).get()) {
+ for (CSVRecord record : parser) {
+ fail("Should have thrown UncheckedIOException");
+ }
+ } catch (UncheckedIOException e) {
+ // This is what the iterator throws — confirming Uncheck.get() wraps
IOException
+ assertTrue(e.getCause() instanceof IOException);
+ }
+ }
}
diff --git
a/phoenix-core/src/test/java/org/apache/phoenix/util/csv/CsvUpsertExecutorTest.java
b/phoenix-core/src/test/java/org/apache/phoenix/util/csv/CsvUpsertExecutorTest.java
index eed02eb2cb..1044ae96f2 100644
---
a/phoenix-core/src/test/java/org/apache/phoenix/util/csv/CsvUpsertExecutorTest.java
+++
b/phoenix-core/src/test/java/org/apache/phoenix/util/csv/CsvUpsertExecutorTest.java
@@ -18,6 +18,7 @@
package org.apache.phoenix.util.csv;
import java.io.IOException;
+import java.io.StringReader;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
@@ -60,7 +61,8 @@ public class CsvUpsertExecutorTest extends
AbstractUpsertExecutorTest<CSVRecord,
}
}
String inputRecord = Joiner.on(',').join(columnValues);
- return Iterables.getFirst(CSVParser.parse(inputRecord, CSVFormat.DEFAULT),
null);
+ return Iterables.getFirst(CSVParser.builder().setFormat(CSVFormat.DEFAULT)
+ .setReader(new StringReader(inputRecord)).get(), null);
}
@Before
diff --git
a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/impl/CSVFileResultHandler.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/impl/CSVFileResultHandler.java
index 2928c3f727..e2a04b0157 100644
---
a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/impl/CSVFileResultHandler.java
+++
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/result/impl/CSVFileResultHandler.java
@@ -23,6 +23,8 @@ import java.io.PrintWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVPrinter;
@@ -47,7 +49,8 @@ public class CSVFileResultHandler extends CSVResultHandler {
public synchronized List<Result> read() throws IOException {
util.ensureBaseResultDirExists();
File file = new File(resultFileName);
- try (CSVParser parser = CSVParser.parse(file, Charset.defaultCharset(),
CSVFormat.DEFAULT)) {
+ try (CSVParser parser = CSVParser.builder().setFormat(CSVFormat.DEFAULT)
+ .setCharset(Charset.defaultCharset()).setFile(file).get()) {
List<CSVRecord> records = parser.getRecords();
List<Result> results = new ArrayList<>();
String header = null;
@@ -55,11 +58,12 @@ public class CSVFileResultHandler extends CSVResultHandler {
// First record is the CSV Header
if (record.getRecordNumber() == 1) {
- header = record.toString();
+ header = StreamSupport.stream(record.spliterator(), false)
+ .collect(Collectors.joining(PherfConstants.RESULT_FILE_DELIMETER));
continue;
}
List<ResultValue> resultValues = new ArrayList<>();
- for (String val :
record.toString().split(PherfConstants.RESULT_FILE_DELIMETER)) {
+ for (String val : record) {
resultValues.add(new ResultValue(val));
}
Result result = new Result(resultFileDetails, header, resultValues);
diff --git
a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/GoogleChartGenerator.java
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/GoogleChartGenerator.java
index 5960bb070c..d6cac7d359 100644
---
a/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/GoogleChartGenerator.java
+++
b/phoenix-pherf/src/main/java/org/apache/phoenix/pherf/util/GoogleChartGenerator.java
@@ -91,27 +91,27 @@ public class GoogleChartGenerator {
String resultFileName = resultDir + PherfConstants.PATH_SEPARATOR +
PherfConstants.RESULT_PREFIX
+ label + ResultFileDetails.CSV_AGGREGATE_PERFORMANCE.getExtension();
- FileReader in = new FileReader(resultFileName);
- final CSVParser parser = new CSVParser(in, CSVFormat.DEFAULT.withHeader());
-
- for (CSVRecord record : parser) {
- String group = record.get("QUERY_GROUP");
- String query = record.get("QUERY");
- String explain = record.get("EXPLAIN_PLAN");
- String tenantId = record.get("TENANT_ID");
- long avgTime = Long.parseLong(record.get("AVG_TIME_MS"));
- long minTime = Long.parseLong(record.get("AVG_MIN_TIME_MS"));
- long numRuns = Long.parseLong(record.get("RUN_COUNT"));
- long rowCount = Long.parseLong(record.get("RESULT_ROW_COUNT"));
- Node node = new Node(minTime, avgTime, numRuns, explain, query,
tenantId, label, rowCount);
-
- if (datanodes.containsKey(group)) {
- datanodes.get(group).getDataSet().put(label, node);
- } else {
- datanodes.put(group, new DataNode(label, node));
+ try (CSVParser parser =
+
CSVParser.builder().setFormat(CSVFormat.DEFAULT.builder().setHeader().get())
+ .setReader(new FileReader(resultFileName)).get()) {
+ for (CSVRecord record : parser) {
+ String group = record.get("QUERY_GROUP");
+ String query = record.get("QUERY");
+ String explain = record.get("EXPLAIN_PLAN");
+ String tenantId = record.get("TENANT_ID");
+ long avgTime = Long.parseLong(record.get("AVG_TIME_MS"));
+ long minTime = Long.parseLong(record.get("AVG_MIN_TIME_MS"));
+ long numRuns = Long.parseLong(record.get("RUN_COUNT"));
+ long rowCount = Long.parseLong(record.get("RESULT_ROW_COUNT"));
+ Node node = new Node(minTime, avgTime, numRuns, explain, query,
tenantId, label, rowCount);
+
+ if (datanodes.containsKey(group)) {
+ datanodes.get(group).getDataSet().put(label, node);
+ } else {
+ datanodes.put(group, new DataNode(label, node));
+ }
}
}
- parser.close();
}
/**
diff --git a/pom.xml b/pom.xml
index cac9a90d55..957b373067 100644
--- a/pom.xml
+++ b/pom.xml
@@ -112,7 +112,7 @@
<protoc.version>2.5.0</protoc.version>
<commons-io.version>2.18.0</commons-io.version>
<commons-lang3.version>3.18.0</commons-lang3.version>
- <commons-csv.version>1.0</commons-csv.version>
+ <commons-csv.version>1.14.1</commons-csv.version>
<commons-compress.version>1.26.0</commons-compress.version>
<sqlline.version>1.9.0</sqlline.version>
<jcip-annotations.version>1.0-1</jcip-annotations.version>