This is an automated email from the ASF dual-hosted git repository. ggregory pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-csv.git
The following commit(s) were added to refs/heads/master by this push: new 480b90f [CSV-238] Escape quotes in CLOBs. 480b90f is described below commit 480b90febb39d7a3dd6f55d6082434ef09eb0b5f Author: Gary Gregory <gardgreg...@gmail.com> AuthorDate: Wed Feb 27 10:41:04 2019 -0500 [CSV-238] Escape quotes in CLOBs. Closes #39. --- src/changes/changes.xml | 17 ++++----- .../java/org/apache/commons/csv/CSVFormat.java | 40 +++++++++++++++++----- .../org/apache/commons/csv/CSVPrinterTest.java | 5 ++- 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 04622d9..0440fbb 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -38,14 +38,15 @@ <title>Release Notes</title> </properties> <body> - <release version="1.7" date="tba" description="Feature and bug fix release"> - <action issue="CSV-233" type="add" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV and TSV.</action> + <release version="1.7" date="2019-MM-DD" description="Feature and bug fix release (Java 8)"> + <action issue="CSV-233" type="add" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV anJ TSV.</action> <action issue="CSV-208" type="fix" dev="ggregory" due-to="Jurrie Overgoor">Fix escape character for POSTGRESQL_TEXT and POSTGRESQL_CSV formats.</action> <action issue="CSV-232" type="fix" dev="ggregory" due-to="Jurrie Overgoor, Gary Gregory">Site link "Source Repository" does not work.</action> <action issue="CSV-234" type="add" dev="ggregory" due-to="Roberto Benedetti, Gary Gregory">Add support for java.sql.Clob.</action> <action issue="CSV-237" type="update" dev="ggregory" due-to="Gary Gregory">Update to Java 8.</action> + <action issue="CSV-238" type="fix" dev="ggregory" due-to="Stephen Olander-Waters">Escape quotes in CLOBs #39.</action> </release> - <release version="1.6" date="2018-09-22" description="Feature and bug fix release"> + <release version="1.6" date="2018-09-22" description="Feature and bug fix release (Java 7)"> <action issue="CSV-231" type="update" dev="britter">Add more documentation to CSVPrinter.</action> <action issue="CSV-217" type="add" dev="ggregory" due-to="Korolyov Alexei">Add autoFlush option for CsvPrinter. PR #24.</action> <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 @@ <action issue="CSV-225" type="fix" dev="ggregory" due-to="Anson Schwabecher">Parse method should avoid creating a redundant BufferedReader.</action> <action issue="CSV-233" type="fix" dev="ggregory" due-to="Gary Gregory">Add predefined CSVFormats for printing MongoDB CSV and TSV.</action> </release> - <release version="1.5" date="2017-09-03" description="Feature and bug fix release"> + <release version="1.5" date="2017-09-03" description="Feature and bug fix release (Java 7)"> <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> <action issue="CSV-194" type="fix" dev="ggregory" due-to="Marc Prud'hommeaux">Fix outdated comments about FileReader in CSVParser #13</action> <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 @@ <action issue="CSV-207" type="add" dev="ggregory" due-to="Gary Gregory">Provide a CSV Format for printing PostgreSQL CSV and Text formats.</action> <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> </release> - <release version="1.4" date="2016-05-28" description="Feature and bug fix release"> + <release version="1.4" date="2016-05-28" description="Feature and bug fix release (Java 6)"> <action issue="CSV-181" type="update" dev="ggregory" due-to="Gary Gregory">Make CSVPrinter.print(Object) GC-free.</action> <action issue="CSV-182" type="add" dev="ggregory" due-to="Gary Gregory">Allow some printing operations directly from CSVFormat.</action> <action issue="CSV-183" type="update" dev="ggregory">Drop ferc.gov tests.</action> </release> - <release version="1.3" date="2016-05-09" description="Feature and bug fix release"> + <release version="1.3" date="2016-05-09" description="Feature and bug fix release (Java 6)"> <action issue="CSV-179" type="add" dev="britter">Add shortcut method for using first record as header to CSVFormat</action> <action issue="CSV-180" type="add" dev="britter">Add withHeader(Class<? extends Enum>) to CSVFormat</action> <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 @@ <action issue="CSV-177" type="add" dev="ggregory" due-to="Gary Gregory">Support trimming leading and trailing blanks.</action> <action issue="CSV-178" type="add" dev="ggregory" due-to="Gary Gregory">Create default formats for Informix UNLOAD and UNLOAD CSV.</action> </release> - <release version="1.2" date="2015-08-24" description="Feature and bug fix release"> + <release version="1.2" date="2015-08-24" description="Feature and bug fix release (Java 6)"> <action issue="CSV-145" type="fix" dev="ggregory" due-to="Frank Ulbricht">CSVFormat.with* methods clear the header comments</action> <action issue="CSV-156" type="fix" dev="ggregory" due-to="Jason Steenstra-Pickens">Incorrect Javadoc on QuoteMode.NONE</action> <action issue="CSV-157" type="add" dev="ggregory">Add enum CSVFormat.Predefined that contains the default CSVFormat values.</action> @@ -107,7 +108,7 @@ <action issue="CSV-131" type="add" dev="ggregory" due-to="Holger Stratmann">Save positions of records to enable random access</action> <action issue="CSV-139" type="add" dev="ggregory">CSVPrinter.printRecord(ResultSet) with metadata</action> </release> - <release version="1.0" date="2014-08-14" description="First release"> + <release version="1.0" date="2014-08-14" description="First release (Java 6)"> <action issue="CSV-125" type="fix" dev="britter">No longer works with Java 6</action> <action issue="CSV-122" type="fix" dev="britter" due-to="Mike Lewis">NullPointerException when empty header string and and null string of ""</action> <action issue="CSV-117" type="update" dev="sebb">Validate format parameters in constructor</action> diff --git a/src/main/java/org/apache/commons/csv/CSVFormat.java b/src/main/java/org/apache/commons/csv/CSVFormat.java index 7fcf830..6f77bef 100644 --- a/src/main/java/org/apache/commons/csv/CSVFormat.java +++ b/src/main/java/org/apache/commons/csv/CSVFormat.java @@ -1240,8 +1240,7 @@ public final class CSVFormat implements Serializable { out.append(getDelimiter()); } if (isQuoteCharacterSet()) { - // the original object is needed so can check for Number - printWithQuotes(reader, out, newRecord); + printWithQuotes(reader, out); } else if (isEscapeCharacterSet()) { printWithEscapes(reader, out); } else if (out instanceof Writer) { @@ -1501,18 +1500,43 @@ public final class CSVFormat implements Serializable { * * @throws IOException */ - private void printWithQuotes(final Reader reader, final Appendable out, final boolean newRecord) - throws IOException { - final char quoteChar = getQuoteCharacter().charValue(); + private void printWithQuotes(final Reader reader, final Appendable out) throws IOException { if (getQuoteMode() == QuoteMode.NONE) { printWithEscapes(reader, out); return; } - out.append(quoteChar); - IOUtils.copy(reader, out); - out.append(quoteChar); + int pos = 0; + + final char quote = getQuoteCharacter().charValue(); + final StringBuilder builder = new StringBuilder(IOUtils.DEFAULT_BUFFER_SIZE); + + out.append(quote); + + int c; + while (-1 != (c = reader.read())) { + builder.append((char) c); + if (c == quote) { + // write out segment up until this char + if (pos > 0) { + out.append(builder.substring(0, pos)); + builder.setLength(0); + pos = -1; + } + + out.append(quote); + out.append((char) c); + } + pos++; + } + + // write last segment + if (pos > 0) { + out.append(builder.substring(0, pos)); + } + + out.append(quote); } @Override diff --git a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java index 18856cf..6a0e3af 100644 --- a/src/test/java/org/apache/commons/csv/CSVPrinterTest.java +++ b/src/test/java/org/apache/commons/csv/CSVPrinterTest.java @@ -219,8 +219,11 @@ public class CSVPrinterTest { try (final Statement statement = connection.createStatement()) { statement.execute("CREATE TABLE TEST(ID INT PRIMARY KEY, NAME VARCHAR(255), TEXT CLOB)"); statement.execute("insert into TEST values(1, 'r1', 'long text 1')"); - longText2 = StringUtils.repeat('a', (IOUtils.DEFAULT_BUFFER_SIZE * 2) + 1); + longText2 = StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 4); + longText2 += "\"\r\n\"a\""; + longText2 += StringUtils.repeat('a', IOUtils.DEFAULT_BUFFER_SIZE - 1); statement.execute("insert into TEST values(2, 'r2', '" + longText2 + "')"); + longText2 = longText2.replace("\"","\"\""); } }