From 1f36e4303bf76b752eed9ebb8c79a80c31139037 Mon Sep 17 00:00:00 2001 From: statta Date: Fri, 31 May 2019 12:28:00 -0400 Subject: Enhance Clob,Blob support Issue-ID: MUSIC-388 Change-Id: Ib02df8239e5d7572470fa696697685bdc582cdbb Signed-off-by: statta --- .../org/apache/calcite/avatica/AvaticaSite.java | 1239 ++++++++++---------- .../calcite/avatica/util/AbstractCursor.java | 25 +- .../org/onap/music/mdbc/mixins/MySQLMixin.java | 3 +- 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). - * - *

Not a valid value for a parameter. - * - *

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). + * + *

Not a valid value for a parameter. + * + *

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; -- cgit 1.2.3-korg