[CALCITE-4752] PreparedStatement#SetObject() fails for BigDecimal values
diff --git a/core/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java b/core/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
index 0f00fd2..4c5ed11 100644
--- a/core/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
+++ b/core/src/main/java/org/apache/calcite/avatica/ColumnMetaData.java
@@ -26,6 +26,7 @@
 import com.google.protobuf.Descriptors.FieldDescriptor;
 
 import java.lang.reflect.Type;
+import java.math.BigDecimal;
 import java.sql.Array;
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
@@ -341,7 +342,7 @@
 
     /** Values are represented as some sub-class of {@link Number}.
      * The JSON encoding does this. */
-    NUMBER(Number.class, Types.NUMERIC),
+    NUMBER(BigDecimal.class, Types.NUMERIC),
 
     ARRAY(Array.class, Types.ARRAY),
     MULTISET(List.class, Types.JAVA_OBJECT),
diff --git a/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java b/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
index bdb7d5f..6b1858e 100644
--- a/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
+++ b/core/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
@@ -118,7 +118,7 @@
     case Types.DOUBLE:
       return new DoubleAccessor(getter);
     case Types.DECIMAL:
-      return new BigDecimalAccessor(getter);
+      return new NumberAccessor(getter, columnMetaData.scale);
     case Types.CHAR:
       switch (columnMetaData.type.rep) {
       case PRIMITIVE_CHAR:
@@ -681,30 +681,9 @@
   }
 
   /**
-   * Accessor that assumes that the underlying value is a {@link BigDecimal};
-   * corresponds to {@link java.sql.Types#DECIMAL}.
-   */
-  private static class BigDecimalAccessor extends BigNumberAccessor {
-    private BigDecimalAccessor(Getter getter) {
-      super(getter);
-    }
-
-    protected Number getNumber() throws SQLException {
-      return (Number) getObject();
-    }
-
-    public BigDecimal getBigDecimal(int scale) throws SQLException {
-      return (BigDecimal) getObject();
-    }
-
-    public BigDecimal getBigDecimal() throws SQLException {
-      return (BigDecimal) getObject();
-    }
-  }
-
-  /**
    * Accessor that assumes that the underlying value is a {@link Number};
-   * corresponds to {@link java.sql.Types#NUMERIC}.
+   * corresponds to {@link java.sql.Types#NUMERIC}
+   * or {@link java.sql.Types#DECIMAL}.
    *
    * <p>This is useful when numbers have been translated over JSON. JSON
    * converts a 0L (0 long) value to the string "0" and back to 0 (0 int).
@@ -722,14 +701,20 @@
       return (Number) super.getObject();
     }
 
+    //FIXME There are several issues with this, the code below simply implements
+    //a previous behaviour codified by the Calcite test suite.
+    //
+    // 1. It interprets a scale of 0 as a NOOP parameter, it should in fact drop all fractionals
+    // 2. The scale from MetaData is NOT applied to BigDecimal values. Why ?
+    // 3. Metadata scale is only applied for getBigDecimal(), and only in this Accessor. Why ?
     public BigDecimal getBigDecimal(int scale) throws SQLException {
       Number n = getNumber();
       if (n == null) {
         return null;
       }
       BigDecimal decimal = AvaticaSite.toBigDecimal(n);
-      if (0 != scale) {
-        return decimal.setScale(scale, RoundingMode.UNNECESSARY);
+      if (0 != scale && !(n instanceof BigDecimal)) {
+        return decimal.setScale(scale, RoundingMode.DOWN);
       }
       return decimal;
     }
@@ -737,6 +722,7 @@
     public BigDecimal getBigDecimal() throws SQLException {
       return getBigDecimal(scale);
     }
+
   }
 
   /**
diff --git a/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java b/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
index c35e5a1..be657f0 100644
--- a/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
+++ b/server/src/test/java/org/apache/calcite/avatica/remote/RemoteMetaTest.java
@@ -47,6 +47,7 @@
 import java.io.InputStream;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.math.BigDecimal;
 import java.net.HttpURLConnection;
 import java.net.InetAddress;
 import java.net.URL;
@@ -59,6 +60,7 @@
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.Statement;
+import java.sql.Types;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.List;
@@ -734,6 +736,65 @@
       ConnectionSpec.getDatabaseLock().unlock();
     }
   }
+
+  @Test public void testBigDecimalTest() throws Exception {
+    final String tableName = "testbigdecimal";
+    try (Connection conn = DriverManager.getConnection(url);
+          Statement stmt = conn.createStatement()) {
+      conn.setAutoCommit(false);
+      stmt.execute("DROP TABLE IF EXISTS " + tableName);
+      stmt.execute("CREATE TABLE " + tableName + " ("
+          + "pk VARCHAR NOT NULL PRIMARY KEY, "
+          + "v1 DECIMAL(10,5))");
+      conn.commit();
+      try (PreparedStatement pstmt = conn.prepareStatement("INSERT INTO "
+          + tableName + " values(?, ?)")) {
+        pstmt.setString(1, "1");
+        pstmt.setBigDecimal(2, new BigDecimal("12345.67890"));
+        assertEquals(1, pstmt.executeUpdate());
+
+        pstmt.setString(1, "2");
+        pstmt.setObject(2, new BigDecimal("12345.67891"));
+        assertEquals(1, pstmt.executeUpdate());
+
+        pstmt.setString(1, "3");
+        pstmt.setObject(2, new BigDecimal("12345.67892"), Types.NUMERIC);
+        assertEquals(1, pstmt.executeUpdate());
+
+        pstmt.setString(1, "4");
+        pstmt.setObject(2, new BigDecimal("4000"), Types.DECIMAL);
+        assertEquals(1, pstmt.executeUpdate());
+
+        pstmt.setString(1, "5");
+        pstmt.setLong(2, 4000L);
+        assertEquals(1, pstmt.executeUpdate());
+
+        conn.commit();
+
+        ResultSet rs = stmt.executeQuery("select v1 from " + tableName + " order by pk asc");
+        assertTrue(rs.next());
+        assertTrue((new BigDecimal("12345.67890")).compareTo(rs.getBigDecimal(1)) == 0);
+        assertEquals("12345.67890", rs.getString(1));
+        assertTrue(rs.next());
+        assertEquals(rs.getObject(1).getClass(), BigDecimal.class);
+        assertTrue((new BigDecimal("12345.67891")).compareTo((BigDecimal) rs.getObject(1)) == 0);
+        // Not implemeneted / throws error
+        //assertTrue((new BigDecimal("12345.67891")).compareTo(
+        //    (BigDecimal)rs.getObject(1, BigDecimal.class)) == 0);
+
+        assertTrue(rs.next());
+        // The build system makes it impossible to test deprecated APIs, but these also
+        // fail bacase of RoundingMode.Unneccessary in AbstractCursor#NumberAccessor.:
+        //assertTrue((new BigDecimal("12345.679")).compareTo(rs.getBigDecimal(1, 3)) == 0);
+        //assertTrue((new BigDecimal("12345.6789200")).compareTo(rs.getBigDecimal(1, 7)) == 0);
+
+        assertTrue(rs.next());
+        assertEquals("4000.00000", rs.getString(1));
+        assertEquals(4000L, rs.getLong(1));
+        assertEquals(4000, rs.getInt(1));
+      }
+    }
+  }
 }
 
 // End RemoteMetaTest.java