Skip to content

Commit

Permalink
[SQLLINE-50] Added possibility to change csv delimiter and csv quote …
Browse files Browse the repository at this point in the history
…character, fixed escaping in case of csv output format

[SQLLINE-87] Do not do dequote if there is only one quote
  • Loading branch information
snuyanzin committed Jul 31, 2018
1 parent 02987f8 commit 86dd42c
Show file tree
Hide file tree
Showing 7 changed files with 108 additions and 8 deletions.
15 changes: 15 additions & 0 deletions src/docbkx/manual.xml
Expand Up @@ -1585,6 +1585,21 @@ NAME Microsoft
4 rows selected (0.012 seconds)
</screen>
</refsect1>
<refsect1>
<title>Example of CSV output formatting with different csv delimiter and quote character</title>
<screen>
0: jdbc:calcite:model=target/test-classes/mod> !set csvDelimiter ###
0: jdbc:calcite:model=target/test-classes/mod> !set csvQuoteCharacter @
0: jdbc:calcite:model=target/test-classes/mod> !set outputFormat csv
0: jdbc:calcite:model=target/test-classes/mod> SELECT * FROM COMPANY;
@COMPANY_ID@###@NAME@
@1@###@Apple@
@2@###@Sun@
@3@###@IBM@
@4@###@Microsoft@
4 rows selected (0.014 seconds)
</screen>
</refsect1>
<refsect1>
<title>Example of TSV output formatting</title>
<screen>
Expand Down
35 changes: 28 additions & 7 deletions src/main/java/sqlline/SeparatedValuesOutputFormat.java
Expand Up @@ -13,17 +13,23 @@

/**
* OutputFormat for values separated by a delimiter.
*
* <p><strong>TODO</strong>:
* Handle character escaping
*/
class SeparatedValuesOutputFormat implements OutputFormat {
private static final String DEFAULT_SEPARATOR = ",";
private static final char DEFAULT_QUOTE_CHARACTER = '"';
private final SqlLine sqlLine;
private char separator;
private final boolean takeSeparatorFromProperties;

public SeparatedValuesOutputFormat(SqlLine sqlLine, char separator) {
this.sqlLine = sqlLine;
setSeparator(separator);
takeSeparatorFromProperties = false;
}

public SeparatedValuesOutputFormat(SqlLine sqlLine) {
this.sqlLine = sqlLine;
this.takeSeparatorFromProperties = true;
}

public int print(Rows rows) {
Expand All @@ -39,11 +45,26 @@ public int print(Rows rows) {
public void printRow(Rows rows, Rows.Row row) {
String[] vals = row.values;
StringBuilder buf = new StringBuilder();
final String separator = takeSeparatorFromProperties
? SqlLineOpts.DEFAULT.equals(sqlLine.getOpts().getCsvDelimiter())
? DEFAULT_SEPARATOR
: sqlLine.getOpts().getCsvDelimiter()
: String.valueOf(getSeparator());
final char quoteCharacter = takeSeparatorFromProperties
? sqlLine.getOpts().getCsvQuoteCharacter()
: DEFAULT_QUOTE_CHARACTER;
for (String val : vals) {
buf.append(buf.length() == 0 ? "" : "" + getSeparator())
.append('\'')
.append(val == null ? "" : val)
.append('\'');
buf.append(buf.length() == 0 ? "" : "" + separator)
.append(quoteCharacter);
if (val != null) {
for (char c : val.toCharArray()) {
if (c == quoteCharacter) {
buf.append(c);
}
buf.append(c);
}
}
buf.append(quoteCharacter);
}
sqlLine.output(buf.toString());
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/sqlline/SqlLine.java
Expand Up @@ -80,7 +80,7 @@ public class SqlLine {
private final Map<String, OutputFormat> formats = map(
"vertical", (OutputFormat) new VerticalOutputFormat(this),
"table", new TableOutputFormat(this),
"csv", new SeparatedValuesOutputFormat(this, ','),
"csv", new SeparatedValuesOutputFormat(this),
"tsv", new SeparatedValuesOutputFormat(this, '\t'),
"xmlattr", new XmlAttributeOutputFormat(this),
"xmlelements", new XmlElementOutputFormat(this),
Expand Down
32 changes: 32 additions & 0 deletions src/main/java/sqlline/SqlLineOpts.java
Expand Up @@ -34,6 +34,8 @@ class SqlLineOpts implements Completer {
private boolean autoSave = false;
private boolean silent = false;
private boolean color = false;
private String csvDelimiter = ",";
private char csvQuoteCharacter = '\'';
private boolean showHeader = true;
private int headerInterval = 100;
private boolean fastConnect = true;
Expand Down Expand Up @@ -385,6 +387,36 @@ public boolean getColor() {
return this.color;
}

public void setCsvDelimiter(String csvDelimiter) {
this.csvDelimiter = csvDelimiter;
}

public String getCsvDelimiter() {
return this.csvDelimiter;
}

public void setCsvQuoteCharacter(String csvQuoteCharacter) {
if (DEFAULT.equals(csvQuoteCharacter)) {
this.csvQuoteCharacter = '\'';
return;
} else if (csvQuoteCharacter != null) {
if (csvQuoteCharacter.length() == 1) {
this.csvQuoteCharacter = csvQuoteCharacter.charAt(0);
return;
} else if (csvQuoteCharacter.length() == 2
&& csvQuoteCharacter.charAt(0) == '\\') {
this.csvQuoteCharacter = csvQuoteCharacter.charAt(1);
return;
}
}
throw new IllegalArgumentException(
"CsvQuoteCharacter is '" + csvQuoteCharacter + "' while it should be a character of default");
}

public char getCsvQuoteCharacter() {
return this.csvQuoteCharacter;
}

public void setShowHeader(boolean showHeader) {
this.showHeader = showHeader;
}
Expand Down
5 changes: 5 additions & 0 deletions src/main/resources/sqlline/SqlLine.properties
Expand Up @@ -58,6 +58,9 @@ help-set: Set a sqlline variable\
\nautoSave true/false Automatically save preferences\
\ncolor true/false Control whether color is used\
\n for display\
\ncsvDelimiter String Delimiter in csv outputFormat\
\ncsvQuoteCharacter char Quote character in\
\n csv outputFormat\
\ndateFormat pattern Format dates using\
\n SimpleDateFormat pattern\
\nfastConnect true/false Skip building table/column list\
Expand Down Expand Up @@ -212,6 +215,8 @@ cmd-usage: Usage: java sqlline.SqlLine \n \
\ -nn <nickname> nickname for the connection\n \
\ -f <file> script file to execute (same as --run)\n \
\ --color=[true/false] control whether color is used for display\n \
\ --csvDelimeter=[delimiter] Delimiter in csv outputFormat\n \
\ --csvQuoteCharacter=[char] Quote character in csv outputFormat\n \
\ --showHeader=[true/false] show column names in query results\n \
\ --headerInterval=ROWS the interval between which headers are displayed\n \
\ --fastConnect=[true/false] skip building table/column list for tab-completion\n \
Expand Down
14 changes: 14 additions & 0 deletions src/main/resources/sqlline/manual.txt
Expand Up @@ -95,6 +95,8 @@ Parameter Reference
autocommit
autosave
color
csvDelimiter
csvQuoteCharacter
dateformat
fastconnect
force
Expand Down Expand Up @@ -212,6 +214,8 @@ Parameter Reference
autocommit
autosave
color
csvDelimiter
csvQuoteCharacter
dateformat
fastconnect
force
Expand Down Expand Up @@ -1908,6 +1912,8 @@ Parameter Reference
autocommit
autosave
color
csvDelimiter
csvQuoteCharacter
dateformat
fastconnect
force
Expand Down Expand Up @@ -1941,6 +1947,14 @@ color

If true, then output to the terminal will use color for a more pleasing visual experience. Requires that the terminal support ANSI control codes (most do). Defaults to false.

csvDelimiter

Sets the delimiter in csv outputFormat. Setting to default causes usage of "," as a delimiter.

csvQuoteCharacter

Sets the quote character in csv outputFormat. Setting to default causes usage of '\'' as a delimiter.

dateformat

The format for how date values are displayed. Setting to default causes date values to be fetched and rendered via ResultSet.getString. Any other setting results in fetch via ResultSet.getObject and rendering via java.text.SimpleDateFormat. For example, the setting "YYYY_MM_dd" yields values like "1970_01_01".
Expand Down
13 changes: 13 additions & 0 deletions src/test/java/sqlline/SqlLineArgsTest.java
Expand Up @@ -690,6 +690,19 @@ public void testTablesCsv() throws Throwable {
containsString("'PUBLIC','SCOTT','SALGRADE','TABLE','',")));
}

@Test
public void testCsvDelimiterAndQuoteCharacter() throws Throwable {
final String script = "!set outputformat csv\n"
+ "!set csvDelimiter ##\n"
+ "!set csvQuoteCharacter @\n"
+ "values ('#', '@#@', 1, date '1969-07-20', null, ' 1''2\"3\t4');\n";
checkScriptFile(script, true, equalTo(SqlLine.Status.OK),
allOf(
containsString("@C1@##@C2@##@C3@##@C4@##@C5@##@C6@"),
containsString(
"@#@##@@@#@@@##@1@##@1969-07-20@##@@##@ 1'2\"3\t4@")));
}

@Test
public void testTablesJson() throws Throwable {
final String script = "!set outputformat json\n"
Expand Down

0 comments on commit 86dd42c

Please sign in to comment.