Repository: jtablesaw/tablesaw
Pull request #523 (2019-05-03 15:20:43)

Workaround for precision of 0 when reading jdbc resultset
Thanks for contributing.

- [X] Tick to sign-off your agreement to the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org)

## Description

Closes https://github.com/jtablesaw/tablesaw/issues/519. Thanks @edgar131 for the report, investigation, and suggested solution


lwhite1: Hi Ben, 

I'm on vacation and a bit short on time.  Thanks for taking care of this. 

A couple questions:

It looks like the case for p=0, falls through to an error. Is that correct? If so, why not return a LongColumn? It seems like anyone who hits the error will likely open a new issue. 

Could we make the 0 case explicit and add a comment explaining what it's for? It may save us troubleshooting this again down the line.

Could we add a test? 


edgar131: Can't use long because "numeric" types could be decimal numbers.  Has to be double to avoid losing any data.  If you do add an explicit case it is still preferable to not explicitly set it to double so that people can override the type if they want to.

> Hi Ben,
> 
> I'm on vacation and a bit short on time. Thanks for taking care of this.
> 
> A couple questions:
> 
> It looks like the case for p=0, falls through to an error. Is that correct? If so, why not return a LongColumn? It seems like anyone who hits the error will likely open a new issue.
> 
> Could we make the 0 case explicit and add a comment explaining what it's for? It may save us troubleshooting this again down the line.
> 
> Could we add a test?


lwhite1: > Can't use long because "numeric" types could be decimal numbers.

So the scale value returned by PG is also incorrect? Otherwise you know for a fact it's not a double.
edgar131: I cant test right now, but pretty sure it was -1 (essentially useless). According to postgres docs...

> NUMERIC without any precision or scale creates a column in which numeric values of any precision and scale can be stored, up to the implementation limit on precision. A column of this kind will not coerce input values to any particular scale, whereas numeric columns with a declared scale will coerce input values to that scale.

Because of that you would have to implement it as at least DOUBLE to ensure that no data is lost.

Patch:
diff --git a/core/src/main/java/tech/tablesaw/io/ColumnTypeDetector.java b/core/src/main/java/tech/tablesaw/io/ColumnTypeDetector.java
index e88fcbbf..351425d6 100644
--- a/core/src/main/java/tech/tablesaw/io/ColumnTypeDetector.java
+++ b/core/src/main/java/tech/tablesaw/io/ColumnTypeDetector.java
@@ -1,9 +1,6 @@
 package tech.tablesaw.io;
 
-import com.google.common.collect.Lists;
-import tech.tablesaw.api.ColumnType;
-import tech.tablesaw.columns.AbstractColumnParser;
-import tech.tablesaw.columns.strings.StringColumnType;
+import static tech.tablesaw.api.ColumnType.TEXT;
 
 import java.util.ArrayList;
 import java.util.HashSet;
@@ -11,15 +8,9 @@ import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
-import static tech.tablesaw.api.ColumnType.BOOLEAN;
-import static tech.tablesaw.api.ColumnType.DOUBLE;
-import static tech.tablesaw.api.ColumnType.INTEGER;
-import static tech.tablesaw.api.ColumnType.LOCAL_DATE;
-import static tech.tablesaw.api.ColumnType.LOCAL_DATE_TIME;
-import static tech.tablesaw.api.ColumnType.LOCAL_TIME;
-import static tech.tablesaw.api.ColumnType.LONG;
-import static tech.tablesaw.api.ColumnType.STRING;
-import static tech.tablesaw.api.ColumnType.TEXT;
+import tech.tablesaw.api.ColumnType;
+import tech.tablesaw.columns.AbstractColumnParser;
+import tech.tablesaw.columns.strings.StringColumnType;
 
 public class ColumnTypeDetector {
 
@@ -47,29 +38,18 @@ public class ColumnTypeDetector {
      */
     private static final double STRING_COLUMN_CUTOFF = 0.50;
 
+    private final List<ColumnType> typeArray;
+    
     /**
-     * Types to choose from. When more than one would work, we pick the first of the options. The order these appear in
-     * is critical. The broadest must go last, which is why String is at the end of the list. Any String read from
-     * the input will match string. If it were first on the list, you would get nothing but strings in your table.
-     *
-     * As another example, an integer type, should go before double. Otherwise double would match integers so
-     * the integer test would never be evaluated and all the ints would be read as doubles.
+     * @param typeArray Types to choose from. When more than one would work, we pick the first of
+     * the options. The order these appear in is critical. The broadest must go last, so String
+     * must be at the end of the list. Any String read from the input will match string. If it
+     * were first on the list, you would get nothing but strings in your table. As another example,
+     * an integer type, should go before double. Otherwise double would match integers so the
+     * integer test would never be evaluated and all the ints would be read as doubles.
      */
-    private List<ColumnType> typeArray =
-            Lists.newArrayList(
-                    LOCAL_DATE_TIME,
-                    LOCAL_TIME,
-                    LOCAL_DATE,
-                    BOOLEAN,
-                    INTEGER,
-                    LONG,
-                    DOUBLE,
-                    STRING);
-
-    public ColumnTypeDetector() {}
-    
-    public ColumnTypeDetector(List<ColumnType> typeArrayOverrides) {
-	    typeArray = typeArrayOverrides;
+    public ColumnTypeDetector(List<ColumnType> typeArray) {
+        this.typeArray = typeArray;
     }
     
     /**
diff --git a/core/src/main/java/tech/tablesaw/io/FileReader.java b/core/src/main/java/tech/tablesaw/io/FileReader.java
index 949c96ff..49dce8c3 100644
--- a/core/src/main/java/tech/tablesaw/io/FileReader.java
+++ b/core/src/main/java/tech/tablesaw/io/FileReader.java
@@ -19,22 +19,11 @@ import static tech.tablesaw.api.ColumnType.SKIP;
 
 public abstract class FileReader {
 
-    private List<ColumnType> typeArrayOverrides = new ArrayList<>();
-
     /**
      * Constructs a CsvReader
      */
     public FileReader() {}
 
-    /**
-     * Constructs a CsvReader with the given list of ColumnTypes
-     * <p>
-     * These are the only types that the CsvReader can detect and parse
-     */
-    public FileReader(List<ColumnType> typeDetectionList) {
-        this.typeArrayOverrides = typeDetectionList;
-    }
-
     protected ColumnType[] getTypes(Reader reader, ReadOptions options, int linesToSkip, AbstractParser<?> parser) {
 
         parser.beginParsing(reader);
@@ -43,12 +32,7 @@ public abstract class FileReader {
             parser.parseNext();
         }
 
-        if (options.minimizeColumnSizes()) {
-            typeArrayOverrides = ReadOptions.EXTENDED_TYPE_ARRAY;
-        }
-
-        ColumnTypeDetector detector = typeArrayOverrides.isEmpty()
-                ? new ColumnTypeDetector() : new ColumnTypeDetector(typeArrayOverrides);
+        ColumnTypeDetector detector = new ColumnTypeDetector(options.columnTypesToDetect());
 
         return detector.detectColumnTypes(new Iterator<String[]>() {
 
diff --git a/core/src/main/java/tech/tablesaw/io/ReadOptions.java b/core/src/main/java/tech/tablesaw/io/ReadOptions.java
index 46d2a9db..a88f9e58 100644
--- a/core/src/main/java/tech/tablesaw/io/ReadOptions.java
+++ b/core/src/main/java/tech/tablesaw/io/ReadOptions.java
@@ -42,12 +42,22 @@ import static tech.tablesaw.api.ColumnType.TEXT;
 
 public class ReadOptions {
 
+    private static final List<ColumnType> DEFAULT_TYPES = Lists.newArrayList(
+            LOCAL_DATE_TIME,
+            LOCAL_TIME,
+            LOCAL_DATE,
+            BOOLEAN,
+            INTEGER,
+            LONG,
+            DOUBLE,
+            STRING);
+
     /**
      * An extended list of types that are used if minimizeColumnSizes is true. By including extra types like Short
      * the resulting table size is reduced at the cost of some additional complexity for the programmer if, for example,
      * they will subsequently modify the data in a way that exceeds the range of the type.
      */
-    public static final List<ColumnType> EXTENDED_TYPE_ARRAY =
+    private static final List<ColumnType> EXTENDED_TYPES =
             Lists.newArrayList(
                     LOCAL_DATE_TIME,
                     LOCAL_TIME,
@@ -63,6 +73,7 @@ public class ReadOptions {
 
     protected final Source source;
     protected final String tableName;
+    protected final List<ColumnType> columnTypesToDetect;
     protected final boolean sample;
     protected final String dateFormat;
     protected final String dateTimeFormat;
@@ -81,6 +92,7 @@ public class ReadOptions {
     protected ReadOptions(ReadOptions.Builder builder) {
 	source = builder.source;
         tableName = builder.tableName;
+        columnTypesToDetect = builder.columnTypesToDetect;
         sample = builder.sample;
         dateFormat = builder.dateFormat;
         timeFormat = builder.timeFormat;
@@ -109,6 +121,10 @@ public class ReadOptions {
         return tableName;
     }
 
+    public List<ColumnType> columnTypesToDetect() {
+        return columnTypesToDetect;
+    }
+
     public boolean sample() {
         return sample;
     }
@@ -164,6 +180,7 @@ public class ReadOptions {
 
         protected final Source source;
         protected String tableName = "";
+        protected List<ColumnType> columnTypesToDetect = DEFAULT_TYPES;
         protected boolean sample = true;
         protected String dateFormat;
         protected DateTimeFormatter dateFormatter;
@@ -275,8 +292,20 @@ public class ReadOptions {
             return this;
         }
 
-        public Builder minimizeColumnSizes(boolean minimize) {
-            this.minimizeColumnSizes = minimize;
+        /**
+         * @see ColumnTypeDetector
+         */
+        public Builder columnTypesToDetect(List<ColumnType> columnTypesToDetect) {
+            this.columnTypesToDetect = columnTypesToDetect;
+            return this;
+        }
+
+        /**
+         * Allow the {@link ColumnTypeDetector} to choose shorter column types such as float
+         * instead of double when the data will fit in a smaller type
+         */
+        public Builder minimizeColumnSizes() {
+            this.columnTypesToDetect = EXTENDED_TYPES;
             return this;
         }
         
diff --git a/core/src/main/java/tech/tablesaw/io/TableBuildingUtils.java b/core/src/main/java/tech/tablesaw/io/TableBuildingUtils.java
index 4f437881..e8125f52 100644
--- a/core/src/main/java/tech/tablesaw/io/TableBuildingUtils.java
+++ b/core/src/main/java/tech/tablesaw/io/TableBuildingUtils.java
@@ -15,7 +15,7 @@ public class TableBuildingUtils {
             return table;
         }
 
-        ColumnTypeDetector detector = new ColumnTypeDetector();
+        ColumnTypeDetector detector = new ColumnTypeDetector(options.columnTypesToDetect());
         Iterator<String[]> iterator = dataRows.iterator();
         ColumnType[] types = detector.detectColumnTypes(iterator, options);
         for (int i = 0; i < columnNames.size(); i++) {
diff --git a/core/src/main/java/tech/tablesaw/io/csv/CsvReadOptions.java b/core/src/main/java/tech/tablesaw/io/csv/CsvReadOptions.java
index d3b40d5c..844e718e 100644
--- a/core/src/main/java/tech/tablesaw/io/csv/CsvReadOptions.java
+++ b/core/src/main/java/tech/tablesaw/io/csv/CsvReadOptions.java
@@ -268,8 +268,8 @@ public class CsvReadOptions extends ReadOptions {
         }
 
         @Override
-        public Builder minimizeColumnSizes(boolean minimizeColumnSizes) {
-            super.minimizeColumnSizes(minimizeColumnSizes);
+        public Builder minimizeColumnSizes() {
+            super.minimizeColumnSizes();
             return this;
         }
     }
diff --git a/core/src/main/java/tech/tablesaw/io/csv/CsvReader.java b/core/src/main/java/tech/tablesaw/io/csv/CsvReader.java
index da696b74..cadfb8ff 100644
--- a/core/src/main/java/tech/tablesaw/io/csv/CsvReader.java
+++ b/core/src/main/java/tech/tablesaw/io/csv/CsvReader.java
@@ -30,7 +30,6 @@ import tech.tablesaw.io.Source;
 import javax.annotation.concurrent.Immutable;
 import java.io.IOException;
 import java.io.Reader;
-import java.util.List;
 
 @Immutable
 public class CsvReader extends FileReader implements DataReader<CsvReadOptions> {
@@ -54,15 +53,6 @@ public class CsvReader extends FileReader implements DataReader<CsvReadOptions>
         super();
     }
 
-    /**
-     * Constructs a CsvReader with the given list of ColumnTypes
-     * <p>
-     * These are the only types that the CsvReader can detect and parse
-     */
-    public CsvReader(List<ColumnType> typeDetectionList) {
-        super(typeDetectionList);
-    }
-
     /**
      * Determines column types if not provided by the user
      * Reads all input into memory unless File was provided
diff --git a/core/src/main/java/tech/tablesaw/io/fixed/FixedWidthReadOptions.java b/core/src/main/java/tech/tablesaw/io/fixed/FixedWidthReadOptions.java
index efbd98a1..c0a544f5 100644
--- a/core/src/main/java/tech/tablesaw/io/fixed/FixedWidthReadOptions.java
+++ b/core/src/main/java/tech/tablesaw/io/fixed/FixedWidthReadOptions.java
@@ -290,8 +290,8 @@ public class FixedWidthReadOptions extends ReadOptions {
         }
 
         @Override
-        public Builder minimizeColumnSizes(boolean minimizeColumnSizes) {
-            super.minimizeColumnSizes(minimizeColumnSizes);
+        public Builder minimizeColumnSizes() {
+            super.minimizeColumnSizes();
             return this;
         }
     }
diff --git a/core/src/main/java/tech/tablesaw/io/fixed/FixedWidthReader.java b/core/src/main/java/tech/tablesaw/io/fixed/FixedWidthReader.java
index 08d68b08..d2a486df 100644
--- a/core/src/main/java/tech/tablesaw/io/fixed/FixedWidthReader.java
+++ b/core/src/main/java/tech/tablesaw/io/fixed/FixedWidthReader.java
@@ -30,7 +30,6 @@ import tech.tablesaw.io.Source;
 import javax.annotation.concurrent.Immutable;
 import java.io.IOException;
 import java.io.Reader;
-import java.util.List;
 
 @Immutable
 public class FixedWidthReader extends FileReader implements DataReader<FixedWidthReadOptions> {
@@ -52,15 +51,6 @@ public class FixedWidthReader extends FileReader implements DataReader<FixedWidt
         super();
     }
 
-    /**
-     * Constructs a FixedWidthReader with the given list of ColumnTypes
-     * <p>
-     * These are the only types that the FixedWidthReader can detect and parse
-     */
-    public FixedWidthReader(List<ColumnType> typeDetectionList) {
-        super(typeDetectionList);
-    }
-
     /**
      * Determines column types if not provided by the user
      * Reads all input into memory unless File was provided
diff --git a/core/src/main/java/tech/tablesaw/io/jdbc/SqlResultSetReader.java b/core/src/main/java/tech/tablesaw/io/jdbc/SqlResultSetReader.java
index c8e95821..c610e51c 100644
--- a/core/src/main/java/tech/tablesaw/io/jdbc/SqlResultSetReader.java
+++ b/core/src/main/java/tech/tablesaw/io/jdbc/SqlResultSetReader.java
@@ -24,7 +24,6 @@ import tech.tablesaw.api.LongColumn;
 import tech.tablesaw.api.ShortColumn;
 import tech.tablesaw.api.Table;
 import tech.tablesaw.columns.Column;
-import tech.tablesaw.columns.numbers.ShortColumnType;
 
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
@@ -94,48 +93,12 @@ public class SqlResultSetReader {
 
         // Setup the columns and add to the table
         for (int i = 1; i <= metaData.getColumnCount(); i++) {
-            String name = metaData.getColumnName(i);
-            int columnType = metaData.getColumnType(i);
-            ColumnType type = SQL_TYPE_TO_TABLESAW_TYPE.get(columnType);
-            // Try to improve on the initial type assigned to 'type' to minimize size/space of type needed.
-            // For all generic numeric columns inspect closer, checking the precision and 
-            // scale to more accurately determine the appropriate java type to use.
-            if (columnType == Types.NUMERIC || columnType == Types.DECIMAL) {
-                int s = metaData.getScale(i);
-                // When scale is 0 then column is a type of integer
-                if (s == 0) {
-                    int p = metaData.getPrecision(i);
-/* Mapping to java integer types based on integer precision defined:
+            ColumnType type = getColumnType(metaData.getColumnType(i), metaData.getScale(i), metaData.getPrecision(i));
 
-Java type           TypeMinVal              TypeMaxVal          p               MaxIntVal
------------------------------------------------------------------------------------------
-byte, Byte:         -128                    127                 NUMBER(2)       99
-short, Short:       -32768                  32767               NUMBER(4)       9_999
-int, Integer:       -2147483648             2147483647          NUMBER(9)       999_999_999 
-long, Long:         -9223372036854775808    9223372036854775807 NUMBER(18)      999_999_999_999_999_999
-
-*/
-                    // Start with SHORT (since ColumnType.BYTE isn't supported yet)
-                    // and find the smallest java integer type that fits
-                    if (p <= 4) {
-                        type = ShortColumnType.instance();
-                    } else if (p <= 9) {
-                        type = ColumnType.INTEGER;
-                    } else if (p <= 18) {
-                        type = ColumnType.LONG;
-                    }
-                } else { // s is not zero, so a decimal value is expected. First try float, then double
-                    if (s <= 7) {
-                        type = ColumnType.FLOAT;
-                    } else if (s <= 16) {
-                        type = ColumnType.DOUBLE;
-                    }
-                }
-            }
             Preconditions.checkState(type != null,
-                    "No column type found for %s as specified for column %s", metaData.getColumnType(i), name);
+                    "No column type found for %s as specified for column %s", metaData.getColumnType(i), metaData.getColumnName(i));
 
-            Column<?> newColumn = type.create(name);
+            Column<?> newColumn = type.create(metaData.getColumnName(i));
             table.addColumns(newColumn);
         }
 
@@ -160,4 +123,45 @@ long, Long:         -9223372036854775808    9223372036854775807 NUMBER(18)
         }
         return table;
     }
+    
+    protected static ColumnType getColumnType(int columnType, int scale, int precision) {
+        ColumnType type = SQL_TYPE_TO_TABLESAW_TYPE.get(columnType);
+        // Try to improve on the initial type assigned to 'type' to minimize size/space of type needed.
+        // For all generic numeric columns inspect closer, checking the precision and 
+        // scale to more accurately determine the appropriate java type to use.
+        if (columnType == Types.NUMERIC || columnType == Types.DECIMAL) {
+            // When scale is 0 then column is a type of integer
+            if (scale == 0) {
+/* Mapping to java integer types based on integer precision defined:
+
+Java type           TypeMinVal              TypeMaxVal          p               MaxIntVal
+-----------------------------------------------------------------------------------------
+byte, Byte:         -128                    127                 NUMBER(2)       99
+short, Short:       -32768                  32767               NUMBER(4)       9_999
+int, Integer:       -2147483648             2147483647          NUMBER(9)       999_999_999 
+long, Long:         -9223372036854775808    9223372036854775807 NUMBER(18)      999_999_999_999_999_999
+
+*/
+                if (precision > 0) {
+                    if (precision <= 4) {
+                        // Start with SHORT (since ColumnType.BYTE isn't supported yet)
+                        // and find the smallest java integer type that fits
+                        type = ColumnType.SHORT;
+                    } else if (precision <= 9) {
+                        type = ColumnType.INTEGER;
+                    } else if (precision <= 18) {
+                        type = ColumnType.LONG;
+                    }
+                }
+            } else { // s is not zero, so a decimal value is expected. First try float, then double
+                if (scale <= 7) {
+                    type = ColumnType.FLOAT;
+                } else if (scale <= 16) {
+                    type = ColumnType.DOUBLE;
+                }
+            }
+        }
+        return type;
+    }
+
 }
\ No newline at end of file
diff --git a/excel/src/main/java/tech/tablesaw/io/xlsx/XlsxReadOptions.java b/excel/src/main/java/tech/tablesaw/io/xlsx/XlsxReadOptions.java
index 8ecbf98a..e39ad065 100644
--- a/excel/src/main/java/tech/tablesaw/io/xlsx/XlsxReadOptions.java
+++ b/excel/src/main/java/tech/tablesaw/io/xlsx/XlsxReadOptions.java
@@ -140,8 +140,8 @@ public class XlsxReadOptions extends ReadOptions {
         }
 
         @Override
-        public Builder minimizeColumnSizes(boolean minimizeColumnSizes) {
-            super.minimizeColumnSizes(minimizeColumnSizes);
+        public Builder minimizeColumnSizes() {
+            super.minimizeColumnSizes();
             return this;
         }
     }
diff --git a/html/src/main/java/tech/tablesaw/io/html/HtmlReadOptions.java b/html/src/main/java/tech/tablesaw/io/html/HtmlReadOptions.java
index 11e7f266..f0724f06 100644
--- a/html/src/main/java/tech/tablesaw/io/html/HtmlReadOptions.java
+++ b/html/src/main/java/tech/tablesaw/io/html/HtmlReadOptions.java
@@ -170,8 +170,8 @@ public class HtmlReadOptions extends ReadOptions {
         }
 
         @Override
-        public Builder minimizeColumnSizes(boolean minimizeColumnSizes) {
-            super.minimizeColumnSizes(minimizeColumnSizes);
+        public Builder minimizeColumnSizes() {
+            super.minimizeColumnSizes();
             return this;
         }    
     }
diff --git a/json/src/main/java/tech/tablesaw/io/json/JsonReadOptions.java b/json/src/main/java/tech/tablesaw/io/json/JsonReadOptions.java
index 762c8b42..2d02ec84 100644
--- a/json/src/main/java/tech/tablesaw/io/json/JsonReadOptions.java
+++ b/json/src/main/java/tech/tablesaw/io/json/JsonReadOptions.java
@@ -169,8 +169,8 @@ public class JsonReadOptions extends ReadOptions {
         }
 
         @Override
-        public Builder minimizeColumnSizes(boolean minimizeColumnSizes) {
-            super.minimizeColumnSizes(minimizeColumnSizes);
+        public Builder minimizeColumnSizes() {
+            super.minimizeColumnSizes();
             return this;
         }
     }


Test patch:
diff --git a/core/src/test/java/tech/tablesaw/TableFilteringTest.java b/core/src/test/java/tech/tablesaw/TableFilteringTest.java
index 2ec48f3a..dc775ab9 100644
--- a/core/src/test/java/tech/tablesaw/TableFilteringTest.java
+++ b/core/src/test/java/tech/tablesaw/TableFilteringTest.java
@@ -41,7 +41,7 @@ public class TableFilteringTest {
 
     @BeforeEach
     public void setUp() throws Exception {
-        table = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true));
+        table = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes());
     }
 
     @Test
diff --git a/core/src/test/java/tech/tablesaw/api/RowTest.java b/core/src/test/java/tech/tablesaw/api/RowTest.java
index 1d458e87..37df598d 100644
--- a/core/src/test/java/tech/tablesaw/api/RowTest.java
+++ b/core/src/test/java/tech/tablesaw/api/RowTest.java
@@ -92,7 +92,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/rev_tornadoes_1950-2014.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         DateTimeColumn dateTimeCol = table.dateColumn("Date").atTime(table.timeColumn("Time"));
         dateTimeCol.setName("DateTime");
         table.addColumns(dateTimeCol);
@@ -154,7 +154,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/bush.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         Row row = new Row(table);
         while (row.hasNext()) {
             row.next();
@@ -172,7 +172,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/bush.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         Row row = new Row(table);
         while (row.hasNext()) {
             row.next();
@@ -205,7 +205,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/rev_tornadoes_1950-2014.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         DateTimeColumn dateTimeCol = table.dateColumn("Date").atTime(table.timeColumn("Time"));
         dateTimeCol.setName("DateTime");
         table.addColumns(dateTimeCol);
@@ -227,7 +227,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/rev_tornadoes_1950-2014.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         Row row = new Row(table);
         while (row.hasNext()) {
             row.next();
@@ -244,7 +244,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/bush.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         Row row = new Row(table);
         while (row.hasNext()) {
             row.next();
@@ -260,7 +260,7 @@ public class RowTest {
         ColumnType[] types = {LOCAL_DATE, SHORT, STRING};
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/bush.csv"))
-                        .minimizeColumnSizes(true)
+                        .minimizeColumnSizes()
                         .columnTypes(types));
         Row row = new Row(table);
         while (row.hasNext()) {
@@ -277,7 +277,7 @@ public class RowTest {
         ColumnType[] types = {LOCAL_DATE, SHORT, TEXT};
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/bush.csv"))
-                        .minimizeColumnSizes(true)
+                        .minimizeColumnSizes()
                         .columnTypes(types));
         Row row = new Row(table);
         while (row.hasNext()) {
@@ -297,7 +297,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/rev_tornadoes_1950-2014.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         Row row = new Row(table);
         while (row.hasNext()) {
             row.next();
@@ -360,7 +360,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/rev_tornadoes_1950-2014.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         DateTimeColumn dateTimeCol = table.dateColumn("Date").atTime(table.timeColumn("Time"));
         dateTimeCol.setName("DateTime");
         table.addColumns(dateTimeCol);
@@ -467,7 +467,7 @@ public class RowTest {
         ColumnType[] types = {LOCAL_DATE, LONG, STRING};
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/bush.csv"))
-                        .minimizeColumnSizes(true)
+                        .minimizeColumnSizes()
                         .columnTypes(types));
         Row row = new Row(table);
         while (row.hasNext()) {
@@ -491,7 +491,7 @@ public class RowTest {
         ColumnType[] types = {LOCAL_DATE, SHORT, STRING};
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/bush.csv"))
-                        .minimizeColumnSizes(true)
+                        .minimizeColumnSizes()
                         .columnTypes(types));
         Row row = new Row(table);
         while (row.hasNext()) {
@@ -537,7 +537,7 @@ public class RowTest {
         ColumnType[] types = {LOCAL_DATE, SHORT, TEXT};
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/bush.csv"))
-                        .minimizeColumnSizes(true)
+                        .minimizeColumnSizes()
                         .columnTypes(types));
         Row row = new Row(table);
         while (row.hasNext()) {
@@ -566,7 +566,7 @@ public class RowTest {
         Table table = Table.read().csv(
                 CsvReadOptions.builder(new File("../data/rev_tornadoes_1950-2014.csv"))
                         .columnTypes(types)
-                        .minimizeColumnSizes(true));
+                        .minimizeColumnSizes());
         Row row = new Row(table);
         while (row.hasNext()) {
             row.next();
diff --git a/core/src/test/java/tech/tablesaw/api/TableTest.java b/core/src/test/java/tech/tablesaw/api/TableTest.java
index bec00611..0e88b89f 100644
--- a/core/src/test/java/tech/tablesaw/api/TableTest.java
+++ b/core/src/test/java/tech/tablesaw/api/TableTest.java
@@ -217,7 +217,7 @@ public class TableTest {
 
     @Test
     public void testDoWithEachRow() throws Exception {
-        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true)).first(10);
+        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes()).first(10);
         Short[] ratingsArray = {53, 58};
         List<Short> ratings = Lists.asList((short) 52, ratingsArray);
 
@@ -231,7 +231,7 @@ public class TableTest {
 
     @Test
     public void testDoWithEachRow2() throws Exception {
-        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true));
+        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes());
         int dateTarget = PackedLocalDate.pack(LocalDate.of(2002, 1, 1));
         double ratingTarget = 75;
         AtomicInteger count = new AtomicInteger(0);
@@ -247,7 +247,7 @@ public class TableTest {
 
     @Test
     public void testDetect() throws Exception {
-        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true));
+        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes());
         int dateTarget = PackedLocalDate.pack(LocalDate.of(2002, 1, 1));
         double ratingTarget = 75;
         Predicate<Row> doable = row ->
@@ -269,14 +269,14 @@ public class TableTest {
 
     @Test
     public void testPairs() throws Exception {
-        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true));
+        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes());
         PairChild pairs = new PairChild();
         t.doWithRows(pairs);
     }
 
     @Test
     public void testPairs2() throws Exception {
-        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true));
+        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes());
 
         Table.Pairs runningAvg =  new Table.Pairs() {
 
@@ -301,7 +301,7 @@ public class TableTest {
     @Test
     public void stepWithRows() throws Exception {
         Table t = Table.read()
-                .csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true))
+                .csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes())
                 .first(6);
 
         final int sum1 = (int) t.shortColumn("approval").sum();
@@ -330,7 +330,7 @@ public class TableTest {
 
     @Test
     public void testRollWithNrows2() throws Exception {
-        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true)).first(4);
+        Table t = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes()).first(4);
         ShortColumn approval = t.shortColumn("approval");
 
         List<Integer> sums = new ArrayList<>();
@@ -515,7 +515,7 @@ public class TableTest {
 
     @Test
     public void testRowSort() throws Exception {
-        Table bush = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes(true));
+        Table bush = Table.read().csv(CsvReadOptions.builder("../data/bush.csv").minimizeColumnSizes());
 
         Comparator<Row> rowComparator = Comparator.comparingDouble(o -> o.getShort("approval"));
 
diff --git a/core/src/test/java/tech/tablesaw/io/csv/CsvReaderTest.java b/core/src/test/java/tech/tablesaw/io/csv/CsvReaderTest.java
index 873642e9..f19480a4 100644
--- a/core/src/test/java/tech/tablesaw/io/csv/CsvReaderTest.java
+++ b/core/src/test/java/tech/tablesaw/io/csv/CsvReaderTest.java
@@ -164,7 +164,7 @@ public class CsvReaderTest {
         Reader reader = new FileReader("../data/bus_stop_test.csv");
         CsvReadOptions options = CsvReadOptions.builder(reader)
                 .header(true)
-                .minimizeColumnSizes(true)
+                .minimizeColumnSizes()
                 .separator(',')
                 .sample(false)
                 .locale(Locale.getDefault())
@@ -590,7 +590,7 @@ public class CsvReaderTest {
     public void testReadFailure() throws IOException {
         // TODO (lwhite): These tests don't fail. What was their intent?
         Table table1 = Table.read().csv(CsvReadOptions.builder("../data/read_failure_test.csv")
-                .minimizeColumnSizes(true));
+                .minimizeColumnSizes());
         table1.structure(); // just make sure the import completed
         ShortColumn test = table1.shortColumn("Test");
         //TODO(lwhite): Better tests
@@ -601,7 +601,7 @@ public class CsvReaderTest {
     public void testReadFailure2() throws IOException {
         Table table1 = Table.read().csv(
                 CsvReadOptions.builder("../data/read_failure_test2.csv")
-                .minimizeColumnSizes(true));
+                .minimizeColumnSizes());
         table1.structure(); // just make sure the import completed
         ShortColumn test = table1.shortColumn("Test");
 
diff --git a/core/src/test/java/tech/tablesaw/io/fixed/FixedWidthReaderTest.java b/core/src/test/java/tech/tablesaw/io/fixed/FixedWidthReaderTest.java
index 2ac3330b..5f3b2792 100644
--- a/core/src/test/java/tech/tablesaw/io/fixed/FixedWidthReaderTest.java
+++ b/core/src/test/java/tech/tablesaw/io/fixed/FixedWidthReaderTest.java
@@ -113,7 +113,7 @@ public class FixedWidthReaderTest {
                 .lineEnding("\n")
                 .sample(false)
                 .locale(Locale.getDefault())
-                .minimizeColumnSizes(true)
+                .minimizeColumnSizes()
                 .build();
 
         Reader reader = new FileReader("../data/fixed_width_missing_values.txt");
@@ -131,7 +131,7 @@ public class FixedWidthReaderTest {
                 .padding('_')
                 .lineEnding("\n")
                 .missingValueIndicator("null")
-                .minimizeColumnSizes(true)
+                .minimizeColumnSizes()
                 .sample(false)
                 .build();
 
diff --git a/core/src/test/java/tech/tablesaw/io/jdbc/SqlResultSetReaderTest.java b/core/src/test/java/tech/tablesaw/io/jdbc/SqlResultSetReaderTest.java
index 62257d68..495a3c38 100644
--- a/core/src/test/java/tech/tablesaw/io/jdbc/SqlResultSetReaderTest.java
+++ b/core/src/test/java/tech/tablesaw/io/jdbc/SqlResultSetReaderTest.java
@@ -21,9 +21,11 @@ import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.Statement;
+import java.sql.Types;
 
 import org.junit.jupiter.api.Test;
 
+import tech.tablesaw.api.ColumnType;
 import tech.tablesaw.api.Table;
 import tech.tablesaw.columns.numbers.DoubleColumnType;
 import tech.tablesaw.columns.numbers.FloatColumnType;
@@ -108,4 +110,9 @@ public class SqlResultSetReaderTest {
 
         }
     }
+
+    @Test
+    public void invalidPrecision() {
+	assertEquals(ColumnType.DOUBLE, SqlResultSetReader.getColumnType(Types.NUMERIC, 0, 0));
+    }
 }
\ No newline at end of file