Repository: jtablesaw/tablesaw
Pull request #400 (2018-10-15 07:06:42)

Sql number type mapping
Thanks for contributing.

- [X] Tick to sign-off your agreement to the [Developer Certificate of Origin (DCO) 1.1](https://developercertificate.org)

## Description

Added logic to interpret NUMBER SQL type according to its precision and scale properties.  Since Oracle converts all convenient numeric types like INTEGER to the equivalent NUMBER type internally, and that NUMBER type is what is present when importing the ResultSet into a new Table instance, an improved logic for mapping the NUMBER type to the best Column type is proposed. 

## Testing

Yes.  Junit tests were added.


benmccann: @gregorco I noticed there's a number of tabs present in this PR. Can you replace with spaces? Thanks!

Patch:
diff --git a/aggregate/pom.xml b/aggregate/pom.xml
index 557e04c2..9bdaeca0 100644
--- a/aggregate/pom.xml
+++ b/aggregate/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>tech.tablesaw</groupId>
     <artifactId>tablesaw-parent</artifactId>
-    <version>0.30.1-SNAPSHOT</version>
+    <version>0.30.2-SNAPSHOT</version>
   </parent>
 
   <!--
@@ -51,17 +51,17 @@
     <dependency>
       <groupId>tech.tablesaw</groupId>
       <artifactId>tablesaw-core</artifactId>
-      <version>0.30.1-SNAPSHOT</version>
+      <version>0.30.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>tech.tablesaw</groupId>
       <artifactId>tablesaw-jsplot</artifactId>
-      <version>0.30.1-SNAPSHOT</version>
+      <version>0.30.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>tech.tablesaw</groupId>
       <artifactId>tablesaw-beakerx</artifactId>
-      <version>0.30.1-SNAPSHOT</version>
+      <version>0.30.2-SNAPSHOT</version>
     </dependency>
   </dependencies>
 </project>
diff --git a/beakerx/pom.xml b/beakerx/pom.xml
index 4cf39759..3520f56b 100644
--- a/beakerx/pom.xml
+++ b/beakerx/pom.xml
@@ -5,7 +5,7 @@
   <parent>
     <groupId>tech.tablesaw</groupId>
     <artifactId>tablesaw-parent</artifactId>
-    <version>0.30.1-SNAPSHOT</version>
+    <version>0.30.2-SNAPSHOT</version>
   </parent>
 
   <artifactId>tablesaw-beakerx</artifactId>
@@ -63,7 +63,7 @@
     <dependency>
       <groupId>tech.tablesaw</groupId>
       <artifactId>tablesaw-core</artifactId>
-      <version>0.30.1-SNAPSHOT</version>
+      <version>0.30.2-SNAPSHOT</version>
     </dependency>
     <dependency>
       <groupId>com.github.twosigma</groupId>
diff --git a/core/pom.xml b/core/pom.xml
index 674645be..55a023e6 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <groupId>tech.tablesaw</groupId>
         <artifactId>tablesaw-parent</artifactId>
-        <version>0.30.1-SNAPSHOT</version>
+        <version>0.30.2-SNAPSHOT</version>
     </parent>
 
     <artifactId>tablesaw-core</artifactId>
diff --git a/core/src/main/java/tech/tablesaw/api/DateColumn.java b/core/src/main/java/tech/tablesaw/api/DateColumn.java
index 41557a9e..2af27328 100644
--- a/core/src/main/java/tech/tablesaw/api/DateColumn.java
+++ b/core/src/main/java/tech/tablesaw/api/DateColumn.java
@@ -354,10 +354,13 @@ public class DateColumn extends AbstractColumn<LocalDate> implements DateFilters
         if (obj == null) {
             return appendMissing();
         }
-        if (!(obj instanceof LocalDate)) {
-            throw new IllegalArgumentException("Cannot append " + obj.getClass().getName() + " to DateColumn");
+        if (obj instanceof java.sql.Date) {
+            return append(((java.sql.Date) obj).toLocalDate());
         }
-        return append((LocalDate) obj);
+        if (obj instanceof LocalDate) {
+            return append((LocalDate) obj);
+        }
+        throw new IllegalArgumentException("Cannot append " + obj.getClass().getName() + " to DateColumn");
     }
 
     @Override
diff --git a/core/src/main/java/tech/tablesaw/api/FloatColumn.java b/core/src/main/java/tech/tablesaw/api/FloatColumn.java
index 0142e1d7..ba9cbcbf 100644
--- a/core/src/main/java/tech/tablesaw/api/FloatColumn.java
+++ b/core/src/main/java/tech/tablesaw/api/FloatColumn.java
@@ -97,7 +97,7 @@ public class FloatColumn extends NumberColumn<Float> {
                 values.add(getFloat(i));
             }
         }
-        final FloatColumn column = FloatColumn.create(name() + " Unique values", values.size());
+        final FloatColumn column = FloatColumn.create(name() + " Unique values");
         for (float value : values) {
             column.append(value);
         }
diff --git a/core/src/main/java/tech/tablesaw/api/IntColumn.java b/core/src/main/java/tech/tablesaw/api/IntColumn.java
index 7c7ce9c0..22205f19 100644
--- a/core/src/main/java/tech/tablesaw/api/IntColumn.java
+++ b/core/src/main/java/tech/tablesaw/api/IntColumn.java
@@ -116,7 +116,7 @@ public class IntColumn extends NumberColumn<Integer> implements CategoricalColum
                 values.add(getInt(i));
             }
         }
-        final IntColumn column = IntColumn.create(name() + " Unique values", values.size());
+        final IntColumn column = IntColumn.create(name() + " Unique values");
         for (int value : values) {
             column.append(value);
         }
diff --git a/core/src/main/java/tech/tablesaw/api/LongColumn.java b/core/src/main/java/tech/tablesaw/api/LongColumn.java
index 073f9603..04acf4b4 100644
--- a/core/src/main/java/tech/tablesaw/api/LongColumn.java
+++ b/core/src/main/java/tech/tablesaw/api/LongColumn.java
@@ -118,7 +118,7 @@ public class LongColumn extends NumberColumn<Long> implements CategoricalColumn<
                 values.add(getLong(i));
             }
         }
-        final LongColumn column = LongColumn.create(name() + " Unique values", values.size());
+        final LongColumn column = LongColumn.create(name() + " Unique values");
         for (long value : values) {
             column.append(value);
         }
diff --git a/core/src/main/java/tech/tablesaw/api/ShortColumn.java b/core/src/main/java/tech/tablesaw/api/ShortColumn.java
index 09432e9a..4a38443f 100644
--- a/core/src/main/java/tech/tablesaw/api/ShortColumn.java
+++ b/core/src/main/java/tech/tablesaw/api/ShortColumn.java
@@ -107,7 +107,8 @@ public class ShortColumn extends NumberColumn<Short> implements CategoricalColum
                 values.add(getShort(i));
             }
         }
-        final ShortColumn column = ShortColumn.create(name() + " Unique values", values.size());
+        final ShortColumn column = ShortColumn.create(name() + " Unique values");
+
         for (short value : values) {
             column.append(value);
         }
diff --git a/core/src/main/java/tech/tablesaw/api/TextColumn.java b/core/src/main/java/tech/tablesaw/api/TextColumn.java
index 60438179..8ec9b468 100644
--- a/core/src/main/java/tech/tablesaw/api/TextColumn.java
+++ b/core/src/main/java/tech/tablesaw/api/TextColumn.java
@@ -46,7 +46,7 @@ import java.util.Set;
  * of missing values in this class's methods.
  */
 public class TextColumn extends AbstractColumn<String>
-        implements StringFilters, StringMapFunctions, StringReduceUtils {
+        implements CategoricalColumn<String>, StringFilters, StringMapFunctions, StringReduceUtils {
 
     public static final String MISSING_VALUE = TextColumnType.missingValueIndicator();
 
diff --git a/core/src/main/java/tech/tablesaw/columns/strings/ByteDictionaryMap.java b/core/src/main/java/tech/tablesaw/columns/strings/ByteDictionaryMap.java
index dea398b3..d5b1d840 100644
--- a/core/src/main/java/tech/tablesaw/columns/strings/ByteDictionaryMap.java
+++ b/core/src/main/java/tech/tablesaw/columns/strings/ByteDictionaryMap.java
@@ -218,7 +218,7 @@ public class ByteDictionaryMap implements DictionaryMap {
         byte key;
         if (value == null || StringColumnType.missingValueIndicator().equals(value)) {
             key = MISSING_VALUE;
-            put(key, value);
+            put(key, StringColumnType.missingValueIndicator());
         } else {
             key = getKeyForValue(value);
         }
diff --git a/core/src/main/java/tech/tablesaw/columns/strings/IntDictionaryMap.java b/core/src/main/java/tech/tablesaw/columns/strings/IntDictionaryMap.java
index 834b39cd..1d4138d2 100644
--- a/core/src/main/java/tech/tablesaw/columns/strings/IntDictionaryMap.java
+++ b/core/src/main/java/tech/tablesaw/columns/strings/IntDictionaryMap.java
@@ -225,7 +225,7 @@ public class IntDictionaryMap implements DictionaryMap {
         int key;
         if (value == null || StringColumnType.missingValueIndicator().equals(value)) {
             key = MISSING_VALUE;
-            put(key, value);
+            put(key, StringColumnType.missingValueIndicator());
         } else {
             key = getKeyForValue(value);
         }
diff --git a/core/src/main/java/tech/tablesaw/columns/strings/ShortDictionaryMap.java b/core/src/main/java/tech/tablesaw/columns/strings/ShortDictionaryMap.java
index 86306298..8a1df0f9 100644
--- a/core/src/main/java/tech/tablesaw/columns/strings/ShortDictionaryMap.java
+++ b/core/src/main/java/tech/tablesaw/columns/strings/ShortDictionaryMap.java
@@ -230,7 +230,7 @@ public class ShortDictionaryMap implements DictionaryMap {
         short key;
         if (value == null || StringColumnType.missingValueIndicator().equals(value)) {
             key = MISSING_VALUE;
-            put(key, value);
+            put(key, StringColumnType.missingValueIndicator());
         } else {
             key = getKeyForValue(value);
         }
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 fc72cc5e..75878d91 100644
--- a/core/src/main/java/tech/tablesaw/io/jdbc/SqlResultSetReader.java
+++ b/core/src/main/java/tech/tablesaw/io/jdbc/SqlResultSetReader.java
@@ -14,12 +14,6 @@
 
 package tech.tablesaw.io.jdbc;
 
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableMap;
-import tech.tablesaw.api.ColumnType;
-import tech.tablesaw.api.Table;
-import tech.tablesaw.columns.Column;
-
 import java.sql.ResultSet;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
@@ -27,6 +21,18 @@ import java.sql.Types;
 import java.util.HashMap;
 import java.util.Map;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+
+import tech.tablesaw.api.ColumnType;
+import tech.tablesaw.api.DoubleColumn;
+import tech.tablesaw.api.FloatColumn;
+import tech.tablesaw.api.IntColumn;
+import tech.tablesaw.api.LongColumn;
+import tech.tablesaw.api.ShortColumn;
+import tech.tablesaw.api.Table;
+import tech.tablesaw.columns.Column;
+
 /**
  * Creates a Relation from the result of a SQL query, by passing the jdbc resultset to the constructor
  */
@@ -89,8 +95,43 @@ public class SqlResultSetReader {
         // Setup the columns and add to the table
         for (int i = 1; i <= metaData.getColumnCount(); i++) {
             String name = metaData.getColumnName(i);
-
-            ColumnType type = SQL_TYPE_TO_TABLESAW_TYPE.get(metaData.getColumnType(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:
+
+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 = ColumnType.SHORT;
+                    } 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);
 
@@ -102,7 +143,19 @@ public class SqlResultSetReader {
         while (resultSet.next()) {
             for (int i = 1; i <= metaData.getColumnCount(); i++) {
                 Column<?> column = table.column(i - 1); // subtract 1 because results sets originate at 1 not 0
-                column.appendObj(resultSet.getObject(i));
+                if (column instanceof ShortColumn) {
+                    column.appendObj(resultSet.getObject(i, Short.class));
+                } else if (column instanceof IntColumn) {
+                    column.appendObj(resultSet.getObject(i, Integer.class));
+                } else if (column instanceof LongColumn) {
+                    column.appendObj(resultSet.getObject(i, Long.class));
+                } else if (column instanceof FloatColumn) {
+                    column.appendObj(resultSet.getObject(i, Float.class));
+                } else if (column instanceof DoubleColumn) {
+                    column.appendObj(resultSet.getObject(i, Double.class));
+                } else {
+                    column.appendObj(resultSet.getObject(i));
+                }
             }
         }
         return table;
diff --git a/jsplot/pom.xml b/jsplot/pom.xml
index b86056fa..b3fb7ba7 100644
--- a/jsplot/pom.xml
+++ b/jsplot/pom.xml
@@ -5,7 +5,7 @@
     <parent>
         <groupId>tech.tablesaw</groupId>
         <artifactId>tablesaw-parent</artifactId>
-        <version>0.30.1-SNAPSHOT</version>
+        <version>0.30.2-SNAPSHOT</version>
     </parent>
 
     <artifactId>tablesaw-jsplot</artifactId>
@@ -59,7 +59,7 @@
         <dependency>
             <groupId>tech.tablesaw</groupId>
             <artifactId>tablesaw-core</artifactId>
-            <version>0.30.1-SNAPSHOT</version>
+            <version>0.30.2-SNAPSHOT</version>
         </dependency>
         <dependency>
             <groupId>junit</groupId>
diff --git a/pom.xml b/pom.xml
index 381101f0..d2b4b46d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
 
     <groupId>tech.tablesaw</groupId>
     <artifactId>tablesaw-parent</artifactId>
-    <version>0.30.1-SNAPSHOT</version>
+    <version>0.30.2-SNAPSHOT</version>
     <name>Tablesaw</name>
     <description>High-performance Java Dataframe</description>
     <url>https://github.com/jtablesaw/tablesaw</url>


Test patch:
diff --git a/core/src/test/java/tech/tablesaw/api/StringColumnTest.java b/core/src/test/java/tech/tablesaw/api/StringColumnTest.java
index c08f1ac2..85e91062 100644
--- a/core/src/test/java/tech/tablesaw/api/StringColumnTest.java
+++ b/core/src/test/java/tech/tablesaw/api/StringColumnTest.java
@@ -59,6 +59,17 @@ TODO: fix
         assertArrayEquals(sc.asList().toArray(), sc.asObjectArray());
     }
 
+    @Test
+    public void testForNulls() {
+        String[] array1 = {"1", "2", "3", "4", null};
+        Table table1 = Table.create("table1", StringColumn.create("id", array1));
+        assertEquals("", table1.stringColumn("id").get(4));
+
+        String[] array2 = {"1", "2", null, "", "5"};
+        Table table2 = Table.create("table2", StringColumn.create("id", array2));
+        assertEquals("", table2.stringColumn("id").get(3));
+    }
+
     @Test
     public void testAppendObj() {
         StringColumn column = StringColumn.create("testing");
diff --git a/core/src/test/java/tech/tablesaw/columns/ColumnTest.java b/core/src/test/java/tech/tablesaw/columns/ColumnTest.java
index 4d34e516..47b53b34 100644
--- a/core/src/test/java/tech/tablesaw/columns/ColumnTest.java
+++ b/core/src/test/java/tech/tablesaw/columns/ColumnTest.java
@@ -18,12 +18,14 @@ import org.junit.Before;
 import org.junit.Test;
 import tech.tablesaw.api.ColumnType;
 import tech.tablesaw.api.DateColumn;
+import tech.tablesaw.api.DateTimeColumn;
 import tech.tablesaw.api.DoubleColumn;
 import tech.tablesaw.api.StringColumn;
 import tech.tablesaw.api.Table;
 import tech.tablesaw.io.csv.CsvReadOptions;
 
 import java.time.LocalDate;
+import java.time.LocalDateTime;
 import java.util.List;
 import java.util.function.BinaryOperator;
 import java.util.function.Function;
@@ -46,6 +48,7 @@ public class ColumnTest {
     private static final Predicate<Double> isPositiveOrZero = d -> d >= 0, isNegative = isPositiveOrZero.negate();
     private static final Function<Double, String> toString = Object::toString;
     private static final Function<Double, Double> negate = d -> -d;
+    private static final Function<LocalDateTime, String> toSeason = d -> getSeason(d.toLocalDate());
 
     private Table table;
 
@@ -148,7 +151,7 @@ public class ColumnTest {
         assertTrue(dc3.contains(0.0));
         assertTrue(dc3.contains(3.0));
     }
-    
+
     // Functional methods
 
     @Test
@@ -176,27 +179,52 @@ public class ColumnTest {
         assertTrue(DoubleColumn.create("t1", new double[] {-1, 0, -1}).anyMatch(isPositiveOrZero));
         assertFalse(DoubleColumn.create("t1", new double[] {0, 1, 2}).anyMatch(isNegative));
     }
-    
+
     @Test
     public void noneMatch() {
         assertTrue(DoubleColumn.create("t1", new double[] {0, 1, 2}).noneMatch(isNegative));
         assertFalse(DoubleColumn.create("t1", new double[] {-1, 0, 1}).noneMatch(isNegative));
         assertFalse(DoubleColumn.create("t1", new double[] {1, 0, -1}).noneMatch(isNegative));
     }
-    
+
     private <T> void check(Column<T> column, @SuppressWarnings("unchecked") T... ts) {
         assertEquals(ts.length, column.size());
         for (int i = 0; i < ts.length; i++) {
             assertEquals(ts[i], column.get(i));
         }
     }
-    
+
     @Test
     public void testFilter() {
         Column<Double> filtered = DoubleColumn.create("t1", new double[] {-1, 0, 1}).filter(isPositiveOrZero);
         check(filtered, 0.0, 1.0);
     }
 
+    static String getSeason(LocalDate date) {
+        String season = "";
+        int month = date.getMonthValue();
+        int day = date.getDayOfMonth();
+
+        if ( month == 1 || month == 2 
+                || ( month == 3 && day <= 15 )
+                || ( month == 12 && day >= 16 ))
+            season = "WINTER";
+        else if ( month == 4 || month == 5 
+                || ( month == 3 && day >= 16 )
+                || ( month == 6 && day <= 15 ))
+            season = "SPRING";
+        else if ( month == 7 || month == 8
+                || ( month == 6 && day >= 16 )
+                || ( month == 9 && day <= 15 ))
+            season = "SUMMER";
+        else if ( month == 10|| month == 11
+                || ( month == 9 && day >= 16 )
+                || ( month == 12 && day <= 15 ))
+            season = "FALL";
+        
+        return season;
+    }
+
     @Test
     public void testMapInto() {
         String[] strings = new String[] {"-1.0", "0.0", "1.0"};
@@ -205,12 +233,26 @@ public class ColumnTest {
                 (StringColumn) doubleColumn.mapInto(toString, StringColumn.create("T", doubleColumn.size()));
         check(stringColumn1, strings);
     }
-    
+
+    @Test
+    public void testMapIntoSeason() {
+            String[] strings = new String[] {"WINTER", "SPRING", "SUMMER"};
+            DateTimeColumn dateColumn = DateTimeColumn.create("Date", new LocalDateTime[] {
+                            LocalDateTime.of(2018, 1, 26, 12, 15),
+                            LocalDateTime.of(2018, 5, 31, 10, 38),
+                            LocalDateTime.of(2018, 9, 2, 21, 42)
+            });
+            StringColumn stringColumn1 =
+                            (StringColumn) dateColumn.mapInto(toSeason, 
+                                            StringColumn.create("Season", dateColumn.size()));
+            check(stringColumn1, strings);
+    }
+
     @Test
     public void testMap() {
         check(DoubleColumn.create("t1", new double[] {-1, 0, 1}).map(negate), 1.0, -0.0, -1.0);
     }
-    
+
     @Test
     public void testMaxComparator() {
         assertEquals(Double.valueOf(1.0), DoubleColumn.create("t1", new double[] {-1, 0, 1}).max(Double::compare).get());
@@ -222,20 +264,21 @@ public class ColumnTest {
         assertEquals(Double.valueOf(-1.0), DoubleColumn.create("t1", new double[] {-1, 0, 1}).min(Double::compare).get());
         assertFalse(DoubleColumn.create("t1").min((d1, d2) -> (int) (d1 - d2)).isPresent());
     }
-   
+
     @Test
     public void testReduceTBinaryOperator() {
         assertEquals(Double.valueOf(1.0), DoubleColumn.create("t1", new double[] {-1, 0, 1}).reduce(1.0, sum));
     }
-    
+
     @Test
     public void testReduceBinaryOperator() {
         assertEquals(Double.valueOf(0.0), DoubleColumn.create("t1", new double[] {-1, 0, 1}).reduce(sum).get());
         assertFalse(DoubleColumn.create("t1", new double[] {}).reduce(sum).isPresent());
     }
-    
+
     @Test
     public void sorted() {
         check(DoubleColumn.create("t1", new double[] {1, -1, 0}).sorted(Double::compare), -1.0, 0.0, 1.0);
     }
+
 }
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 89b6251d..13e0f0d3 100644
--- a/core/src/test/java/tech/tablesaw/io/jdbc/SqlResultSetReaderTest.java
+++ b/core/src/test/java/tech/tablesaw/io/jdbc/SqlResultSetReaderTest.java
@@ -14,16 +14,23 @@
 
 package tech.tablesaw.io.jdbc;
 
-import org.junit.Assert;
-import org.junit.Test;
-import tech.tablesaw.api.Table;
-import tech.tablesaw.util.TestDb;
-
 import java.sql.Connection;
 import java.sql.DriverManager;
 import java.sql.ResultSet;
 import java.sql.Statement;
 
+import org.junit.Assert;
+import org.junit.Test;
+
+import tech.tablesaw.api.Table;
+import tech.tablesaw.columns.numbers.DoubleColumnType;
+import tech.tablesaw.columns.numbers.FloatColumnType;
+import tech.tablesaw.columns.numbers.IntColumnType;
+import tech.tablesaw.columns.numbers.LongColumnType;
+import tech.tablesaw.columns.numbers.ShortColumnType;
+import tech.tablesaw.columns.strings.StringColumnType;
+import tech.tablesaw.util.TestDb;
+
 /**
  * Tests for creating Tables from JDBC result sets using SqlResutSetReader
  */
@@ -51,8 +58,12 @@ public class SqlResultSetReaderTest {
         // Build the UnpaidInvoice table.
         TestDb.buildUnpaidOrderTable(conn);
 
+        // Build the OracleNumbers table.
+        TestDb.buildNumbersTable(conn);
+        
         try (Statement stmt = conn.createStatement()) {
             String sql;
+
             sql = "SELECT * FROM coffee";
             try (ResultSet rs = stmt.executeQuery(sql)) {
                 Table coffee = SqlResultSetReader.read(rs, "Coffee");
@@ -63,7 +74,7 @@ public class SqlResultSetReaderTest {
             sql = "SELECT * FROM Customer";
             try (ResultSet rs = stmt.executeQuery(sql)) {
                 Table customer = SqlResultSetReader.read(rs, "Customer");
-                Assert.assertEquals(6, customer.columnCount());
+                Assert.assertEquals(7, customer.columnCount());
                 Assert.assertEquals(3, customer.rowCount());
             }
 
@@ -73,6 +84,26 @@ public class SqlResultSetReaderTest {
                 Assert.assertEquals(5, unpaidInvoice.columnCount());
                 Assert.assertEquals(0, unpaidInvoice.rowCount());
             }
+
+            sql = "SELECT * FROM Numbers";
+            try (ResultSet rs = stmt.executeQuery(sql)) {
+                Table numbers = SqlResultSetReader.read(rs, "Numbers");
+                Assert.assertEquals(13, numbers.columnCount());
+                Assert.assertEquals(3, numbers.rowCount());
+                Assert.assertTrue(numbers.column("Description").type() instanceof StringColumnType);
+                Assert.assertTrue(numbers.column("NumInt").type() instanceof IntColumnType);
+                Assert.assertTrue(numbers.column("NumInt6_0").type() instanceof IntColumnType);
+                Assert.assertTrue(numbers.column("NumLong").type() instanceof LongColumnType);
+                Assert.assertTrue(numbers.column("NumShort").type() instanceof ShortColumnType);
+                Assert.assertTrue(numbers.column("NumNumber").type() instanceof DoubleColumnType);
+                Assert.assertTrue(numbers.column("NumBigInt").type() instanceof DoubleColumnType);
+                Assert.assertTrue(numbers.column("NumBigDec").type() instanceof DoubleColumnType);
+                Assert.assertTrue(numbers.column("NumFloat7_1").type() instanceof FloatColumnType);
+                Assert.assertTrue(numbers.column("NumFloat7_7").type() instanceof FloatColumnType);
+                Assert.assertTrue(numbers.column("NumDouble7_8").type() instanceof DoubleColumnType);
+                Assert.assertTrue(numbers.column("NumDouble7_16").type() instanceof DoubleColumnType);
+            }
+
         }
     }
 }
\ No newline at end of file
diff --git a/core/src/test/java/tech/tablesaw/joining/DataFrameJoinerTest.java b/core/src/test/java/tech/tablesaw/joining/DataFrameJoinerTest.java
index ab26b529..85eff58a 100644
--- a/core/src/test/java/tech/tablesaw/joining/DataFrameJoinerTest.java
+++ b/core/src/test/java/tech/tablesaw/joining/DataFrameJoinerTest.java
@@ -357,21 +357,17 @@ public class DataFrameJoinerTest {
     }
 
     @Test
-    public void innerJoinWithDoubleBirdsCatsFishException() {
-        try {
-            DOUBLE_INDEXED_BIRDS.join("ID").inner(DOUBLE_INDEXED_CATS, DOUBLE_INDEXED_FISH);
-        } catch (IllegalArgumentException e) {
-            assertTrue(e.getMessage().contains("Joining is supported on integral, string, and date-like columns."));
-        }
+    public void innerJoinWithDoubleBirdsCatsFishDouble() {
+    	Table joined = DOUBLE_INDEXED_BIRDS.join("ID").inner(DOUBLE_INDEXED_CATS, DOUBLE_INDEXED_FISH);
+    	assertEquals(4, joined.columnCount());
+    	assertEquals(1, joined.rowCount());
     }
 
     @Test
-    public void innerJoinWithDoubleDogsCatsBirdsException() {
-        try {
-            DOUBLE_INDEXED_FISH.join("ID").inner(DOUBLE_INDEXED_CATS, DOUBLE_INDEXED_BIRDS);
-        } catch (ClassCastException e) {
-            assertTrue(e.getMessage().contains("FloatColumn cannot be cast to tech.tablesaw.api.ShortColumn"));
-        }
+    public void innerJoinWithDoubleDogsCatsBirdsDouble() {
+    	Table joined = DOUBLE_INDEXED_FISH.join("ID").inner(DOUBLE_INDEXED_CATS, DOUBLE_INDEXED_BIRDS);
+    	assertEquals(4, joined.columnCount());
+    	assertEquals(1, joined.rowCount());
     }
 
     @Test
@@ -1052,19 +1048,6 @@ public class DataFrameJoinerTest {
         assertEquals(1, joined.rowCount());
     }
 
-    @Test
-    public void innerJoinFootballSoccerOnHomeGameException() {
-        Table table1 = createFOOTBALLSCHEDULEDateTime();
-        Table table2 = createSOCCERSCHEDULEDateTime();
-        try {
-            Table joined = table1.join("HomeGame")
-                    .inner(true, table2);
-            assertEquals(9, joined.columnCount());
-        } catch (IllegalStateException e) {
-            assertTrue(e.getMessage().contains("Column HomeGame does not exist in table SoccerSchedule2"));
-        }
-    }
-
     @Test
     public void fullOuterJoinFootballSoccerOnPlayDateTimeSeasonRevenue() {
         Table table1 = createFOOTBALLSCHEDULEDateTime();
@@ -1120,14 +1103,11 @@ public class DataFrameJoinerTest {
     }
 
     @Test
-    public void fullOuterJoinFootballBaseballException() {
+    public void fullOuterJoinFootballBaseballBoolean() {
         Table table1 = createFOOTBALLSCHEDULE();
         Table table2 = createBASEBALLSCHEDULEDateTime();
-        try {
-            table1.join("HomeGame")
-                .fullOuter(true, table2);
-        } catch (IllegalArgumentException e) {
-            assertTrue(e.getMessage().contains("Joining is supported on integral, string, and date-like columns."));
-        }
+        Table joined = table1.join("HomeGame").fullOuter(true, table2);
+        assertEquals(10, joined.columnCount());
+        assertEquals(8, joined.rowCount());
     }
 }
diff --git a/core/src/test/java/tech/tablesaw/util/DoubleArraysTest.java b/core/src/test/java/tech/tablesaw/util/DoubleArraysTest.java
index 5798ed10..557fa00e 100644
--- a/core/src/test/java/tech/tablesaw/util/DoubleArraysTest.java
+++ b/core/src/test/java/tech/tablesaw/util/DoubleArraysTest.java
@@ -14,15 +14,14 @@
 
 package tech.tablesaw.util;
 
-import static org.junit.Assert.assertTrue;
-
-import java.util.Arrays;
-
 import org.junit.Test;
-
 import tech.tablesaw.api.Table;
 import tech.tablesaw.table.TableSliceGroup;
 
+import java.util.Arrays;
+
+import static org.junit.Assert.assertTrue;
+
 public class DoubleArraysTest {
 
     @Test
diff --git a/core/src/test/java/tech/tablesaw/util/TestDb.java b/core/src/test/java/tech/tablesaw/util/TestDb.java
index dae110ac..23d443d9 100644
--- a/core/src/test/java/tech/tablesaw/util/TestDb.java
+++ b/core/src/test/java/tech/tablesaw/util/TestDb.java
@@ -50,6 +50,9 @@ public class TestDb {
             // Build the UnpaidInvoice table.
             buildUnpaidOrderTable(conn);
 
+            // Build the OracleNumbers table.
+            buildNumbersTable(conn);
+            
             // Close the connection.
             conn.close();
         } catch (Exception e) {
@@ -91,6 +94,13 @@ public class TestDb {
                 // No need to report an error.
                 // The table simply did not exist.
             }
+            try {
+                // Drop the OracleNumbers table.
+                stmt.execute("DROP TABLE OracleNumbers");
+            } catch (SQLException ex) {
+                // No need to report an error.
+                // The table simply did not exist.
+            }
         } catch (SQLException ex) {
             System.out.println("ERROR: " + ex.getMessage());
             ex.printStackTrace();
@@ -257,6 +267,7 @@ public class TestDb {
             stmt.execute("CREATE TABLE Customer" +
                     "( CustomerNumber CHAR(10) NOT NULL PRIMARY KEY, " +
                     "  Name CHAR(25)," +
+                    "  RegistrationDate DATE," +
                     "  Address CHAR(25)," +
                     "  City CHAR(12)," +
                     "  State CHAR(2)," +
@@ -264,16 +275,16 @@ public class TestDb {
 
             // Add some rows to the new table.
             stmt.executeUpdate("INSERT INTO Customer VALUES" +
-                    "('101', 'Downtown Cafe', '17 N. Main Street'," +
+                    "('101', 'Downtown Cafe', '2004-01-29', '17 N. Main Street'," +
                     " 'Asheville', 'NC', '55515')");
 
             stmt.executeUpdate("INSERT INTO Customer VALUES" +
-                    "('102', 'Main Street Grocery'," +
+                    "('102', 'Main Street Grocery', '2005-02-10'," +
                     " '110 E. Main Street'," +
                     " 'Canton', 'NC', '55555')");
 
             stmt.executeUpdate("INSERT INTO Customer VALUES" +
-                    "('103', 'The Coffee Place', '101 Center Plaza'," +
+                    "('103', 'The Coffee Place', '2006-08-31', '101 Center Plaza'," +
                     " 'Waynesville', 'NC', '55516')");
         } catch (SQLException ex) {
             System.out.println("ERROR: " + ex.getMessage());
@@ -301,4 +312,83 @@ public class TestDb {
             System.out.println("ERROR: " + ex.getMessage());
         }
     }
+
+    /**
+     * The buildNumbersTable method creates the
+     * Numbers table and adds some rows to it.
+     */
+    public static void buildNumbersTable(Connection conn) {
+        try {
+            // Get a Statement object.
+            Statement stmt = conn.createStatement();
+            // Create the table.
+            stmt.execute("CREATE TABLE Numbers (" +
+                    "Description CHAR(25), " +
+                    "NumInt NUMBER(9), " +
+                    "NumInt6_0 NUMBER(6,0), " +
+                    "NumLong NUMBER(10), " +
+                    "NumShort NUMBER(4), " +
+                    "NumNumber NUMBER(38), " +
+                    "NumBigInt NUMBER(38), " +
+                    "NumBigDec NUMBER(38), " +
+                    "NumFloat NUMBER(19,4), " +
+                    "NumFloat7_1 NUMBER(7,1), " +
+                    "NumFloat7_7 NUMBER(12,7), " +
+                    "NumDouble7_8 NUMBER(13,8), " +
+                    "NumDouble7_16 NUMBER(21,16)" +
+                    ")");
+
+            // Insert row #1.
+            stmt.execute("INSERT INTO Numbers VALUES ( " +
+                    "'RowOne', " +
+                    "99999, " +
+                    "999999, " +
+                    "2000000000, " +
+                    "5555, " +
+                    "111111111133333333334444444444, " +
+                    "555555555566666666667777777777, " +
+                    "888888888899999999990000000000, " +
+                    "911222333444555.6677, " +
+                    "77777.1, " +
+                    "77777.1234567, " +
+                    "77777.12345678, " +
+                    "77777.1234567890123456)");
+
+            // Insert row #2.
+            stmt.execute("INSERT INTO Numbers VALUES ( " +
+                    "'RowTwo', " +
+                    "89999, " +
+                    "900001, " +
+                    "3000000000, " +
+                    "4555, " +
+                    "911111111133333333334444444444, " +
+                    "455555555566666666667777777777, " +
+                    "788888888899999999990000000000, " +
+                    "911222333444555.6667, " +
+                    "67777.1, " +
+                    "67777.1234567, " +
+                    "67777.12345678, " +
+                    "67777.1234567890123456)");
+
+            // Insert row #3.
+            stmt.execute("INSERT INTO Numbers VALUES ( " +
+                    "'RowThree', " +
+                    "79999, " +
+                    "800001, " +
+                    "2000000000, " +
+                    "3555, " +
+                    "811111111133333333334444444444, " +
+                    "355555555566666666667777777777, " +
+                    "688888888899999999990000000000, " +
+                    "811222333444555.6667, " +
+                    "57777.1, " +
+                    "57777.1234567, " +
+                    "57777.12345678, " +
+                    "57777.1234567890123456)");
+        } catch (SQLException ex) {
+            System.out.println("ERROR: " + ex.getMessage());
+        }
+    }
+
+
 }
\ No newline at end of file