diff options
author | statta <statta@research.att.com> | 2019-05-31 12:28:00 -0400 |
---|---|---|
committer | statta <statta@research.att.com> | 2019-05-31 12:28:00 -0400 |
commit | 1f36e4303bf76b752eed9ebb8c79a80c31139037 (patch) | |
tree | 4ca30eb5f32459460cbc098396a32d5ec1925452 | |
parent | 65b45cafb4dff93bef52e91f2ab3f2a772e4472e (diff) |
Enhance Clob,Blob support
Issue-ID: MUSIC-388
Change-Id: Ib02df8239e5d7572470fa696697685bdc582cdbb
Signed-off-by: statta <statta@research.att.com>
3 files changed, 652 insertions, 615 deletions
diff --git a/mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java b/mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java index 5fd4e69..2e7cdc0 100644 --- a/mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java +++ b/mdbc-server/src/main/java/org/apache/calcite/avatica/AvaticaSite.java @@ -1,612 +1,627 @@ -/*
- * 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) {
- }
-
- 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);
- }
-
- }
-
- public void setClob(Clob x) {
- }
-
- 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
+/* + * 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 diff --git a/mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java b/mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java index cacbb8b..bf139f5 100644 --- a/mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java +++ b/mdbc-server/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java @@ -41,6 +41,7 @@ import java.util.Calendar; import java.util.List;
import java.util.Map;
import javax.sql.rowset.serial.SerialBlob;
+import javax.sql.rowset.serial.SerialClob;
import org.apache.calcite.avatica.AvaticaSite;
import org.apache.calcite.avatica.AvaticaUtils;
import org.apache.calcite.avatica.ColumnMetaData;
@@ -848,7 +849,9 @@ public abstract class AbstractCursor implements Cursor { throw new IllegalStateException("Unhandled value type: " + o.getClass());
}
-
+ // This method is not implemented in the base Avatica jar version which is being used currently;
+ // Added implementation to enable Blob database reads; this has unintended consequences if entire object
+ // cannot be loaded into memory
@Override public Blob getBlob() throws SQLException {
Object o = getObject();
@@ -857,13 +860,31 @@ public abstract class AbstractCursor implements Cursor { }
if (o instanceof byte[]) {
byte[] byteArr = (byte[] )o;
- //System.out.println(new String(byteArr, StandardCharsets.UTF_8));
return new SerialBlob(byteArr);
}
throw new IllegalStateException("Unhandled value type: " + o.getClass());
}
+
+ // This method is not implemented in the base Avatica jar version which is being used currently;
+ // Added implementation to enable Clob database writes; this has unintended consequences if entire object
+ // cannot be loaded into memory
+ @Override public Clob getClob() throws SQLException {
+
+ Object o = getObject();
+ if (null == o) {
+ return null;
+ }
+ if (o instanceof byte[]) {
+ byte[] byteArr = (byte[] )o;
+ return new SerialClob(new String(byteArr).toCharArray());
+ }
+
+ throw new IllegalStateException("Unhandled value type: " + o.getClass());
+
+ }
+
}
/**
diff --git a/mdbc-server/src/main/java/org/onap/music/mdbc/mixins/MySQLMixin.java b/mdbc-server/src/main/java/org/onap/music/mdbc/mixins/MySQLMixin.java index 7e9b5f4..8f27953 100755 --- a/mdbc-server/src/main/java/org/onap/music/mdbc/mixins/MySQLMixin.java +++ b/mdbc-server/src/main/java/org/onap/music/mdbc/mixins/MySQLMixin.java @@ -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; |