Skip to content

Commit 480b90f

Browse files
author
Gary Gregory
committed
[CSV-238] Escape quotes in CLOBs.
Closes apache#39.
1 parent e24dc31 commit 480b90f

3 files changed

Lines changed: 45 additions & 17 deletions

File tree

src/changes/changes.xml

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,14 +38,15 @@
3838
<title>Release Notes</title>
3939
</properties>
4040
<body>
41-
<release version="1.7" date="tba" description="Feature and bug fix release">
42-
<action issue="CSV-233" type="add" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV and TSV.</action>
41+
<release version="1.7" date="2019-MM-DD" description="Feature and bug fix release (Java 8)">
42+
<action issue="CSV-233" type="add" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV anJ TSV.</action>
4343
<action issue="CSV-208" type="fix" dev="ggregory" due-to="Jurrie Overgoor">Fix escape character for POSTGRESQL_TEXT and POSTGRESQL_CSV formats.</action>
4444
<action issue="CSV-232" type="fix" dev="ggregory" due-to="Jurrie Overgoor, Gary Gregory">Site link "Source Repository" does not work.</action>
4545
<action issue="CSV-234" type="add" dev="ggregory" due-to="Roberto Benedetti, Gary Gregory">Add support for java.sql.Clob.</action>
4646
<action issue="CSV-237" type="update" dev="ggregory" due-to="Gary Gregory">Update to Java 8.</action>
47+
<action issue="CSV-238" type="fix" dev="ggregory" due-to="Stephen Olander-Waters">Escape quotes in CLOBs #39.</action>
4748
</release>
48-
<release version="1.6" date="2018-09-22" description="Feature and bug fix release">
49+
<release version="1.6" date="2018-09-22" description="Feature and bug fix release (Java 7)">
4950
<action issue="CSV-231" type="update" dev="britter">Add more documentation to CSVPrinter.</action>
5051
<action issue="CSV-217" type="add" dev="ggregory" due-to="Korolyov Alexei">Add autoFlush option for CsvPrinter. PR #24.</action>
5152
<action issue="CSV-219" type="fix" dev="ggregory" due-to="Zhang Hongda">The behavior of quote char using is not similar as Excel does when the first string contains CJK char(s).</action>
@@ -57,7 +58,7 @@
5758
<action issue="CSV-225" type="fix" dev="ggregory" due-to="Anson Schwabecher">Parse method should avoid creating a redundant BufferedReader.</action>
5859
<action issue="CSV-233" type="fix" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV and TSV.</action>
5960
</release>
60-
<release version="1.5" date="2017-09-03" description="Feature and bug fix release">
61+
<release version="1.5" date="2017-09-03" description="Feature and bug fix release (Java 7)">
6162
<action issue="CSV-203" type="fix" dev="ggregory" due-to="Richard Wheeldon, Kai Paroth">withNullString value is printed without quotes when QuoteMode.ALL is specified; add QuoteMode.ALL_NON_NULL. PR #17.</action>
6263
<action issue="CSV-194" type="fix" dev="ggregory" due-to="Marc Prud'hommeaux">Fix outdated comments about FileReader in CSVParser #13</action>
6364
<action issue="CSV-193" type="fix" dev="ggregory" due-to="Matthias Wiehl">Fix incorrect method name 'withFirstRowAsHeader' in user guide.</action>
@@ -72,12 +73,12 @@
7273
<action issue="CSV-207" type="add" dev="ggregory" due-to="Gary Gregory">Provide a CSV Format for printing PostgreSQL CSV and Text formats.</action>
7374
<action issue="CSV-214" type="add" dev="ggregory" due-to="Nitin Mahendru, Gary Gregory">Adding a placeholder in the Lexer and CSV parser to store the end-of-line string.</action>
7475
</release>
75-
<release version="1.4" date="2016-05-28" description="Feature and bug fix release">
76+
<release version="1.4" date="2016-05-28" description="Feature and bug fix release (Java 6)">
7677
<action issue="CSV-181" type="update" dev="ggregory" due-to="Gary Gregory">Make CSVPrinter.print(Object) GC-free.</action>
7778
<action issue="CSV-182" type="add" dev="ggregory" due-to="Gary Gregory">Allow some printing operations directly from CSVFormat.</action>
7879
<action issue="CSV-183" type="update" dev="ggregory">Drop ferc.gov tests.</action>
7980
</release>
80-
<release version="1.3" date="2016-05-09" description="Feature and bug fix release">
81+
<release version="1.3" date="2016-05-09" description="Feature and bug fix release (Java 6)">
8182
<action issue="CSV-179" type="add" dev="britter">Add shortcut method for using first record as header to CSVFormat</action>
8283
<action issue="CSV-180" type="add" dev="britter">Add withHeader(Class&lt;? extends Enum&gt;) to CSVFormat</action>
8384
<action issue="CSV-167" type="update" dev="sebb" due-to="Rene">Comment line hides next record; update Javadoc to make behaviour clear</action>
@@ -91,7 +92,7 @@
9192
<action issue="CSV-177" type="add" dev="ggregory" due-to="Gary Gregory">Support trimming leading and trailing blanks.</action>
9293
<action issue="CSV-178" type="add" dev="ggregory" due-to="Gary Gregory">Create default formats for Informix UNLOAD and UNLOAD CSV.</action>
9394
</release>
94-
<release version="1.2" date="2015-08-24" description="Feature and bug fix release">
95+
<release version="1.2" date="2015-08-24" description="Feature and bug fix release (Java 6)">
9596
<action issue="CSV-145" type="fix" dev="ggregory" due-to="Frank Ulbricht">CSVFormat.with* methods clear the header comments</action>
9697
<action issue="CSV-156" type="fix" dev="ggregory" due-to="Jason Steenstra-Pickens">Incorrect Javadoc on QuoteMode.NONE</action>
9798
<action issue="CSV-157" type="add" dev="ggregory">Add enum CSVFormat.Predefined that contains the default CSVFormat values.</action>
@@ -107,7 +108,7 @@
107108
<action issue="CSV-131" type="add" dev="ggregory" due-to="Holger Stratmann">Save positions of records to enable random access</action>
108109
<action issue="CSV-139" type="add" dev="ggregory">CSVPrinter.printRecord(ResultSet) with metadata</action>
109110
</release>
110-
<release version="1.0" date="2014-08-14" description="First release">
111+
<release version="1.0" date="2014-08-14" description="First release (Java 6)">
111112
<action issue="CSV-125" type="fix" dev="britter">No longer works with Java 6</action>
112113
<action issue="CSV-122" type="fix" dev="britter" due-to="Mike Lewis">NullPointerException when empty header string and and null string of ""</action>
113114
<action issue="CSV-117" type="update" dev="sebb">Validate format parameters in constructor</action>

src/main/java/org/apache/commons/csv/CSVFormat.java

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1240,8 +1240,7 @@ private void print(final Reader reader, final Appendable out, final boolean newR
12401240
out.append(getDelimiter());
12411241
}
12421242
if (isQuoteCharacterSet()) {
1243-
// the original object is needed so can check for Number
1244-
printWithQuotes(reader, out, newRecord);
1243+
printWithQuotes(reader, out);
12451244
} else if (isEscapeCharacterSet()) {
12461245
printWithEscapes(reader, out);
12471246
} else if (out instanceof Writer) {
@@ -1501,18 +1500,43 @@ private void printWithQuotes(final Object object, final CharSequence value, fina
15011500
*
15021501
* @throws IOException
15031502
*/
1504-
private void printWithQuotes(final Reader reader, final Appendable out, final boolean newRecord)
1505-
throws IOException {
1506-
final char quoteChar = getQuoteCharacter().charValue();
1503+
private void printWithQuotes(final Reader reader, final Appendable out) throws IOException {
15071504

15081505
if (getQuoteMode() == QuoteMode.NONE) {
15091506
printWithEscapes(reader, out);
15101507
return;
15111508
}
15121509

1513-
out.append(quoteChar);
1514-
IOUtils.copy(reader, out);
1515-
out.append(quoteChar);
1510+
int pos = 0;
1511+
1512+
final char quote = getQuoteCharacter().charValue();
1513+
final StringBuilder builder = new StringBuilder(IOUtils.DEFAULT_BUFFER_SIZE);
1514+
1515+
out.append(quote);
1516+
1517+
int c;
1518+
while (-1 != (c = reader.read())) {
1519+
builder.append((char) c);
1520+
if (c == quote) {
1521+
// write out segment up until this char
1522+
if (pos > 0) {
1523+
out.append(builder.substring(0, pos));
1524+
builder.setLength(0);
1525+
pos = -1;
1526+
}
1527+
1528+
out.append(quote);
1529+
out.append((char) c);
1530+
}
1531+
pos++;
1532+
}
1533+
1534+
// write last segment
1535+
if (pos > 0) {
1536+
out.append(builder.substring(0, pos));
1537+
}
1538+
1539+
out.append(quote);
15161540
}
15171541

15181542
@Override

src/test/java/org/apache/commons/csv/CSVPrinterTest.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,8 +219,11 @@ private void setUpTable(final Connection connection) throws SQLException {
219219
try (final Statement statement = connection.createStatement()) {
220220
statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255), TEXT CLOB)");
221221
statement.execute("insert into TEST values(1, 'r1', 'long text 1')");
222-
longText2 = StringUtils.repeat('a', (IOUtils.DEFAULT_BUFFER_SIZE * 2) + 1);
222+
longText2 = StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 4);
223+
longText2 += "\"\r\n\"a\"";
224+
longText2 += StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 1);
223225
statement.execute("insert into TEST values(2, 'r2', '" + longText2 + "')");
226+
longText2 = longText2.replace("\"","\"\"");
224227
}
225228
}
226229

0 commit comments

Comments
 (0)