diff --git a/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/information_schema.properties b/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/information_schema.properties
new file mode 100644
index 0000000000..9c689f93c0
--- /dev/null
+++ b/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/information_schema.properties
@@ -0,0 +1,17 @@
+#example properties file
+jdbc.Driver=org.h2.Driver
+jdbc.URL=jdbc:h2:~/test
+jdbc.Schema=INFORMATION_SCHEMA
+jdbc.User=sa
+jdbc.Password=
+
+generator=org.jooq.util.DefaultGenerator
+generator.database=org.jooq.util.h2.H2Database
+generator.database.includes=SCHEMATA,TABLES,COLUMNS,CONSTRAINTS,CROSS_REFERENCES,TYPE_INFO,FUNCTION_ALIASES,FUNCTION_COLUMNS,SEQUENCES
+generator.database.excludes=
+generator.generate.deprecated=false
+generator.generate.instance-fields=false
+generator.generate.records=false
+
+generator.target.package=org.jooq.util.h2.information_schema
+generator.target.directory=./src/main/java
\ No newline at end of file
diff --git a/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/library.properties b/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/library.properties
new file mode 100644
index 0000000000..3de66d6bdf
--- /dev/null
+++ b/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/library.properties
@@ -0,0 +1,48 @@
+#example properties file
+jdbc.Driver=org.h2.Driver
+#jdbc.URL=jdbc:h2:tcp://localhost/~/test
+jdbc.URL=jdbc:h2:~/test
+jdbc.Schema=PUBLIC
+jdbc.User=sa
+jdbc.Password=
+
+generator=org.jooq.util.DefaultGenerator
+generator.database=org.jooq.util.h2.H2Database
+generator.database.includes=.*
+generator.database.excludes=T_BOOK_DETAILS,SYSTEM_SEQUENCE.*
+
+#Database enum type mappings
+generator.database.enum-type.BOOLEAN_10=1,0
+generator.database.enum-type.BOOLEAN_YN_UC="Y",N
+generator.database.enum-type.BOOLEAN_YN_LC=y,"n"
+generator.database.enum-type.BOOLEAN_YES_NO_UC="YES","NO"
+generator.database.enum-type.BOOLEAN_YES_NO_LC=yes,no
+generator.database.enum-type.BOOLEAN_TRUE_FALSE_UC=TRUE,FALSE
+generator.database.enum-type.BOOLEAN_TRUE_FALSE_LC=true,false
+
+generator.database.forced-type.BOOLEAN_10=(?i:(.*?\.)?T_BOOLEANS\.ONE_ZERO)
+generator.database.forced-type.BOOLEAN_YN_UC=(?i:(.*?\.)?T_BOOLEANS\.Y_N_UC)
+generator.database.forced-type.BOOLEAN_YN_LC=(?i:(.*?\.)?T_BOOLEANS\.Y_N_LC)
+generator.database.forced-type.BOOLEAN_YES_NO_UC=(?i:(.*?\.)?T_BOOLEANS\.YES_NO_UC)
+generator.database.forced-type.BOOLEAN_YES_NO_LC=(?i:(.*?\.)?T_BOOLEANS\.YES_NO_LC)
+generator.database.forced-type.BOOLEAN_TRUE_FALSE_UC=(?i:(.*?\.)?T_BOOLEANS\.TRUE_FALSE_UC)
+generator.database.forced-type.BOOLEAN_TRUE_FALSE_LC=(?i:(.*?\.)?T_BOOLEANS\.TRUE_FALSE_LC)
+
+#[#677] Forced types
+generator.database.forced-type.BOOLEAN=(?i:(.*?\.)?T_BOOLEANS\.(VC|C|N)_BOOLEAN)
+
+#Generator configuration
+generator.generate.relations=true
+generator.generate.instance-fields=false
+generator.generate.generated-annotation=false
+
+#Generate a master data table enum from T_LANGUAGE
+generator.generate.master-data-tables=T_LANGUAGE,T_658_11,T_658_21,T_658_31,T_658_12,T_658_22,T_658_32
+generator.generate.master-data-table-literal.T_LANGUAGE=CD
+generator.generate.master-data-table-description.T_LANGUAGE=DESCRIPTION
+generator.generate.master-data-table-literal.T_658_12=CD
+generator.generate.master-data-table-literal.T_658_22=CD
+generator.generate.master-data-table-literal.T_658_32=CD
+
+generator.target.package=org.jooq.test.h2.generatedclasses
+generator.target.directory=./src
\ No newline at end of file
diff --git a/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/library.xml b/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/library.xml
new file mode 100644
index 0000000000..ab854ac34f
--- /dev/null
+++ b/jOOQ-test/configuration/org/jooq/configuration/IvanD/h2/library.xml
@@ -0,0 +1,133 @@
+
+
+
+ org.h2.Driver
+ jdbc:h2:~/test
+ sa
+
+
+
+ org.jooq.util.DefaultGenerator
+
+ org.jooq.util.h2.H2Database
+ .*
+ T_BOOK_DETAILS,SYSTEM_SEQUENCE.*
+ REC_VERSION
+ REC_TIMESTAMP
+ false
+ true
+ PUBLIC
+
+
+ T_LANGUAGE
+ CD
+ DESCRIPTION
+
+
+ T_658_11
+
+
+ T_658_21
+
+
+ T_658_31
+
+
+ T_658_12
+ CD
+
+
+ T_658_22
+ CD
+
+
+ T_658_32
+ CD
+
+
+
+
+
+ org.jooq.test._.converters.Boolean_10
+ org.jooq.test._.converters.Boolean_10_Converter
+
+
+ org.jooq.test._.converters.Boolean_TF_LC
+ org.jooq.test._.converters.Boolean_TF_LC_Converter
+
+
+ org.jooq.test._.converters.Boolean_TF_UC
+ org.jooq.test._.converters.Boolean_TF_UC_Converter
+
+
+ org.jooq.test._.converters.Boolean_YN_LC
+ org.jooq.test._.converters.Boolean_YN_LC_Converter
+
+
+ org.jooq.test._.converters.Boolean_YN_UC
+ org.jooq.test._.converters.Boolean_YN_UC_Converter
+
+
+ org.jooq.test._.converters.Boolean_YES_NO_LC
+ org.jooq.test._.converters.Boolean_YES_NO_LC_Converter
+
+
+ org.jooq.test._.converters.Boolean_YES_NO_UC
+ org.jooq.test._.converters.Boolean_YES_NO_UC_Converter
+
+
+
+
+
+ BOOLEAN
+ (?i:(.*?.)?T_BOOLEANS.(VC|C|N)_BOOLEAN)
+
+
+
+ org.jooq.test._.converters.Boolean_YES_NO_LC
+ (?i:(.*?.)?T_BOOLEANS.YES_NO_LC)
+
+
+ org.jooq.test._.converters.Boolean_YES_NO_UC
+ (?i:(.*?.)?T_BOOLEANS.YES_NO_UC)
+
+
+ org.jooq.test._.converters.Boolean_YN_LC
+ (?i:(.*?.)?T_BOOLEANS.Y_N_LC)
+
+
+ org.jooq.test._.converters.Boolean_YN_UC
+ (?i:(.*?.)?T_BOOLEANS.Y_N_UC)
+
+
+ org.jooq.test._.converters.Boolean_TF_LC
+ (?i:(.*?.)?T_BOOLEANS.TRUE_FALSE_LC)
+
+
+ org.jooq.test._.converters.Boolean_TF_UC
+ (?i:(.*?.)?T_BOOLEANS.TRUE_FALSE_UC)
+
+
+ org.jooq.test._.converters.Boolean_10
+ (?i:(.*?.)?T_BOOLEANS.ONE_ZERO)
+
+
+
+
+ true
+ true
+ true
+ false
+ false
+ false
+ false
+ true
+ true
+ false
+
+
+ org.jooq.test.h2.generatedclasses
+ ./src
+
+
+
\ No newline at end of file
diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/FormatTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/FormatTests.java
index de48edca3f..7bbeae43cb 100644
--- a/jOOQ-test/src/org/jooq/test/_/testcases/FormatTests.java
+++ b/jOOQ-test/src/org/jooq/test/_/testcases/FormatTests.java
@@ -41,7 +41,10 @@ import static junit.framework.Assert.assertTrue;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
+import java.math.BigDecimal;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
@@ -86,6 +89,45 @@ extends BaseTest decimalPointIndexSet = new HashSet();
+ for (String formatLine : format.split("\n")) {
+ // Include only data lines
+ if (formatLine.startsWith("|")) {
+ decimalPointIndexSet.add(formatLine.indexOf("."));
+ }
+ }
+
+ // Remove -1 position
+ decimalPointIndexSet.remove(-1);
+
+ // Check if all decimal points have the same position
+ assertEquals(1, decimalPointIndexSet.size());
+ }
+
@Test
public void testFormatHTML() throws Exception {
List> fields = TBook().getFields();
diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java
index 86f1683cc4..111777db6e 100644
--- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java
+++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java
@@ -1222,6 +1222,11 @@ public abstract class jOOQAbstractTest<
new CRUDTests(this).testNonUpdatables();
}
+ @Test
+ public void testFormat() throws Exception {
+ new FormatTests(this).testFormat();
+ }
+
@Test
public void testFormatHTML() throws Exception {
new FormatTests(this).testFormatHTML();
diff --git a/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java b/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java
index ee578f2ec4..a0f39ffc47 100644
--- a/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java
+++ b/jOOQ/src/main/java/org/jooq/impl/ResultImpl.java
@@ -88,6 +88,7 @@ import org.w3c.dom.Element;
/**
* @author Lukas Eder
+ * @author Ivan Dugic
*/
class ResultImpl implements Result, AttachableInternal {
@@ -937,33 +938,73 @@ class ResultImpl implements Result, AttachableInternal {
@Override
public final String format(int maxRecords) {
- final int MAX_WIDTH = 50;
+ final int COL_MIN_WIDTH = 4;
+ final int COL_MAX_WIDTH = 50;
+ // Numeric columns have greater max width because values are aligned
+ final int NUM_COL_MAX_WIDTH = 100;
+
final int MAX_RECORDS = 50;
- StringBuilder sb = new StringBuilder();
- Map, Integer> widths = new HashMap, Integer>();
-
- // Initialise widths
+ // Get max decimal places for numeric type columns
+ Map, Integer> decimalPlacesMap = new HashMap, Integer>();
for (Field> f : getFields()) {
- widths.put(f, 4);
+ if (Number.class.isAssignableFrom(f.getType())) {
+ List decimalPlacesList = new ArrayList();
+
+ // Initialize
+ decimalPlacesList.add(0);
+
+ // Collect all decimal places for the column values
+ String value;
+ for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
+ value = format0(getValue(i, f));
+ decimalPlacesList.add(getDecimalPlaces(value));
+ }
+
+ // Find max
+ decimalPlacesMap.put(f, Collections.max(decimalPlacesList));
+ }
}
- // Find width for every field to satisfy formatting the first 50 records
+ // Get max column widths
+ Map, Integer> widthMap = new HashMap, Integer>();
+ int colMaxWidth;
for (Field> f : getFields()) {
- widths.put(f, min(MAX_WIDTH, max(widths.get(f), f.getName().length())));
+ // Is number column?
+ boolean isNumCol = Number.class.isAssignableFrom(f.getType());
+ colMaxWidth = isNumCol ? NUM_COL_MAX_WIDTH : COL_MAX_WIDTH;
+
+ // Collect all widths for the column
+ List widthList = new ArrayList();
+
+ // Add column name width first
+ widthList.add(min(colMaxWidth, max(COL_MIN_WIDTH, f.getName().length())));
+
+ // Add column values width
+ String value;
for (int i = 0; i < min(MAX_RECORDS, size()); i++) {
- widths.put(f, min(MAX_WIDTH, max(widths.get(f), format0(getValue(i, f)).length())));
+ value = format0(getValue(i, f));
+ // Align number values before width is calculated
+ if (isNumCol) {
+ value = alignNumberValue(decimalPlacesMap.get(f), value);
+ }
+
+ widthList.add(min(colMaxWidth, value.length()));
}
+
+ // Find max
+ widthMap.put(f, Collections.max(widthList));
}
// Begin the writing
// ---------------------------------------------------------------------
+ StringBuilder sb = new StringBuilder();
// Write top line
sb.append("+");
for (Field> f : getFields()) {
- sb.append(rightPad("", widths.get(f), "-"));
+ sb.append(rightPad("", widthMap.get(f), "-"));
sb.append("+");
}
@@ -973,20 +1014,20 @@ class ResultImpl implements Result, AttachableInternal {
String padded;
if (Number.class.isAssignableFrom(f.getType())) {
- padded = leftPad(f.getName(), widths.get(f));
+ padded = leftPad(f.getName(), widthMap.get(f));
}
else {
- padded = rightPad(f.getName(), widths.get(f));
+ padded = rightPad(f.getName(), widthMap.get(f));
}
- sb.append(abbreviate(padded, widths.get(f)));
+ sb.append(abbreviate(padded, widthMap.get(f)));
sb.append("|");
}
// Write separator
sb.append("\n+");
for (Field> f : getFields()) {
- sb.append(rightPad("", widths.get(f), "-"));
+ sb.append(rightPad("", widthMap.get(f), "-"));
sb.append("+");
}
@@ -995,16 +1036,21 @@ class ResultImpl implements Result, AttachableInternal {
sb.append("\n|");
for (Field> f : getFields()) {
String value = format0(getValue(i, f)).replace("\n", "{lf}").replace("\r", "{cr}");
- String padded;
+ String padded;
if (Number.class.isAssignableFrom(f.getType())) {
- padded = leftPad(value, widths.get(f));
+ // Align number value before left pad
+ value = alignNumberValue(decimalPlacesMap.get(f), value);
+
+ // Left pad
+ padded = leftPad(value, widthMap.get(f));
}
else {
- padded = rightPad(value, widths.get(f));
+ // Right pad
+ padded = rightPad(value, widthMap.get(f));
}
- sb.append(abbreviate(padded, widths.get(f)));
+ sb.append(abbreviate(padded, widthMap.get(f)));
sb.append("|");
}
}
@@ -1013,7 +1059,7 @@ class ResultImpl implements Result, AttachableInternal {
if (size() > 0) {
sb.append("\n+");
for (Field> f : getFields()) {
- sb.append(rightPad("", widths.get(f), "-"));
+ sb.append(rightPad("", widthMap.get(f), "-"));
sb.append("+");
}
}
@@ -1028,6 +1074,34 @@ class ResultImpl implements Result, AttachableInternal {
return sb.toString();
}
+ private String alignNumberValue(Integer columnDecimalPlaces, String value) {
+ if (!"{null}".equals(value) && columnDecimalPlaces != 0) {
+ int decimalPlaces = getDecimalPlaces(value);
+ int rightPadSize = value.length() + columnDecimalPlaces - decimalPlaces;
+
+ if (decimalPlaces == 0) {
+ // If integer value, add one for decimal point
+ value = rightPad(value, rightPadSize + 1);
+ }
+ else {
+ value = rightPad(value, rightPadSize);
+ }
+ }
+
+ return value;
+ }
+
+ private Integer getDecimalPlaces(String value) {
+ int decimalPlaces = 0;
+
+ int dotIndex = value.indexOf(".");
+ if (dotIndex != -1) {
+ decimalPlaces = value.length() - dotIndex - 1;
+ }
+
+ return decimalPlaces;
+ }
+
@Override
public final String formatHTML() {
StringBuilder sb = new StringBuilder();
@@ -1140,6 +1214,10 @@ class ResultImpl implements Result, AttachableInternal {
else if (value instanceof EnumType) {
formatted = ((EnumType) value).getLiteral();
}
+ else if (value instanceof Number) {
+ // Remove insignificant zeros
+ formatted = value.toString().replaceAll("(?:(\\..*[^0])0+|\\.0+)$", "$1");
+ }
else {
formatted = value.toString();
}