From 9f122fabbe142fa72f1362bd4a969ad84a525967 Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 12 Oct 2021 15:17:45 +0200 Subject: [PATCH 1/2] Ported QuoteStyle feature. --- .../org/relique/jdbc/csv/CsvConnection.java | 9 +++---- .../java/org/relique/jdbc/csv/CsvDriver.java | 15 ++++++----- .../org/relique/jdbc/csv/CsvRawReader.java | 12 ++++----- .../java/org/relique/jdbc/csv/QuoteStyle.java | 27 +++++++++++++++++++ .../org/relique/jdbc/csv/TestCsvDriver.java | 23 ++++++++++++++++ src/testdata/nullquotestyle.csv | 5 ++++ 6 files changed, 73 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/relique/jdbc/csv/QuoteStyle.java create mode 100644 src/testdata/nullquotestyle.csv diff --git a/src/main/java/org/relique/jdbc/csv/CsvConnection.java b/src/main/java/org/relique/jdbc/csv/CsvConnection.java index fb9eddfd..35e3a821 100644 --- a/src/main/java/org/relique/jdbc/csv/CsvConnection.java +++ b/src/main/java/org/relique/jdbc/csv/CsvConnection.java @@ -140,7 +140,7 @@ public class CsvConnection implements Connection private boolean autoCommit; - private String quoteStyle; + private QuoteStyle quoteStyle; private ArrayList fixedWidthColumns = null; @@ -492,7 +492,7 @@ else if (prop.length() == 0) setSkipLeadingLines(info.getProperty(CsvDriver.SKIP_LEADING_LINES, CsvDriver.DEFAULT_SKIP_LEADING_LINES)); setQuoteStyle(info.getProperty(CsvDriver.QUOTE_STYLE, - CsvDriver.DEFAULT_QUOTE_STYLE)); + CsvDriver.DEFAULT_QUOTE_STYLE.name())); setIgnoreUnparseableLines(Boolean.parseBoolean(info.getProperty( CsvDriver.IGNORE_UNPARSEABLE_LINES, CsvDriver.DEFAULT_IGNORE_UNPARSEABLE_LINES))); @@ -556,13 +556,12 @@ protected CsvConnection(TableReader tableReader, Properties info, } } - private void setQuoteStyle(String property) + private void setQuoteStyle(QuoteStyle property) { - // TODO Auto-generated method stub quoteStyle = property; } - public String getQuoteStyle() + public QuoteStyle getQuoteStyle() { return quoteStyle; } diff --git a/src/main/java/org/relique/jdbc/csv/CsvDriver.java b/src/main/java/org/relique/jdbc/csv/CsvDriver.java index f6abfdf9..a205529c 100644 --- a/src/main/java/org/relique/jdbc/csv/CsvDriver.java +++ b/src/main/java/org/relique/jdbc/csv/CsvDriver.java @@ -103,7 +103,7 @@ public class CsvDriver implements Driver // choosing Rome makes sure we change chronology from Julian to Gregorian on // 1582-10-04/15, as SQL does. public static final String QUOTE_STYLE = "quoteStyle"; - public static final String DEFAULT_QUOTE_STYLE = "SQL"; + public static final QuoteStyle DEFAULT_QUOTE_STYLE = QuoteStyle.valueOf("SQL"); public static final String READER_CLASS_PREFIX = "class:"; public static final String ZIP_FILE_PREFIX = "zip:"; @@ -309,7 +309,7 @@ public static void writeToCsv(ResultSet resultSet, PrintStream out, boolean writ { String separator = DEFAULT_SEPARATOR; Character quoteChar = Character.valueOf(DEFAULT_QUOTECHAR); - String quoteStyle = DEFAULT_QUOTE_STYLE; + QuoteStyle quoteStyle = DEFAULT_QUOTE_STYLE; String dateFormat = DEFAULT_DATE_FORMAT; String timeFormat = DEFAULT_TIME_FORMAT; String timestampFormat = DEFAULT_TIMESTAMP_FORMAT; @@ -418,17 +418,17 @@ else if (columnType == Types.TIMESTAMP) out.flush(); } - private static String addQuotes(String value, String separator, char quoteChar, String quoteStyle) + private static String addQuotes(String value, String separator, char quoteChar, QuoteStyle quoteStyle) { /* * Escape all quote chars embedded in the string. */ - if (quoteStyle.equals("C")) + if (quoteStyle.equals(QuoteStyle.C)) { value = value.replace("\\", "\\\\"); value = value.replace("" + quoteChar, "\\" + quoteChar); } - else + else if (quoteStyle == QuoteStyle.SQL) { value = value.replace("" + quoteChar, "" + quoteChar + quoteChar); } @@ -436,8 +436,9 @@ private static String addQuotes(String value, String separator, char quoteChar, /* * Surround value with quotes if it contains any special characters. */ - if (value.indexOf(separator) >= 0 || value.indexOf(quoteChar) >= 0 || - value.indexOf('\r') >= 0 || value.indexOf('\n') >= 0) + if (quoteStyle != QuoteStyle.NONE && ( + value.indexOf(separator) >= 0 || value.indexOf(quoteChar) >= 0 || + value.indexOf('\r') >= 0 || value.indexOf('\n') >= 0)) { value = quoteChar + value + quoteChar; } diff --git a/src/main/java/org/relique/jdbc/csv/CsvRawReader.java b/src/main/java/org/relique/jdbc/csv/CsvRawReader.java index 6f3b84ca..11baa67c 100644 --- a/src/main/java/org/relique/jdbc/csv/CsvRawReader.java +++ b/src/main/java/org/relique/jdbc/csv/CsvRawReader.java @@ -61,7 +61,7 @@ public class CsvRawReader private String comment = null; private boolean ignoreUnparseableLines; private String missingValue; - private String quoteStyle; + private QuoteStyle quoteStyle; private ArrayList fixedWidthColumns; private LinkedList readAheadLines; private boolean readingAhead; @@ -83,7 +83,7 @@ public CsvRawReader(LineNumberReader in, String missingValue, boolean defectiveHeaders, int skipLeadingDataLines, - String quoteStyle, + QuoteStyle quoteStyle, ArrayList fixedWidthColumns) throws IOException, SQLException { this.tableName = tableName; @@ -501,20 +501,20 @@ private String[] parseCsvLine(String line, boolean trimValues) { char currentChar = line.charAt(currentPos); if (value.length() == 0 && isQuoteChar(currentChar) - && !inQuotedString) + && !inQuotedString && quoteStyle != QuoteStyle.NONE) { // acknowledge quoteChar only at beginning of value. inQuotedString = true; quotedLineNumber = input.getLineNumber(); } - else if (currentChar == '\\' && "C".equals(quoteStyle)) + else if (currentChar == '\\' && quoteStyle == QuoteStyle.C) { // in C quoteStyle \\ escapes any character. char nextChar = line.charAt(currentPos + 1); value.append(nextChar); currentPos++; } - else if (isQuoteChar(currentChar)) + else if (isQuoteChar(currentChar) && quoteStyle != QuoteStyle.NONE) { char nextChar = line.charAt(currentPos + 1); if (!inQuotedString) @@ -526,7 +526,7 @@ else if (isQuoteChar(currentChar)) else if (isQuoteChar(nextChar)) { value.append(quoteChar.charValue()); - if ("SQL".equals(quoteStyle)) + if (quoteStyle == QuoteStyle.SQL) { // doubled quoteChar in quoted strings collapse to // one single quoteChar in SQL quotestyle diff --git a/src/main/java/org/relique/jdbc/csv/QuoteStyle.java b/src/main/java/org/relique/jdbc/csv/QuoteStyle.java new file mode 100644 index 00000000..4ed821f2 --- /dev/null +++ b/src/main/java/org/relique/jdbc/csv/QuoteStyle.java @@ -0,0 +1,27 @@ +/** + * CsvJdbc - a JDBC driver for CSV files + * Copyright (C) 2015 Daniel Wagner + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +package org.relique.jdbc.csv; + +/** + * Enum for supported quote styles. + */ +public enum QuoteStyle { + + C, SQL, NONE; +} \ No newline at end of file diff --git a/src/test/java/org/relique/jdbc/csv/TestCsvDriver.java b/src/test/java/org/relique/jdbc/csv/TestCsvDriver.java index 05ac51fb..687f027e 100644 --- a/src/test/java/org/relique/jdbc/csv/TestCsvDriver.java +++ b/src/test/java/org/relique/jdbc/csv/TestCsvDriver.java @@ -3541,6 +3541,29 @@ public void testEscapingQuotecharExplicitSQLStyle() throws SQLException } } + @Test + public void testEscapingQuotecharExplicitNONEStyle() throws SQLException + { + Properties props = new Properties(); + props.put("separator", ";"); + props.put("quotechar", "'"); + props.put("quoteStyle", "NONE"); + + Connection conn = DriverManager.getConnection("jdbc:relique:csv:" + + filePath, props); + + Statement stmt = conn.createStatement(); + ResultSet results = stmt.executeQuery("SELECT F1 FROM nullquotestyle"); + assertTrue(results.next()); + assertEquals("'doubling \\\"\\\"quotechar'", results.getObject("F1")); + assertTrue(results.next()); + assertEquals("Foo\\\\Bar",results.getObject("F1")); + assertTrue(results.next()); + assertEquals("Joe \"6\" Pack",results.getObject("F1")); + assertTrue(results.next()); + assertEquals("\"\"Jane\"\" Doe",results.getObject("F1")); + } + @Test public void testBadQuotechar() throws SQLException { diff --git a/src/testdata/nullquotestyle.csv b/src/testdata/nullquotestyle.csv new file mode 100644 index 00000000..c542e45d --- /dev/null +++ b/src/testdata/nullquotestyle.csv @@ -0,0 +1,5 @@ +F1;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12 +'doubling \"\"quotechar';F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12 +Foo\\Bar;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12 +Joe "6" Pack;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12 +""Jane"" Doe;F2;F3;F4;F5;F6;F7;F8;F9;F10;F11;F12 From 4893e6f6bf9af31410f3bde2c7c1eb07bb92591d Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 12 Oct 2021 15:55:10 +0200 Subject: [PATCH 2/2] Fixed compilation value to enum compversion. --- src/main/java/org/relique/jdbc/csv/CsvConnection.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/relique/jdbc/csv/CsvConnection.java b/src/main/java/org/relique/jdbc/csv/CsvConnection.java index 35e3a821..03c2bbdf 100644 --- a/src/main/java/org/relique/jdbc/csv/CsvConnection.java +++ b/src/main/java/org/relique/jdbc/csv/CsvConnection.java @@ -491,8 +491,8 @@ else if (prop.length() == 0) CsvDriver.DEFAULT_SKIP_LEADING_DATA_LINES)); setSkipLeadingLines(info.getProperty(CsvDriver.SKIP_LEADING_LINES, CsvDriver.DEFAULT_SKIP_LEADING_LINES)); - setQuoteStyle(info.getProperty(CsvDriver.QUOTE_STYLE, - CsvDriver.DEFAULT_QUOTE_STYLE.name())); + setQuoteStyle(QuoteStyle.valueOf(info.getProperty(CsvDriver.QUOTE_STYLE, + CsvDriver.DEFAULT_QUOTE_STYLE.name()))); setIgnoreUnparseableLines(Boolean.parseBoolean(info.getProperty( CsvDriver.IGNORE_UNPARSEABLE_LINES, CsvDriver.DEFAULT_IGNORE_UNPARSEABLE_LINES)));