diff --git a/jOOQ/src/main/java/org/jooq/impl/Executor.java b/jOOQ/src/main/java/org/jooq/impl/Executor.java
index 49a903ad34..f023b058f0 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Executor.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Executor.java
@@ -1590,6 +1590,82 @@ public class Executor implements Configuration {
return fetchLazy(rs, Utils.getDataTypes(types));
}
+ /**
+ * Fetch all data from a formatted string.
+ *
+ * The supplied string is supposed to be formatted in the following,
+ * human-readable way:
+ * COL1 COL2 COL3 containing whitespace
+ * ----- ---- --------------------------
+ * val1 1 some text
+ * val2 2 more text
+ *
This method will decode the above formatted string
+ * according to the following rules:
+ *
+ * - The number of columns is defined by the number of dash groups in the
+ * second line
+ * - The column types are
VARCHAR(N) where
+ * N = number of dashes per dash group
+ * - The column names are defined by the trimmed text contained in the
+ * first row
+ * - The data is defined by the trimmed text contained in the subsequent
+ * rows
+ *
+ *
+ * This is the same as calling {@link #fetchFromTXT(String, String)} with
+ * "{null}" as nullLiteral
+ *
+ * A future version of jOOQ will also support the inverse operation of
+ * {@link Result#format()} through this method
+ *
+ * @param string The formatted string
+ * @return The transformed result
+ * @see #fetchFromTXT(String, String)
+ * @throws DataAccessException If the supplied string does not adhere to the
+ * above format rules.
+ */
+ @Support
+ public final Result fetchFromTXT(String string) throws DataAccessException {
+ return fetchFromTXT(string, "{null}");
+ }
+
+ /**
+ * Fetch all data from a formatted string.
+ *
+ * The supplied string is supposed to be formatted in the following,
+ * human-readable way:
+ * COL1 COL2 COL3 containing whitespace
+ * ----- ---- --------------------------
+ * val1 1 some text
+ * val2 2 more text
+ *
This method will decode the above formatted string
+ * according to the following rules:
+ *
+ * - The number of columns is defined by the number of dash groups in the
+ * second line
+ * - The column types are
VARCHAR(N) where
+ * N = number of dashes per dash group
+ * - The column names are defined by the trimmed text contained in the
+ * first row
+ * - The data is defined by the trimmed text contained in the subsequent
+ * rows
+ *
+ *
+ * A future version of jOOQ will also support the inverse operation of
+ * {@link Result#format()} through this method
+ *
+ * @param string The formatted string
+ * @param nullLiteral The string literal to be used as null
+ * value.
+ * @return The transformed result
+ * @throws DataAccessException If the supplied string does not adhere to the
+ * above format rules.
+ */
+ @Support
+ public final Result fetchFromTXT(String string, String nullLiteral) throws DataAccessException {
+ return fetchFromStringData(Utils.parseTXT(string, nullLiteral));
+ }
+
/**
* Fetch all data from a CSV string.
*
diff --git a/jOOQ/src/main/java/org/jooq/impl/Utils.java b/jOOQ/src/main/java/org/jooq/impl/Utils.java
index a1f0898cf8..09da952480 100644
--- a/jOOQ/src/main/java/org/jooq/impl/Utils.java
+++ b/jOOQ/src/main/java/org/jooq/impl/Utils.java
@@ -75,6 +75,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.persistence.Column;
@@ -130,7 +131,7 @@ import org.jooq.util.postgres.PostgresUtils;
*/
final class Utils {
- static final JooqLogger log = JooqLogger.getLogger(Utils.class);
+ static final JooqLogger log = JooqLogger.getLogger(Utils.class);
// ------------------------------------------------------------------------
// Some constants for use with Configuration.setData()
@@ -141,7 +142,7 @@ final class Utils {
* clause in {@link Executor#batchStore(UpdatableRecord...)} calls for
* {@link SQLDialect#POSTGRES}
*/
- static final String DATA_OMIT_RETURNING_CLAUSE = "org.jooq.configuration.omit-returning-clause";
+ static final String DATA_OMIT_RETURNING_CLAUSE = "org.jooq.configuration.omit-returning-clause";
/**
* [#1905] This constant is used internally by jOOQ to indicate to
@@ -161,7 +162,7 @@ final class Utils {
* The default escape character for [a] LIKE [b] ESCAPE [...]
* clauses.
*/
- static final char ESCAPE = '!';
+ static final char ESCAPE = '!';
/**
* Indicating whether JPA (javax.persistence) is on the
@@ -169,10 +170,15 @@ final class Utils {
*/
private static Boolean isJPAAvailable;
+ /**
+ * A pattern for the dash line syntax
+ */
+ private static final Pattern DASH_PATTERN = Pattern.compile("(-+)"); ;
+
/**
* A pattern for the JDBC escape syntax
*/
- private static final Pattern JDBC_ESCAPE_PATTERN = Pattern.compile("\\{(fn|d|t|ts)\\b.*");
+ private static final Pattern JDBC_ESCAPE_PATTERN = Pattern.compile("\\{(fn|d|t|ts)\\b.*");
// ------------------------------------------------------------------------
// XXX: Record constructors and related methods
@@ -2396,4 +2402,54 @@ final class Utils {
private static final void pgSetValue(UDTRecord> record, Field field, String value) throws SQLException {
record.setValue(field, pgFromString(field.getType(), value));
}
+
+ static List parseTXT(String string, String nullLiteral) {
+ String[] strings = string.split("[\\r\\n]+");
+
+ if (strings.length < 2) {
+ throw new DataAccessException("String must contain at least two lines");
+ }
+
+ // Find the set of positions defined by the dashed line number two:
+ // ----- ------- ----
+ // results in
+ // [{0,5} {7,14} {15,19}]
+ List positions = new ArrayList();
+ Matcher m = DASH_PATTERN.matcher(strings[1]);
+
+ while (m.find()) {
+ positions.add(new int[] { m.start(1), m.end(1) });
+ }
+
+ // Parse header line and data lines into string arrays
+ List result = new ArrayList();
+ parseTXTLine(positions, result, strings[0], nullLiteral);
+
+ for (int j = 2; j < strings.length; j++) {
+ parseTXTLine(positions, result, strings[j], nullLiteral);
+ }
+
+ return result;
+ }
+
+ private static void parseTXTLine(List positions, List result, String string, String nullLiteral) {
+ String[] fields = new String[positions.size()];
+ result.add(fields);
+ int length = string.length();
+
+ for (int i = 0; i < fields.length; i++) {
+ int[] position = positions.get(i);
+
+ if (position[0] < length) {
+ fields[i] = string.substring(position[0], Math.min(position[1], length)).trim();
+ }
+ else {
+ fields[i] = null;
+ }
+
+ if (StringUtils.equals(fields[i], nullLiteral)) {
+ fields[i] = null;
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockFileDatabase.java b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockFileDatabase.java
index 8b7b28e8fc..5c812b13f4 100644
--- a/jOOQ/src/main/java/org/jooq/tools/jdbc/MockFileDatabase.java
+++ b/jOOQ/src/main/java/org/jooq/tools/jdbc/MockFileDatabase.java
@@ -128,12 +128,8 @@ public class MockFileDatabase implements MockDataProvider {
// A line of result data
else if (line.startsWith(">")) {
-
- // But ignore visual delimiter
- if (!line.startsWith("> -")) {
- currentResult.append(line.substring(2));
- currentResult.append("\n");
- }
+ currentResult.append(line.substring(2));
+ currentResult.append("\n");
}
// A result data termination literal
@@ -219,7 +215,7 @@ public class MockFileDatabase implements MockDataProvider {
rows = Integer.parseInt(rowString.substring(7).trim());
}
- return new MockResult(rows, create.fetchFromCSV(currentResult.toString(), ' '));
+ return new MockResult(rows, create.fetchFromTXT(currentResult.toString()));
}
private String readLine() throws IOException {
diff --git a/jOOQ/src/test/java/org/jooq/test/MockTest.java b/jOOQ/src/test/java/org/jooq/test/MockTest.java
index a5dda9ced2..d4e831d3f9 100644
--- a/jOOQ/src/test/java/org/jooq/test/MockTest.java
+++ b/jOOQ/src/test/java/org/jooq/test/MockTest.java
@@ -333,5 +333,53 @@ public class MockTest extends AbstractTest {
@Test
public void testFileDatabase_SELECT_ID1_NAME1_FROM_TABLE1() throws Exception {
Result> r = MOCK.select(FIELD_ID1, FIELD_NAME1).from(TABLE1).fetch();
+
+ assertEquals(2, r.size());
+ assertEquals("ID1", r.field(0).getName());
+ assertEquals("NAME1", r.field(1).getName());
+ assertEquals(asList(1, 2), r.getValues(0));
+ assertEquals(asList("X", "Y"), r.getValues(1));
+ }
+
+ @Test
+ public void testFileDatabase_SELECT_COMPLEX_DATA() throws Exception {
+ List> results = MOCK.fetchMany("select complex_data");
+ assertEquals(2, results.size());
+
+ Result r1 = results.get(0);
+ Result r2 = results.get(1);
+
+ // Result 1
+ // --------
+ assertEquals(2, r1.size());
+
+ // Header
+ assertEquals(3, r1.fields().length);
+ assertEquals("F1", r1.field(0).getName());
+ assertEquals("F2", r1.field(1).getName());
+ assertEquals("F3 is a bit more complex", r1.field(2).getName());
+
+ // Data
+ assertEquals("1", r1.getValue(0, 0));
+ assertEquals("2", r1.getValue(0, 1));
+ assertEquals("and a string containing data", r1.getValue(0, 2));
+ assertEquals("1.1", r1.getValue(1, 0));
+ assertEquals("x", r1.getValue(1, 1));
+ assertEquals("another string", r1.getValue(1, 2));
+
+ // Result 1
+ // --------
+ assertEquals(1, r2.size());
+
+ // Header
+ assertEquals(3, r2.fields().length);
+ assertEquals("A", r2.field(0).getName());
+ assertEquals("B", r2.field(1).getName());
+ assertEquals("\"C D\"", r2.field(2).getName());
+
+ // Data
+ assertEquals("x", r2.getValue(0, 0));
+ assertEquals("y", r2.getValue(0, 1));
+ assertEquals("z", r2.getValue(0, 2));
}
}
diff --git a/jOOQ/src/test/resources/org/jooq/test/data/db.txt b/jOOQ/src/test/resources/org/jooq/test/data/db.txt
index 14a207438e..0d52428286 100644
--- a/jOOQ/src/test/resources/org/jooq/test/data/db.txt
+++ b/jOOQ/src/test/resources/org/jooq/test/data/db.txt
@@ -15,6 +15,19 @@ select 'A', 'B' from dual;
select "TABLE1"."ID1", "TABLE1"."NAME1" from "TABLE1";
> ID1 NAME1
> --- -----
-> 1 X
-> 2 Y
-@ rows: 2
\ No newline at end of file
+> 1 X
+> 2 Y
+@ rows: 2
+
+# [#2280] Check if "advanced" CSV content can be handled, too
+select complex_data;
+> F1 F2 F3 is a bit more complex
+> --- -- ----------------------------
+> 1 2 and a string containing data
+> 1.1 x another string
+@ rows: 2
+
+> A B "C D"
+> - - -----
+> x y z
+@ rows: 1
\ No newline at end of file