Enhance Clob,Blob support 64/89064/1
authorstatta <statta@research.att.com>
Fri, 31 May 2019 16:28:00 +0000 (12:28 -0400)
committerstatta <statta@research.att.com>
Fri, 31 May 2019 16:28:00 +0000 (12:28 -0400)
Issue-ID: MUSIC-388
Change-Id: Ib02df8239e5d7572470fa696697685bdc582cdbb
Signed-off-by: statta <statta@research.att.com>
mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java
mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java
mdbc-server/src/main/java/org/onap/music/mdbc/mixins/MySQLMixin.java

index 5fd4e69..2e7cdc0 100644 (file)
-/*\r
- * Licensed to the Apache Software Foundation (ASF) under one or more\r
- * contributor license agreements.  See the NOTICE file distributed with\r
- * this work for additional information regarding copyright ownership.\r
- * The ASF licenses this file to you under the Apache License, Version 2.0\r
- * (the "License"); you may not use this file except in compliance with\r
- * the License.  You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package org.apache.calcite.avatica;\r
-\r
-import org.apache.calcite.avatica.remote.TypedValue;\r
-import org.apache.calcite.avatica.util.Cursor;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.Reader;\r
-import java.math.BigDecimal;\r
-import java.math.BigInteger;\r
-import java.net.URL;\r
-import java.nio.charset.StandardCharsets;\r
-import java.sql.Array;\r
-import java.sql.Blob;\r
-import java.sql.Clob;\r
-import java.sql.Date;\r
-import java.sql.NClob;\r
-import java.sql.Ref;\r
-import java.sql.RowId;\r
-import java.sql.SQLException;\r
-import java.sql.SQLXML;\r
-import java.sql.Time;\r
-import java.sql.Timestamp;\r
-import java.sql.Types;\r
-import java.util.Calendar;\r
-\r
-/**\r
- * A location that a value can be written to or read from.\r
- */\r
-public class AvaticaSite {\r
-  final AvaticaParameter parameter;\r
-\r
-  /** Calendar is not thread-safe. But calendar is only used from within one\r
-   * thread, and we have to trust that clients are not modifying calendars\r
-   * that they pass to us in a method such as\r
-   * {@link java.sql.PreparedStatement#setTime(int, Time, Calendar)}, so we do\r
-   * not need to synchronize access. */\r
-  final Calendar calendar;\r
-  private final int index;\r
-  final TypedValue[] slots;\r
-\r
-  /** Value that means the parameter has been set to null.\r
-   * If value is null, parameter has not been set. */\r
-  public static final Object DUMMY_VALUE = Dummy.INSTANCE;\r
-\r
-  public AvaticaSite(AvaticaParameter parameter, Calendar calendar, int index,\r
-      TypedValue[] slots) {\r
-    assert calendar != null;\r
-    assert parameter != null;\r
-    assert slots != null;\r
-    this.parameter = parameter;\r
-    this.calendar = calendar;\r
-    this.index = index;\r
-    this.slots = slots;\r
-  }\r
-\r
-  private TypedValue wrap(ColumnMetaData.Rep rep, Object o,\r
-      Calendar calendar) {\r
-    return TypedValue.ofJdbc(rep, o, calendar);\r
-  }\r
-\r
-  private TypedValue wrap(ColumnMetaData.Rep rep, Object o) {\r
-    return TypedValue.ofJdbc(rep, o, calendar);\r
-  }\r
-\r
-  public boolean isSet(int index) {\r
-    return slots[index] != null;\r
-  }\r
-\r
-  public void setByte(byte o) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.BYTE, o);\r
-  }\r
-\r
-  public void setChar(char o) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.CHARACTER, o);\r
-  }\r
-\r
-  public void setShort(short o) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.SHORT, o);\r
-  }\r
-\r
-  public void setInt(int o) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.INTEGER, o);\r
-  }\r
-\r
-  public void setLong(long o) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.LONG, o);\r
-  }\r
-\r
-  public void setBoolean(boolean o) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.BOOLEAN, o);\r
-  }\r
-\r
-  public void setRowId(RowId x) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, x);\r
-  }\r
-\r
-  public void setNString(String o) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.STRING, o);\r
-  }\r
-\r
-  public void setNCharacterStream(Reader value, long length) {\r
-  }\r
-\r
-  public void setNClob(NClob value) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, value);\r
-  }\r
-\r
-  public void setClob(Reader reader, long length) {\r
-  }\r
-\r
-  public void setBlob(InputStream inputStream, long length) {\r
-  }\r
-\r
-  public void setNClob(Reader reader, long length) {\r
-  }\r
-\r
-  public void setSQLXML(SQLXML xmlObject) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, xmlObject);\r
-  }\r
-\r
-  public void setAsciiStream(InputStream x, long length) {\r
-  }\r
-\r
-  public void setBinaryStream(InputStream x, long length) {\r
-  }\r
-\r
-  public void setCharacterStream(Reader reader, long length) {\r
-  }\r
-\r
-  public void setAsciiStream(InputStream x) {\r
-  }\r
-\r
-  public void setBinaryStream(InputStream x) {\r
-  }\r
-\r
-  public void setCharacterStream(Reader reader) {\r
-  }\r
-\r
-  public void setNCharacterStream(Reader value) {\r
-  }\r
-\r
-  public void setClob(Reader reader) {\r
-  }\r
-  \r
-  public void setClob(InputStream inputStream) {\r
-  }\r
-\r
-  public void setBlob(InputStream inputStream) {\r
-  }\r
-\r
-  public void setNClob(Reader reader) {\r
-  }\r
-\r
-  public void setUnicodeStream(InputStream x, int length) {\r
-  }\r
-\r
-  public void setFloat(float x) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.FLOAT, x);\r
-  }\r
-\r
-  public void setDouble(double x) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.DOUBLE, x);\r
-  }\r
-\r
-  public void setBigDecimal(BigDecimal x) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.NUMBER, x);\r
-  }\r
-\r
-  public void setString(String x) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.STRING, x);\r
-  }\r
-\r
-  public void setBytes(byte[] x) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.BYTE_STRING, x);\r
-  }\r
-\r
-  public void setTimestamp(Timestamp x, Calendar calendar) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP, x, calendar);\r
-  }\r
-\r
-  public void setTime(Time x, Calendar calendar) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_TIME, x, calendar);\r
-  }\r
-\r
-  public void setDate(Date x, Calendar calendar) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_DATE, x, calendar);\r
-  }\r
-\r
-  public void setObject(Object x, int targetSqlType) {\r
-    if (x == null || Types.NULL == targetSqlType) {\r
-      setNull(targetSqlType);\r
-      return;\r
-    }\r
-    switch (targetSqlType) {\r
-    case Types.CLOB:\r
-       if (x instanceof Clob) {\r
-            setClob((Clob) x);\r
-            break;\r
-          } else if (x instanceof InputStream) {\r
-            setClob((InputStream) x);\r
-          }\r
-          throw unsupportedCast(x.getClass(), Blob.class);\r
-    case Types.DATALINK:\r
-    case Types.NCLOB:\r
-    case Types.OTHER:\r
-    case Types.REF:\r
-    case Types.SQLXML:\r
-    case Types.STRUCT:\r
-      throw notImplemented();\r
-    case Types.ARRAY:\r
-      setArray(toArray(x));\r
-      break;\r
-    case Types.BIGINT:\r
-      setLong(toLong(x));\r
-      break;\r
-    case Types.BINARY:\r
-    case Types.LONGVARBINARY:\r
-    case Types.VARBINARY:\r
-      setBytes(toBytes(x));\r
-      break;\r
-    case Types.BIT:\r
-    case Types.BOOLEAN:\r
-      setBoolean(toBoolean(x));\r
-      break;\r
-    case Types.BLOB:\r
-      if (x instanceof Blob) {\r
-        setBlob((Blob) x);\r
-        break;\r
-      } else if (x instanceof InputStream) {\r
-        setBlob((InputStream) x);\r
-      }\r
-      throw unsupportedCast(x.getClass(), Blob.class);\r
-    case Types.DATE:\r
-      setDate(toDate(x), calendar);\r
-      break;\r
-    case Types.DECIMAL:\r
-    case Types.NUMERIC:\r
-      setBigDecimal(toBigDecimal(x));\r
-      break;\r
-    case Types.DISTINCT:\r
-      throw notImplemented();\r
-    case Types.DOUBLE:\r
-    case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes\r
-      setDouble(toDouble(x));\r
-      break;\r
-    case Types.INTEGER:\r
-      setInt(toInt(x));\r
-      break;\r
-    case Types.JAVA_OBJECT:\r
-      setObject(x);\r
-      break;\r
-    case Types.LONGNVARCHAR:\r
-    case Types.LONGVARCHAR:\r
-    case Types.NVARCHAR:\r
-    case Types.VARCHAR:\r
-    case Types.CHAR:\r
-    case Types.NCHAR:\r
-      setString(toString(x));\r
-      break;\r
-    case Types.REAL:\r
-      setFloat(toFloat(x));\r
-      break;\r
-    case Types.ROWID:\r
-      if (x instanceof RowId) {\r
-        setRowId((RowId) x);\r
-        break;\r
-      }\r
-      throw unsupportedCast(x.getClass(), RowId.class);\r
-    case Types.SMALLINT:\r
-      setShort(toShort(x));\r
-      break;\r
-    case Types.TIME:\r
-      setTime(toTime(x), calendar);\r
-      break;\r
-    case Types.TIMESTAMP:\r
-      setTimestamp(toTimestamp(x), calendar);\r
-      break;\r
-    case Types.TINYINT:\r
-      setByte(toByte(x));\r
-      break;\r
-    default:\r
-      throw notImplemented();\r
-    }\r
-  }\r
-\r
-  /** Similar logic to {@link #setObject}. */\r
-  public static Object get(Cursor.Accessor accessor, int targetSqlType,\r
-      Calendar localCalendar) throws SQLException {\r
-    switch (targetSqlType) {\r
-    case Types.CLOB:\r
-        return accessor.getClob();\r
-    case Types.DATALINK:\r
-    case Types.NCLOB:\r
-    case Types.REF:\r
-    case Types.SQLXML:\r
-    case Types.STRUCT:\r
-      throw notImplemented();\r
-    case Types.ARRAY:\r
-      return accessor.getArray();\r
-    case Types.BIGINT:\r
-      final long aLong = accessor.getLong();\r
-      if (aLong == 0 && accessor.wasNull()) {\r
-        return null;\r
-      }\r
-      return aLong;\r
-    case Types.BINARY:\r
-    case Types.LONGVARBINARY:\r
-    case Types.VARBINARY:\r
-      return accessor.getBytes();\r
-    case Types.BIT:\r
-    case Types.BOOLEAN:\r
-      final boolean aBoolean = accessor.getBoolean();\r
-      if (!aBoolean && accessor.wasNull()) {\r
-        return null;\r
-      }\r
-      return aBoolean;\r
-    case Types.BLOB:\r
-      return accessor.getBlob();\r
-    case Types.DATE:\r
-      return accessor.getDate(localCalendar);\r
-    case Types.DECIMAL:\r
-    case Types.NUMERIC:\r
-      return accessor.getBigDecimal();\r
-    case Types.DISTINCT:\r
-      throw notImplemented();\r
-    case Types.DOUBLE:\r
-    case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes\r
-      final double aDouble = accessor.getDouble();\r
-      if (aDouble == 0 && accessor.wasNull()) {\r
-        return null;\r
-      }\r
-      return aDouble;\r
-    case Types.INTEGER:\r
-      final int anInt = accessor.getInt();\r
-      if (anInt == 0 && accessor.wasNull()) {\r
-        return null;\r
-      }\r
-      return anInt;\r
-    case Types.JAVA_OBJECT:\r
-    case Types.OTHER:\r
-      return accessor.getObject();\r
-    case Types.LONGNVARCHAR:\r
-    case Types.LONGVARCHAR:\r
-    case Types.NVARCHAR:\r
-    case Types.VARCHAR:\r
-    case Types.CHAR:\r
-    case Types.NCHAR:\r
-      return accessor.getString();\r
-    case Types.REAL:\r
-      final float aFloat = accessor.getFloat();\r
-      if (aFloat == 0 && accessor.wasNull()) {\r
-        return null;\r
-      }\r
-      return aFloat;\r
-    case Types.ROWID:\r
-      throw notImplemented();\r
-    case Types.SMALLINT:\r
-      final short aShort = accessor.getShort();\r
-      if (aShort == 0 && accessor.wasNull()) {\r
-        return null;\r
-      }\r
-      return aShort;\r
-    case Types.TIME:\r
-      return accessor.getTime(localCalendar);\r
-    case Types.TIMESTAMP:\r
-      return accessor.getTimestamp(localCalendar);\r
-    case Types.TINYINT:\r
-      final byte aByte = accessor.getByte();\r
-      if (aByte == 0 && accessor.wasNull()) {\r
-        return null;\r
-      }\r
-      return aByte;\r
-    default:\r
-      throw notImplemented();\r
-    }\r
-  }\r
-\r
-  public void setObject(Object x) {\r
-    slots[index] = TypedValue.ofJdbc(x, calendar);\r
-  }\r
-\r
-  public void setNull(int sqlType) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, null);\r
-  }\r
-\r
-  public void setRef(Ref x) {\r
-  }\r
-\r
-  public void setBlob(Blob x) {\r
-     InputStream iStream;\r
-    try {\r
-        iStream = x.getBinaryStream();\r
-        int length =0;\r
-        while(iStream.read() != -1)\r
-            length ++;\r
-         setBytes(x.getBytes(1, length));\r
-         \r
-    } catch (SQLException | IOException e) {\r
-        throw new RuntimeException(e);\r
-    }\r
-    \r
-  }\r
-\r
-  public void setClob(Clob x) {\r
-  }\r
-\r
-  public void setArray(Array x) {\r
-    slots[index] = wrap(ColumnMetaData.Rep.ARRAY, x);\r
-  }\r
-\r
-  public void setNull(int sqlType, String typeName) {\r
-  }\r
-\r
-  public void setURL(URL x) {\r
-  }\r
-\r
-  public void setObject(Object x, int targetSqlType,\r
-      int scaleOrLength) {\r
-  }\r
-\r
-  private static RuntimeException unsupportedCast(Class<?> from, Class<?> to) {\r
-    return new UnsupportedOperationException("Cannot convert from "\r
-        + from.getCanonicalName() + " to " + to.getCanonicalName());\r
-  }\r
-\r
-  private static RuntimeException notImplemented() {\r
-    return new RuntimeException("not implemented");\r
-  }\r
-\r
-  private static Array toArray(Object x) {\r
-    if (x instanceof Array) {\r
-      return (Array) x;\r
-    }\r
-    throw unsupportedCast(x.getClass(), Array.class);\r
-  }\r
-\r
-  public static BigDecimal toBigDecimal(Object x) {\r
-    if (x instanceof BigDecimal) {\r
-      return (BigDecimal) x;\r
-    } else if (x instanceof BigInteger) {\r
-      return new BigDecimal((BigInteger) x);\r
-    } else if (x instanceof Number) {\r
-      if (x instanceof Double || x instanceof Float) {\r
-        return new BigDecimal(((Number) x).doubleValue());\r
-      } else {\r
-        return new BigDecimal(((Number) x).longValue());\r
-      }\r
-    } else if (x instanceof Boolean) {\r
-      return (Boolean) x ? BigDecimal.ONE : BigDecimal.ZERO;\r
-    } else if (x instanceof String) {\r
-      return new BigDecimal((String) x);\r
-    }\r
-    throw unsupportedCast(x.getClass(), BigDecimal.class);\r
-  }\r
-\r
-  private static boolean toBoolean(Object x) {\r
-    if (x instanceof Boolean) {\r
-      return (Boolean) x;\r
-    } else if (x instanceof Number) {\r
-      return ((Number) x).intValue() != 0;\r
-    } else if (x instanceof String) {\r
-      String s = (String) x;\r
-      if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("yes")) {\r
-        return true;\r
-      } else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("no")) {\r
-        return false;\r
-      }\r
-    }\r
-    throw unsupportedCast(x.getClass(), Boolean.TYPE);\r
-  }\r
-\r
-  private static byte toByte(Object x) {\r
-    if (x instanceof Number) {\r
-      return ((Number) x).byteValue();\r
-    } else if (x instanceof Boolean) {\r
-      return (Boolean) x ? (byte) 1 : (byte) 0;\r
-    } else if (x instanceof String) {\r
-      return Byte.parseByte((String) x);\r
-    } else {\r
-      throw unsupportedCast(x.getClass(), Byte.TYPE);\r
-    }\r
-  }\r
-\r
-  private static byte[] toBytes(Object x) {\r
-    if (x instanceof byte[]) {\r
-      return (byte[]) x;\r
-    }\r
-    if (x instanceof String) {\r
-      return ((String) x).getBytes(StandardCharsets.UTF_8);\r
-    }\r
-    throw unsupportedCast(x.getClass(), byte[].class);\r
-  }\r
-\r
-  private static Date toDate(Object x) {\r
-    if (x instanceof String) {\r
-      return Date.valueOf((String) x);\r
-    }\r
-    return new Date(toLong(x));\r
-  }\r
-\r
-  private static Time toTime(Object x) {\r
-    if (x instanceof String) {\r
-      return Time.valueOf((String) x);\r
-    }\r
-    return new Time(toLong(x));\r
-  }\r
-\r
-  private static Timestamp toTimestamp(Object x) {\r
-    if (x instanceof String) {\r
-      return Timestamp.valueOf((String) x);\r
-    }\r
-    return new Timestamp(toLong(x));\r
-  }\r
-\r
-  private static double toDouble(Object x) {\r
-    if (x instanceof Number) {\r
-      return ((Number) x).doubleValue();\r
-    } else if (x instanceof Boolean) {\r
-      return (Boolean) x ? 1D : 0D;\r
-    } else if (x instanceof String) {\r
-      return Double.parseDouble((String) x);\r
-    } else {\r
-      throw unsupportedCast(x.getClass(), Double.TYPE);\r
-    }\r
-  }\r
-\r
-  private static float toFloat(Object x) {\r
-    if (x instanceof Number) {\r
-      return ((Number) x).floatValue();\r
-    } else if (x instanceof Boolean) {\r
-      return (Boolean) x ? 1F : 0F;\r
-    } else if (x instanceof String) {\r
-      return Float.parseFloat((String) x);\r
-    } else {\r
-      throw unsupportedCast(x.getClass(), Float.TYPE);\r
-    }\r
-  }\r
-\r
-  private static int toInt(Object x) {\r
-    if (x instanceof Number) {\r
-      return ((Number) x).intValue();\r
-    } else if (x instanceof Boolean) {\r
-      return (Boolean) x ? 1 : 0;\r
-    } else if (x instanceof String) {\r
-      return Integer.parseInt((String) x);\r
-    } else {\r
-      throw unsupportedCast(x.getClass(), Integer.TYPE);\r
-    }\r
-  }\r
-\r
-  private static long toLong(Object x) {\r
-    if (x instanceof Number) {\r
-      return ((Number) x).longValue();\r
-    } else if (x instanceof Boolean) {\r
-      return (Boolean) x ? 1L : 0L;\r
-    } else if (x instanceof String) {\r
-      return Long.parseLong((String) x);\r
-    } else {\r
-      throw unsupportedCast(x.getClass(), Long.TYPE);\r
-    }\r
-  }\r
-\r
-  private static short toShort(Object x) {\r
-    if (x instanceof Number) {\r
-      return ((Number) x).shortValue();\r
-    } else if (x instanceof Boolean) {\r
-      return (Boolean) x ? (short) 1 : (short) 0;\r
-    } else if (x instanceof String) {\r
-      return Short.parseShort((String) x);\r
-    } else {\r
-      throw unsupportedCast(x.getClass(), Short.TYPE);\r
-    }\r
-  }\r
-\r
-  private static String toString(Object x) {\r
-    if (x instanceof String) {\r
-      return (String) x;\r
-    } else if (x instanceof Character\r
-        || x instanceof Boolean) {\r
-      return x.toString();\r
-    }\r
-    throw unsupportedCast(x.getClass(), String.class);\r
-  }\r
-\r
-  /** Singleton value to denote parameters that have been set to null (as\r
-   * opposed to not set).\r
-   *\r
-   * <p>Not a valid value for a parameter.\r
-   *\r
-   * <p>As an enum, it is serializable by Jackson. */\r
-  private enum Dummy {\r
-    INSTANCE\r
-  }\r
-}\r
-\r
-// End AvaticaSite.java\r
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.calcite.avatica;
+
+import org.apache.calcite.avatica.remote.TypedValue;
+import org.apache.calcite.avatica.util.Cursor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Date;
+import java.sql.NClob;
+import java.sql.Ref;
+import java.sql.RowId;
+import java.sql.SQLException;
+import java.sql.SQLXML;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Calendar;
+
+/**
+ * A location that a value can be written to or read from.
+ */
+public class AvaticaSite {
+  final AvaticaParameter parameter;
+
+  /** Calendar is not thread-safe. But calendar is only used from within one
+   * thread, and we have to trust that clients are not modifying calendars
+   * that they pass to us in a method such as
+   * {@link java.sql.PreparedStatement#setTime(int, Time, Calendar)}, so we do
+   * not need to synchronize access. */
+  final Calendar calendar;
+  private final int index;
+  final TypedValue[] slots;
+
+  /** Value that means the parameter has been set to null.
+   * If value is null, parameter has not been set. */
+  public static final Object DUMMY_VALUE = Dummy.INSTANCE;
+
+  public AvaticaSite(AvaticaParameter parameter, Calendar calendar, int index,
+      TypedValue[] slots) {
+    assert calendar != null;
+    assert parameter != null;
+    assert slots != null;
+    this.parameter = parameter;
+    this.calendar = calendar;
+    this.index = index;
+    this.slots = slots;
+  }
+
+  private TypedValue wrap(ColumnMetaData.Rep rep, Object o,
+      Calendar calendar) {
+    return TypedValue.ofJdbc(rep, o, calendar);
+  }
+
+  private TypedValue wrap(ColumnMetaData.Rep rep, Object o) {
+    return TypedValue.ofJdbc(rep, o, calendar);
+  }
+
+  public boolean isSet(int index) {
+    return slots[index] != null;
+  }
+
+  public void setByte(byte o) {
+    slots[index] = wrap(ColumnMetaData.Rep.BYTE, o);
+  }
+
+  public void setChar(char o) {
+    slots[index] = wrap(ColumnMetaData.Rep.CHARACTER, o);
+  }
+
+  public void setShort(short o) {
+    slots[index] = wrap(ColumnMetaData.Rep.SHORT, o);
+  }
+
+  public void setInt(int o) {
+    slots[index] = wrap(ColumnMetaData.Rep.INTEGER, o);
+  }
+
+  public void setLong(long o) {
+    slots[index] = wrap(ColumnMetaData.Rep.LONG, o);
+  }
+
+  public void setBoolean(boolean o) {
+    slots[index] = wrap(ColumnMetaData.Rep.BOOLEAN, o);
+  }
+
+  public void setRowId(RowId x) {
+    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, x);
+  }
+
+  public void setNString(String o) {
+    slots[index] = wrap(ColumnMetaData.Rep.STRING, o);
+  }
+
+  public void setNCharacterStream(Reader value, long length) {
+  }
+
+  public void setNClob(NClob value) {
+    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, value);
+  }
+
+  public void setClob(Reader reader, long length) {
+  }
+
+  public void setBlob(InputStream inputStream, long length) {
+  }
+
+  public void setNClob(Reader reader, long length) {
+  }
+
+  public void setSQLXML(SQLXML xmlObject) {
+    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, xmlObject);
+  }
+
+  public void setAsciiStream(InputStream x, long length) {
+  }
+
+  public void setBinaryStream(InputStream x, long length) {
+  }
+
+  public void setCharacterStream(Reader reader, long length) {
+  }
+
+  public void setAsciiStream(InputStream x) {
+  }
+
+  public void setBinaryStream(InputStream x) {
+  }
+
+  public void setCharacterStream(Reader reader) {
+  }
+
+  public void setNCharacterStream(Reader value) {
+  }
+
+  public void setClob(Reader reader) {
+  }
+  
+  public void setClob(InputStream inputStream) {
+  }
+
+  public void setBlob(InputStream inputStream) {
+  }
+
+  public void setNClob(Reader reader) {
+  }
+
+  public void setUnicodeStream(InputStream x, int length) {
+  }
+
+  public void setFloat(float x) {
+    slots[index] = wrap(ColumnMetaData.Rep.FLOAT, x);
+  }
+
+  public void setDouble(double x) {
+    slots[index] = wrap(ColumnMetaData.Rep.DOUBLE, x);
+  }
+
+  public void setBigDecimal(BigDecimal x) {
+    slots[index] = wrap(ColumnMetaData.Rep.NUMBER, x);
+  }
+
+  public void setString(String x) {
+    slots[index] = wrap(ColumnMetaData.Rep.STRING, x);
+  }
+
+  public void setBytes(byte[] x) {
+    slots[index] = wrap(ColumnMetaData.Rep.BYTE_STRING, x);
+  }
+
+  public void setTimestamp(Timestamp x, Calendar calendar) {
+    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_TIMESTAMP, x, calendar);
+  }
+
+  public void setTime(Time x, Calendar calendar) {
+    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_TIME, x, calendar);
+  }
+
+  public void setDate(Date x, Calendar calendar) {
+    slots[index] = wrap(ColumnMetaData.Rep.JAVA_SQL_DATE, x, calendar);
+  }
+
+  public void setObject(Object x, int targetSqlType) {
+    if (x == null || Types.NULL == targetSqlType) {
+      setNull(targetSqlType);
+      return;
+    }
+    switch (targetSqlType) {
+    case Types.CLOB:
+       if (x instanceof Clob) {
+            setClob((Clob) x);
+            break;
+          } else if (x instanceof InputStream) {
+            setClob((InputStream) x);
+          }
+          throw unsupportedCast(x.getClass(), Blob.class);
+    case Types.DATALINK:
+    case Types.NCLOB:
+    case Types.OTHER:
+    case Types.REF:
+    case Types.SQLXML:
+    case Types.STRUCT:
+      throw notImplemented();
+    case Types.ARRAY:
+      setArray(toArray(x));
+      break;
+    case Types.BIGINT:
+      setLong(toLong(x));
+      break;
+    case Types.BINARY:
+    case Types.LONGVARBINARY:
+    case Types.VARBINARY:
+      setBytes(toBytes(x));
+      break;
+    case Types.BIT:
+    case Types.BOOLEAN:
+      setBoolean(toBoolean(x));
+      break;
+    case Types.BLOB:
+      if (x instanceof Blob) {
+        setBlob((Blob) x);
+        break;
+      } else if (x instanceof InputStream) {
+        setBlob((InputStream) x);
+      }
+      throw unsupportedCast(x.getClass(), Blob.class);
+    case Types.DATE:
+      setDate(toDate(x), calendar);
+      break;
+    case Types.DECIMAL:
+    case Types.NUMERIC:
+      setBigDecimal(toBigDecimal(x));
+      break;
+    case Types.DISTINCT:
+      throw notImplemented();
+    case Types.DOUBLE:
+    case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes
+      setDouble(toDouble(x));
+      break;
+    case Types.INTEGER:
+      setInt(toInt(x));
+      break;
+    case Types.JAVA_OBJECT:
+      setObject(x);
+      break;
+    case Types.LONGNVARCHAR:
+    case Types.LONGVARCHAR:
+    case Types.NVARCHAR:
+    case Types.VARCHAR:
+    case Types.CHAR:
+    case Types.NCHAR:
+      setString(toString(x));
+      break;
+    case Types.REAL:
+      setFloat(toFloat(x));
+      break;
+    case Types.ROWID:
+      if (x instanceof RowId) {
+        setRowId((RowId) x);
+        break;
+      }
+      throw unsupportedCast(x.getClass(), RowId.class);
+    case Types.SMALLINT:
+      setShort(toShort(x));
+      break;
+    case Types.TIME:
+      setTime(toTime(x), calendar);
+      break;
+    case Types.TIMESTAMP:
+      setTimestamp(toTimestamp(x), calendar);
+      break;
+    case Types.TINYINT:
+      setByte(toByte(x));
+      break;
+    default:
+      throw notImplemented();
+    }
+  }
+
+  /** Similar logic to {@link #setObject}. */
+  public static Object get(Cursor.Accessor accessor, int targetSqlType,
+      Calendar localCalendar) throws SQLException {
+    switch (targetSqlType) {
+    case Types.CLOB:
+        return accessor.getClob();
+    case Types.DATALINK:
+    case Types.NCLOB:
+    case Types.REF:
+    case Types.SQLXML:
+    case Types.STRUCT:
+      throw notImplemented();
+    case Types.ARRAY:
+      return accessor.getArray();
+    case Types.BIGINT:
+      final long aLong = accessor.getLong();
+      if (aLong == 0 && accessor.wasNull()) {
+        return null;
+      }
+      return aLong;
+    case Types.BINARY:
+    case Types.LONGVARBINARY:
+    case Types.VARBINARY:
+      return accessor.getBytes();
+    case Types.BIT:
+    case Types.BOOLEAN:
+      final boolean aBoolean = accessor.getBoolean();
+      if (!aBoolean && accessor.wasNull()) {
+        return null;
+      }
+      return aBoolean;
+    case Types.BLOB:
+      return accessor.getBlob();
+    case Types.DATE:
+      return accessor.getDate(localCalendar);
+    case Types.DECIMAL:
+    case Types.NUMERIC:
+      return accessor.getBigDecimal();
+    case Types.DISTINCT:
+      throw notImplemented();
+    case Types.DOUBLE:
+    case Types.FLOAT: // yes really; SQL FLOAT is up to 8 bytes
+      final double aDouble = accessor.getDouble();
+      if (aDouble == 0 && accessor.wasNull()) {
+        return null;
+      }
+      return aDouble;
+    case Types.INTEGER:
+      final int anInt = accessor.getInt();
+      if (anInt == 0 && accessor.wasNull()) {
+        return null;
+      }
+      return anInt;
+    case Types.JAVA_OBJECT:
+    case Types.OTHER:
+      return accessor.getObject();
+    case Types.LONGNVARCHAR:
+    case Types.LONGVARCHAR:
+    case Types.NVARCHAR:
+    case Types.VARCHAR:
+    case Types.CHAR:
+    case Types.NCHAR:
+      return accessor.getString();
+    case Types.REAL:
+      final float aFloat = accessor.getFloat();
+      if (aFloat == 0 && accessor.wasNull()) {
+        return null;
+      }
+      return aFloat;
+    case Types.ROWID:
+      throw notImplemented();
+    case Types.SMALLINT:
+      final short aShort = accessor.getShort();
+      if (aShort == 0 && accessor.wasNull()) {
+        return null;
+      }
+      return aShort;
+    case Types.TIME:
+      return accessor.getTime(localCalendar);
+    case Types.TIMESTAMP:
+      return accessor.getTimestamp(localCalendar);
+    case Types.TINYINT:
+      final byte aByte = accessor.getByte();
+      if (aByte == 0 && accessor.wasNull()) {
+        return null;
+      }
+      return aByte;
+    default:
+      throw notImplemented();
+    }
+  }
+
+  public void setObject(Object x) {
+    slots[index] = TypedValue.ofJdbc(x, calendar);
+  }
+
+  public void setNull(int sqlType) {
+    slots[index] = wrap(ColumnMetaData.Rep.OBJECT, null);
+  }
+
+  public void setRef(Ref x) {
+  }
+
+  // This method is not implemented in the base Avatica jar version which is being used currently;
+  // Added implementation to enable Blob database writes
+  public void setBlob(Blob x) {
+     InputStream iStream;
+    try {
+        iStream = x.getBinaryStream();
+        int length =0;
+        while(iStream.read() != -1)
+            length ++;
+         setBytes(x.getBytes(1, length));
+         
+    } catch (SQLException | IOException e) {
+        throw new RuntimeException(e);
+    }
+    
+  }
+  
+  // This method is not implemented in the base Avatica jar version which is being used currently;
+  // Added implementation to enable Clob database writes
+  public void setClob(Clob x) {
+      Reader iStream;
+      try {
+          iStream = x.getCharacterStream();
+          int length =0;
+          while(iStream.read() != -1)
+              length ++;
+           setBytes(x.getSubString(1, length).getBytes());
+           
+      } catch (SQLException | IOException e) {
+          throw new RuntimeException(e);
+      }
+  }
+
+  public void setArray(Array x) {
+    slots[index] = wrap(ColumnMetaData.Rep.ARRAY, x);
+  }
+
+  public void setNull(int sqlType, String typeName) {
+  }
+
+  public void setURL(URL x) {
+  }
+
+  public void setObject(Object x, int targetSqlType,
+      int scaleOrLength) {
+  }
+
+  private static RuntimeException unsupportedCast(Class<?> from, Class<?> to) {
+    return new UnsupportedOperationException("Cannot convert from "
+        + from.getCanonicalName() + " to " + to.getCanonicalName());
+  }
+
+  private static RuntimeException notImplemented() {
+    return new RuntimeException("not implemented");
+  }
+
+  private static Array toArray(Object x) {
+    if (x instanceof Array) {
+      return (Array) x;
+    }
+    throw unsupportedCast(x.getClass(), Array.class);
+  }
+
+  public static BigDecimal toBigDecimal(Object x) {
+    if (x instanceof BigDecimal) {
+      return (BigDecimal) x;
+    } else if (x instanceof BigInteger) {
+      return new BigDecimal((BigInteger) x);
+    } else if (x instanceof Number) {
+      if (x instanceof Double || x instanceof Float) {
+        return new BigDecimal(((Number) x).doubleValue());
+      } else {
+        return new BigDecimal(((Number) x).longValue());
+      }
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? BigDecimal.ONE : BigDecimal.ZERO;
+    } else if (x instanceof String) {
+      return new BigDecimal((String) x);
+    }
+    throw unsupportedCast(x.getClass(), BigDecimal.class);
+  }
+
+  private static boolean toBoolean(Object x) {
+    if (x instanceof Boolean) {
+      return (Boolean) x;
+    } else if (x instanceof Number) {
+      return ((Number) x).intValue() != 0;
+    } else if (x instanceof String) {
+      String s = (String) x;
+      if (s.equalsIgnoreCase("true") || s.equalsIgnoreCase("yes")) {
+        return true;
+      } else if (s.equalsIgnoreCase("false") || s.equalsIgnoreCase("no")) {
+        return false;
+      }
+    }
+    throw unsupportedCast(x.getClass(), Boolean.TYPE);
+  }
+
+  private static byte toByte(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).byteValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? (byte) 1 : (byte) 0;
+    } else if (x instanceof String) {
+      return Byte.parseByte((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Byte.TYPE);
+    }
+  }
+
+  private static byte[] toBytes(Object x) {
+    if (x instanceof byte[]) {
+      return (byte[]) x;
+    }
+    if (x instanceof String) {
+      return ((String) x).getBytes(StandardCharsets.UTF_8);
+    }
+    throw unsupportedCast(x.getClass(), byte[].class);
+  }
+
+  private static Date toDate(Object x) {
+    if (x instanceof String) {
+      return Date.valueOf((String) x);
+    }
+    return new Date(toLong(x));
+  }
+
+  private static Time toTime(Object x) {
+    if (x instanceof String) {
+      return Time.valueOf((String) x);
+    }
+    return new Time(toLong(x));
+  }
+
+  private static Timestamp toTimestamp(Object x) {
+    if (x instanceof String) {
+      return Timestamp.valueOf((String) x);
+    }
+    return new Timestamp(toLong(x));
+  }
+
+  private static double toDouble(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).doubleValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? 1D : 0D;
+    } else if (x instanceof String) {
+      return Double.parseDouble((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Double.TYPE);
+    }
+  }
+
+  private static float toFloat(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).floatValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? 1F : 0F;
+    } else if (x instanceof String) {
+      return Float.parseFloat((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Float.TYPE);
+    }
+  }
+
+  private static int toInt(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).intValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? 1 : 0;
+    } else if (x instanceof String) {
+      return Integer.parseInt((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Integer.TYPE);
+    }
+  }
+
+  private static long toLong(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).longValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? 1L : 0L;
+    } else if (x instanceof String) {
+      return Long.parseLong((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Long.TYPE);
+    }
+  }
+
+  private static short toShort(Object x) {
+    if (x instanceof Number) {
+      return ((Number) x).shortValue();
+    } else if (x instanceof Boolean) {
+      return (Boolean) x ? (short) 1 : (short) 0;
+    } else if (x instanceof String) {
+      return Short.parseShort((String) x);
+    } else {
+      throw unsupportedCast(x.getClass(), Short.TYPE);
+    }
+  }
+
+  private static String toString(Object x) {
+    if (x instanceof String) {
+      return (String) x;
+    } else if (x instanceof Character
+        || x instanceof Boolean) {
+      return x.toString();
+    }
+    throw unsupportedCast(x.getClass(), String.class);
+  }
+
+  /** Singleton value to denote parameters that have been set to null (as
+   * opposed to not set).
+   *
+   * <p>Not a valid value for a parameter.
+   *
+   * <p>As an enum, it is serializable by Jackson. */
+  private enum Dummy {
+    INSTANCE
+  }
+}
+
+// End AvaticaSite.java
index cacbb8b..bf139f5 100644 (file)
@@ -41,6 +41,7 @@ import java.util.Calendar;
 import java.util.List;\r
 import java.util.Map;\r
 import javax.sql.rowset.serial.SerialBlob;\r
+import javax.sql.rowset.serial.SerialClob;\r
 import org.apache.calcite.avatica.AvaticaSite;\r
 import org.apache.calcite.avatica.AvaticaUtils;\r
 import org.apache.calcite.avatica.ColumnMetaData;\r
@@ -848,7 +849,9 @@ public abstract class AbstractCursor implements Cursor {
       throw new IllegalStateException("Unhandled value type: " + o.getClass());\r
     }\r
     \r
-    \r
+    // This method is not implemented in the base Avatica jar version which is being used currently;\r
+    // Added implementation to enable Blob database reads; this has unintended consequences if entire object\r
+    // cannot be loaded into memory\r
     @Override public Blob getBlob() throws SQLException {\r
         \r
         Object o = getObject();\r
@@ -857,13 +860,31 @@ public abstract class AbstractCursor implements Cursor {
         }\r
         if (o instanceof byte[]) {\r
             byte[] byteArr = (byte[] )o;\r
-            //System.out.println(new String(byteArr, StandardCharsets.UTF_8));\r
             return new SerialBlob(byteArr);\r
         } \r
         \r
         throw new IllegalStateException("Unhandled value type: " + o.getClass());\r
         \r
     }\r
+    \r
+    // This method is not implemented in the base Avatica jar version which is being used currently;\r
+    // Added implementation to enable Clob database writes; this has unintended consequences if entire object\r
+    // cannot be loaded into memory\r
+    @Override public Clob getClob() throws SQLException {\r
+        \r
+        Object o = getObject();\r
+        if (null == o) {\r
+          return null;\r
+        }\r
+        if (o instanceof byte[]) {\r
+            byte[] byteArr = (byte[] )o;\r
+            return new SerialClob(new String(byteArr).toCharArray());\r
+        } \r
+        \r
+        throw new IllegalStateException("Unhandled value type: " + o.getClass());\r
+        \r
+    }\r
+    \r
   }\r
 \r
   /**\r
index 7e9b5f4..8f27953 100755 (executable)
@@ -333,7 +333,8 @@ mysql> describe tables;
                case "text":
                case "varchar":         return Types.VARCHAR;
                case "mediumblob":
-               case "blob":            return Types.VARCHAR;
+               case "longblob":    
+               case "blob":            return Types.BLOB;
                default:
                        logger.error(EELFLoggerDelegate.errorLogger,"unrecognized and/or unsupported data type "+nm);
                        return Types.VARCHAR;