http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/src/main/java/org/apache/calcite/avatica/remote/TypedValue.java ---------------------------------------------------------------------- diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/TypedValue.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/TypedValue.java deleted file mode 100644 index d96293b..0000000 --- a/avatica/src/main/java/org/apache/calcite/avatica/remote/TypedValue.java +++ /dev/null @@ -1,533 +0,0 @@ -/* - * 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.remote; - -import org.apache.calcite.avatica.ColumnMetaData; -import org.apache.calcite.avatica.proto.Common; -import org.apache.calcite.avatica.util.ByteString; -import org.apache.calcite.avatica.util.DateTimeUtils; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.protobuf.HBaseZeroCopyByteString; - -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; - -/** Value and type. - * - * <p>There are 3 representations: - * <ul> - * <li>JDBC - the representation used by JDBC get and set methods - * <li>Serial - suitable for serializing using JSON - * <li>Local - used by Calcite for efficient computation - * </ul> - * - * <p>The following table shows the Java type(s) that may represent each SQL - * type in each representation. - * - * <table> - * <caption>SQL types and their representations</caption> - * <tr> - * <th>Type</th> <th>JDBC</th> <th>Serial</th> <th>Local</th> - * </tr> - * <tr> - * <td>BOOLEAN</td> <td>boolean</td> <td>boolean</td> <td>boolean</td> - * </tr> - * <tr> - * <td>BINARY, VARBINARY</td> <td>byte[]</td> - * <td>String (base64)</td> <td>{@link ByteString}</td> - * </tr> - * <tr> - * <td>DATE</td> <td>{@link java.sql.Date}</td> - * <td>int</td> <td>int</td> - * </tr> - * <tr> - * <td>TIME</td> <td>{@link java.sql.Time}</td> - * <td>int</td> <td>int</td> - * </tr> - * <tr> - * <td>DATE</td> <td>{@link java.sql.Timestamp}</td> - * <td>long</td> <td>long</td> - * </tr> - * <tr> - * <td>CHAR, VARCHAR</td> - * <td>String</td> <td>String</td> <td>String</td> - * </tr> - * <tr> - * <td>TINYINT</td> <td>byte</td> <td>Number</td> <td>byte</td> - * </tr> - * <tr> - * <td>SMALLINT</td> <td>short</td> <td>Number</td> <td>short</td> - * </tr> - * <tr> - * <td>INTEGER</td> <td>int</td> <td>Number</td> <td>int</td> - * </tr> - * <tr> - * <td>BIGINT</td> <td>long</td> <td>Number</td> <td>long</td> - * </tr> - * <tr> - * <td>REAL</td> <td>float</td> <td>Number</td> <td>float</td> - * </tr> - * <tr> - * <td>FLOAT, DOUBLE</td> - * <td>double</td> <td>Number</td> <td>double</td> - * </tr> - * <tr> - * <td>DECIMAL</td> - * <td>BigDecimal</td> <td>Number</td> <td>BigDecimal</td> - * </tr> - * </table> - * - * Note: - * <ul> - * <li>The various numeric types (TINYINT, SMALLINT, INTEGER, BIGINT, REAL, - * FLOAT, DOUBLE) are represented by {@link Number} in serial format because - * JSON numbers are not strongly typed. A {@code float} value {@code 3.0} is - * transmitted as {@code 3}, and is therefore decoded as an {@code int}. - * - * <li>The date-time types (DATE, TIME, TIMESTAMP) are represented in JDBC as - * {@link java.sql.Date}, {@link java.sql.Time}, {@link java.sql.Timestamp}, - * all sub-classes of {@link java.util.Date}. When they are passed to and - * from the server, they are interpreted in terms of a time zone, by default - * the current connection's time zone. Their serial and local representations - * as {@code int} (days since 1970-01-01 for DATE, milliseconds since - * 00:00:00.000 for TIME), and long (milliseconds since 1970-01-01 - * 00:00:00.000 for TIMESTAMP) are easier to work with, because it is clear - * that time zone is not involved. - * - * <li>BINARY and VARBINARY values are represented as base64-encoded strings - * for serialization over JSON. - * </ul> - */ -public class TypedValue { - public static final TypedValue NULL = - new TypedValue(ColumnMetaData.Rep.OBJECT, null); - - /** Type of the value. */ - public final ColumnMetaData.Rep type; - - /** Value. - * - * <p>Always in a form that can be serialized to JSON by Jackson. - * For example, byte arrays are represented as String. */ - public final Object value; - - private TypedValue(ColumnMetaData.Rep rep, Object value) { - this.type = rep; - this.value = value; - assert isSerial(rep, value) : "rep: " + rep + ", value: " + value; - } - - private boolean isSerial(ColumnMetaData.Rep rep, Object value) { - if (value == null) { - return true; - } - switch (rep) { - case BYTE_STRING: - return value instanceof String; - case JAVA_SQL_DATE: - case JAVA_SQL_TIME: - return value instanceof Integer; - case JAVA_SQL_TIMESTAMP: - case JAVA_UTIL_DATE: - return value instanceof Long; - default: - return true; - } - } - - @JsonCreator - public static TypedValue create(@JsonProperty("type") String type, - @JsonProperty("value") Object value) { - if (value == null) { - return NULL; - } - ColumnMetaData.Rep rep = ColumnMetaData.Rep.valueOf(type); - return ofLocal(rep, serialToLocal(rep, value)); - } - - /** Creates a TypedValue from a value in local representation. */ - public static TypedValue ofLocal(ColumnMetaData.Rep rep, Object value) { - return new TypedValue(rep, localToSerial(rep, value)); - } - - /** Creates a TypedValue from a value in serial representation. */ - public static TypedValue ofSerial(ColumnMetaData.Rep rep, Object value) { - return new TypedValue(rep, value); - } - - /** Creates a TypedValue from a value in JDBC representation. */ - public static TypedValue ofJdbc(ColumnMetaData.Rep rep, Object value, - Calendar calendar) { - if (value == null) { - return NULL; - } - return new TypedValue(rep, jdbcToSerial(rep, value, calendar)); - } - - /** Creates a TypedValue from a value in JDBC representation, - * deducing its type. */ - public static TypedValue ofJdbc(Object value, Calendar calendar) { - if (value == null) { - return NULL; - } - final ColumnMetaData.Rep rep = ColumnMetaData.Rep.of(value.getClass()); - return new TypedValue(rep, jdbcToSerial(rep, value, calendar)); - } - - /** Converts the value into the local representation. - * - * <p>For example, a byte string is represented as a {@link ByteString}; - * a long is represented as a {@link Long} (not just some {@link Number}). - */ - public Object toLocal() { - if (value == null) { - return null; - } - return serialToLocal(type, value); - } - - /** Converts a value to the exact type required for the given - * representation. */ - private static Object serialToLocal(ColumnMetaData.Rep rep, Object value) { - assert value != null; - if (value.getClass() == rep.clazz) { - return value; - } - switch (rep) { - case BYTE: - return ((Number) value).byteValue(); - case SHORT: - return ((Number) value).shortValue(); - case INTEGER: - case JAVA_SQL_DATE: - case JAVA_SQL_TIME: - return ((Number) value).intValue(); - case LONG: - case JAVA_UTIL_DATE: - case JAVA_SQL_TIMESTAMP: - return ((Number) value).longValue(); - case FLOAT: - return ((Number) value).floatValue(); - case DOUBLE: - return ((Number) value).doubleValue(); - case NUMBER: - return value instanceof BigDecimal ? value - : value instanceof BigInteger ? new BigDecimal((BigInteger) value) - : value instanceof Double ? new BigDecimal((Double) value) - : value instanceof Float ? new BigDecimal((Float) value) - : new BigDecimal(((Number) value).longValue()); - case BYTE_STRING: - return ByteString.ofBase64((String) value); - default: - throw new IllegalArgumentException("cannot convert " + value + " (" - + value.getClass() + ") to " + rep); - } - } - - /** Converts the value into the JDBC representation. - * - * <p>For example, a byte string is represented as a {@link ByteString}; - * a long is represented as a {@link Long} (not just some {@link Number}). - */ - public Object toJdbc(Calendar calendar) { - if (value == null) { - return null; - } - return serialToJdbc(type, value, calendar); - } - - private static Object serialToJdbc(ColumnMetaData.Rep type, Object value, - Calendar calendar) { - switch (type) { - case BYTE_STRING: - return ByteString.ofBase64((String) value).getBytes(); - case JAVA_UTIL_DATE: - return new java.util.Date(adjust((Number) value, calendar)); - case JAVA_SQL_DATE: - return new java.sql.Date( - adjust(((Number) value).longValue() * DateTimeUtils.MILLIS_PER_DAY, - calendar)); - case JAVA_SQL_TIME: - return new java.sql.Time(adjust((Number) value, calendar)); - case JAVA_SQL_TIMESTAMP: - return new java.sql.Timestamp(adjust((Number) value, calendar)); - default: - return serialToLocal(type, value); - } - } - - private static long adjust(Number number, Calendar calendar) { - long t = number.longValue(); - if (calendar != null) { - t -= calendar.getTimeZone().getOffset(t); - } - return t; - } - - /** Converts a value from JDBC format to a type that can be serialized as - * JSON. */ - private static Object jdbcToSerial(ColumnMetaData.Rep rep, Object value, - Calendar calendar) { - switch (rep) { - case BYTE_STRING: - return new ByteString((byte[]) value).toBase64String(); - case JAVA_UTIL_DATE: - case JAVA_SQL_TIMESTAMP: - case JAVA_SQL_DATE: - case JAVA_SQL_TIME: - long t = ((Date) value).getTime(); - if (calendar != null) { - t += calendar.getTimeZone().getOffset(t); - } - switch (rep) { - case JAVA_SQL_DATE: - return (int) DateTimeUtils.floorDiv(t, DateTimeUtils.MILLIS_PER_DAY); - case JAVA_SQL_TIME: - return (int) DateTimeUtils.floorMod(t, DateTimeUtils.MILLIS_PER_DAY); - default: - return t; - } - default: - return value; - } - } - - /** Converts a value from internal format to a type that can be serialized - * as JSON. */ - private static Object localToSerial(ColumnMetaData.Rep rep, Object value) { - switch (rep) { - case BYTE_STRING: - return ((ByteString) value).toBase64String(); - default: - return value; - } - } - - /** Converts a list of {@code TypedValue} to a list of values. */ - public static List<Object> values(List<TypedValue> typedValues) { - final List<Object> list = new ArrayList<>(); - for (TypedValue typedValue : typedValues) { - list.add(typedValue.toLocal()); - } - return list; - } - - public Common.TypedValue toProto() { - final Common.TypedValue.Builder builder = Common.TypedValue.newBuilder(); - - Common.Rep protoRep = type.toProto(); - builder.setType(protoRep); - - // Serialize the type into the protobuf - switch (protoRep) { - case BOOLEAN: - case PRIMITIVE_BOOLEAN: - builder.setBoolValue((boolean) value); - break; - case BYTE_STRING: - case STRING: - builder.setStringValueBytes(HBaseZeroCopyByteString.wrap(((String) value).getBytes())); - break; - case PRIMITIVE_CHAR: - case CHARACTER: - builder.setStringValue(Character.toString((char) value)); - break; - case BYTE: - case PRIMITIVE_BYTE: - builder.setNumberValue(Byte.valueOf((byte) value).longValue()); - break; - case DOUBLE: - case PRIMITIVE_DOUBLE: - builder.setDoubleValue((double) value); - break; - case FLOAT: - case PRIMITIVE_FLOAT: - builder.setNumberValue(Float.floatToIntBits((float) value)); - break; - case INTEGER: - case PRIMITIVE_INT: - builder.setNumberValue(Integer.valueOf((int) value).longValue()); - break; - case PRIMITIVE_SHORT: - case SHORT: - builder.setNumberValue(Short.valueOf((short) value).longValue()); - break; - case LONG: - case PRIMITIVE_LONG: - builder.setNumberValue((long) value); - break; - case JAVA_SQL_DATE: - case JAVA_SQL_TIME: - // Persisted as integers - builder.setNumberValue(Integer.valueOf((int) value).longValue()); - break; - case JAVA_SQL_TIMESTAMP: - case JAVA_UTIL_DATE: - // Persisted as longs - builder.setNumberValue((long) value); - break; - case BIG_INTEGER: - byte[] bytes = ((BigInteger) value).toByteArray(); - builder.setBytesValues(com.google.protobuf.ByteString.copyFrom(bytes)); - break; - case BIG_DECIMAL: - final BigDecimal bigDecimal = (BigDecimal) value; - final int scale = bigDecimal.scale(); - final BigInteger bigInt = bigDecimal.toBigInteger(); - builder.setBytesValues(com.google.protobuf.ByteString.copyFrom(bigInt.toByteArray())) - .setNumberValue(scale); - break; - case NUMBER: - builder.setNumberValue(((Number) value).longValue()); - break; - case OBJECT: - if (null == value) { - // We can persist a null value through easily - builder.setNull(true); - break; - } - // Intentional fall-through to RTE because we can't serialize something we have no type - // insight into. - case UNRECOGNIZED: - // Fail? - throw new RuntimeException("Unhandled value: " + protoRep + " " + value.getClass()); - default: - // Fail? - throw new RuntimeException("Unknown serialized type: " + protoRep); - } - - return builder.build(); - } - - public static TypedValue fromProto(Common.TypedValue proto) { - ColumnMetaData.Rep rep = ColumnMetaData.Rep.fromProto(proto.getType()); - - Object value = null; - - // Deserialize the value again - switch (proto.getType()) { - case BOOLEAN: - case PRIMITIVE_BOOLEAN: - value = proto.getBoolValue(); - break; - case BYTE_STRING: - case STRING: - value = proto.getStringValue(); - break; - case PRIMITIVE_CHAR: - case CHARACTER: - value = proto.getStringValue().charAt(0); - break; - case BYTE: - case PRIMITIVE_BYTE: - value = Long.valueOf(proto.getNumberValue()).byteValue(); - break; - case DOUBLE: - case PRIMITIVE_DOUBLE: - value = proto.getDoubleValue(); - break; - case FLOAT: - case PRIMITIVE_FLOAT: - value = Float.intBitsToFloat((int) proto.getNumberValue()); - break; - case INTEGER: - case PRIMITIVE_INT: - value = Long.valueOf(proto.getNumberValue()).intValue(); - break; - case PRIMITIVE_SHORT: - case SHORT: - value = Long.valueOf(proto.getNumberValue()).shortValue(); - break; - case LONG: - case PRIMITIVE_LONG: - value = Long.valueOf(proto.getNumberValue()); - break; - case JAVA_SQL_DATE: - case JAVA_SQL_TIME: - value = Long.valueOf(proto.getNumberValue()).intValue(); - break; - case JAVA_SQL_TIMESTAMP: - case JAVA_UTIL_DATE: - value = proto.getNumberValue(); - break; - case BIG_INTEGER: - value = new BigInteger(proto.getBytesValues().toByteArray()); - break; - case BIG_DECIMAL: - BigInteger bigInt = new BigInteger(proto.getBytesValues().toByteArray()); - value = new BigDecimal(bigInt, (int) proto.getNumberValue()); - break; - case NUMBER: - value = Long.valueOf(proto.getNumberValue()); - break; - case OBJECT: - if (proto.getNull()) { - value = null; - break; - } - // Intentional fall through to RTE. If we sent an object over the wire, it could only - // possibly be null (at this point). Anything else has to be an error. - case UNRECOGNIZED: - // Fail? - throw new RuntimeException("Unhandled type: " + proto.getType()); - default: - // Fail? - throw new RuntimeException("Unknown type: " + proto.getType()); - } - - return new TypedValue(rep, value); - } - - @Override public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((type == null) ? 0 : type.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - } - - @Override public boolean equals(Object o) { - if (o == this) { - return true; - } - if (o instanceof TypedValue) { - TypedValue other = (TypedValue) o; - - if (type != other.type) { - return false; - } - - if (null == value) { - if (null != other.value) { - return false; - } - } - - return value.equals(other.value); - } - - return false; - } -} - -// End TypedValue.java
http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/src/main/java/org/apache/calcite/avatica/remote/package-info.java ---------------------------------------------------------------------- diff --git a/avatica/src/main/java/org/apache/calcite/avatica/remote/package-info.java b/avatica/src/main/java/org/apache/calcite/avatica/remote/package-info.java deleted file mode 100644 index 1cf3e14..0000000 --- a/avatica/src/main/java/org/apache/calcite/avatica/remote/package-info.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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. - */ - -/** - * JDBC driver that uses remote procedure calls. - */ -@PackageMarker -package org.apache.calcite.avatica.remote; - -import org.apache.calcite.avatica.util.PackageMarker; - -// End package-info.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java ---------------------------------------------------------------------- diff --git a/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java b/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java deleted file mode 100644 index 70f87a7..0000000 --- a/avatica/src/main/java/org/apache/calcite/avatica/util/AbstractCursor.java +++ /dev/null @@ -1,1377 +0,0 @@ -/* - * 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.util; - -import org.apache.calcite.avatica.AvaticaSite; -import org.apache.calcite.avatica.AvaticaUtils; -import org.apache.calcite.avatica.ColumnMetaData; - -import java.io.InputStream; -import java.io.Reader; -import java.lang.reflect.Field; -import java.math.BigDecimal; -import java.math.RoundingMode; -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.SQLException; -import java.sql.SQLXML; -import java.sql.Struct; -import java.sql.Time; -import java.sql.Timestamp; -import java.sql.Types; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.List; -import java.util.Map; - -/** - * Base class for implementing a cursor. - * - * <p>Derived class needs to provide {@link Getter} and can override - * {@link org.apache.calcite.avatica.util.Cursor.Accessor} implementations if it - * wishes.</p> - */ -public abstract class AbstractCursor implements Cursor { - /** - * Slot into which each accessor should write whether the - * value returned was null. - */ - protected final boolean[] wasNull = {false}; - - protected AbstractCursor() { - } - - public boolean wasNull() { - return wasNull[0]; - } - - public List<Accessor> createAccessors(List<ColumnMetaData> types, - Calendar localCalendar, ArrayImpl.Factory factory) { - List<Accessor> accessors = new ArrayList<>(); - for (ColumnMetaData type : types) { - accessors.add( - createAccessor(type, accessors.size(), localCalendar, factory)); - } - return accessors; - } - - protected Accessor createAccessor(ColumnMetaData columnMetaData, int ordinal, - Calendar localCalendar, ArrayImpl.Factory factory) { - // Create an accessor appropriate to the underlying type; the accessor - // can convert to any type in the same family. - Getter getter = createGetter(ordinal); - return createAccessor(columnMetaData, getter, localCalendar, factory); - } - - protected Accessor createAccessor(ColumnMetaData columnMetaData, - Getter getter, Calendar localCalendar, ArrayImpl.Factory factory) { - switch (columnMetaData.type.rep) { - case NUMBER: - switch (columnMetaData.type.id) { - case Types.TINYINT: - case Types.SMALLINT: - case Types.INTEGER: - case Types.BIGINT: - case Types.REAL: - case Types.FLOAT: - case Types.DOUBLE: - case Types.NUMERIC: - case Types.DECIMAL: - return new NumberAccessor(getter, columnMetaData.scale); - } - } - switch (columnMetaData.type.id) { - case Types.TINYINT: - return new ByteAccessor(getter); - case Types.SMALLINT: - return new ShortAccessor(getter); - case Types.INTEGER: - return new IntAccessor(getter); - case Types.BIGINT: - return new LongAccessor(getter); - case Types.BOOLEAN: - return new BooleanAccessor(getter); - case Types.REAL: - return new FloatAccessor(getter); - case Types.FLOAT: - case Types.DOUBLE: - return new DoubleAccessor(getter); - case Types.DECIMAL: - return new BigDecimalAccessor(getter); - case Types.CHAR: - switch (columnMetaData.type.rep) { - case PRIMITIVE_CHAR: - case CHARACTER: - return new StringFromCharAccessor(getter, columnMetaData.displaySize); - default: - return new FixedStringAccessor(getter, columnMetaData.displaySize); - } - case Types.VARCHAR: - return new StringAccessor(getter); - case Types.BINARY: - case Types.VARBINARY: - switch (columnMetaData.type.rep) { - case STRING: - return new BinaryFromStringAccessor(getter); - default: - return new BinaryAccessor(getter); - } - case Types.DATE: - switch (columnMetaData.type.rep) { - case PRIMITIVE_INT: - case INTEGER: - case NUMBER: - return new DateFromNumberAccessor(getter, localCalendar); - case JAVA_SQL_DATE: - return new DateAccessor(getter); - default: - throw new AssertionError("bad " + columnMetaData.type.rep); - } - case Types.TIME: - switch (columnMetaData.type.rep) { - case PRIMITIVE_INT: - case INTEGER: - case NUMBER: - return new TimeFromNumberAccessor(getter, localCalendar); - case JAVA_SQL_TIME: - return new TimeAccessor(getter); - default: - throw new AssertionError("bad " + columnMetaData.type.rep); - } - case Types.TIMESTAMP: - switch (columnMetaData.type.rep) { - case PRIMITIVE_LONG: - case LONG: - case NUMBER: - return new TimestampFromNumberAccessor(getter, localCalendar); - case JAVA_SQL_TIMESTAMP: - return new TimestampAccessor(getter); - case JAVA_UTIL_DATE: - return new TimestampFromUtilDateAccessor(getter, localCalendar); - default: - throw new AssertionError("bad " + columnMetaData.type.rep); - } - case Types.ARRAY: - final ColumnMetaData.ArrayType arrayType = - (ColumnMetaData.ArrayType) columnMetaData.type; - final SlotGetter componentGetter = new SlotGetter(); - final Accessor componentAccessor = - createAccessor(ColumnMetaData.dummy(arrayType.component, true), - componentGetter, localCalendar, factory); - return new ArrayAccessor(getter, arrayType.component, componentAccessor, - componentGetter, factory); - case Types.STRUCT: - switch (columnMetaData.type.rep) { - case OBJECT: - final ColumnMetaData.StructType structType = - (ColumnMetaData.StructType) columnMetaData.type; - List<Accessor> accessors = new ArrayList<>(); - for (ColumnMetaData column : structType.columns) { - final Getter fieldGetter = - structType.columns.size() == 1 - ? getter - : new StructGetter(getter, column); - accessors.add( - createAccessor(column, fieldGetter, localCalendar, factory)); - } - return new StructAccessor(getter, accessors); - default: - throw new AssertionError("bad " + columnMetaData.type.rep); - } - case Types.JAVA_OBJECT: - case Types.OTHER: // e.g. map - if (columnMetaData.type.name.startsWith("INTERVAL_")) { - int end = columnMetaData.type.name.indexOf("("); - if (end < 0) { - end = columnMetaData.type.name.length(); - } - TimeUnitRange range = - TimeUnitRange.valueOf( - columnMetaData.type.name.substring("INTERVAL_".length(), end)); - if (range.monthly()) { - return new IntervalYearMonthAccessor(getter, range); - } else { - return new IntervalDayTimeAccessor(getter, range, - columnMetaData.scale); - } - } - return new ObjectAccessor(getter); - default: - throw new RuntimeException("unknown type " + columnMetaData.type.id); - } - } - - protected abstract Getter createGetter(int ordinal); - - public abstract boolean next(); - - /** Accesses a timestamp value as a string. - * The timestamp is in SQL format (e.g. "2013-09-22 22:30:32"), - * not Java format ("2013-09-22 22:30:32.123"). */ - private static String timestampAsString(long v, Calendar calendar) { - if (calendar != null) { - v -= calendar.getTimeZone().getOffset(v); - } - return DateTimeUtils.unixTimestampToString(v); - } - - /** Accesses a date value as a string, e.g. "2013-09-22". */ - private static String dateAsString(int v, Calendar calendar) { - AvaticaUtils.discard(calendar); // time zone shift doesn't make sense - return DateTimeUtils.unixDateToString(v); - } - - /** Accesses a time value as a string, e.g. "22:30:32". */ - private static String timeAsString(int v, Calendar calendar) { - if (calendar != null) { - v -= calendar.getTimeZone().getOffset(v); - } - return DateTimeUtils.unixTimeToString(v); - } - - private static Date longToDate(long v, Calendar calendar) { - if (calendar != null) { - v -= calendar.getTimeZone().getOffset(v); - } - return new Date(v); - } - - static Time intToTime(int v, Calendar calendar) { - if (calendar != null) { - v -= calendar.getTimeZone().getOffset(v); - } - return new Time(v); - } - - static Timestamp longToTimestamp(long v, Calendar calendar) { - if (calendar != null) { - v -= calendar.getTimeZone().getOffset(v); - } - return new Timestamp(v); - } - - /** Implementation of {@link Cursor.Accessor}. */ - static class AccessorImpl implements Accessor { - protected final Getter getter; - - public AccessorImpl(Getter getter) { - assert getter != null; - this.getter = getter; - } - - public boolean wasNull() { - return getter.wasNull(); - } - - public String getString() { - final Object o = getObject(); - return o == null ? null : o.toString(); - } - - public boolean getBoolean() { - return getLong() != 0L; - } - - public byte getByte() { - return (byte) getLong(); - } - - public short getShort() { - return (short) getLong(); - } - - public int getInt() { - return (int) getLong(); - } - - public long getLong() { - throw cannotConvert("long"); - } - - public float getFloat() { - return (float) getDouble(); - } - - public double getDouble() { - throw cannotConvert("double"); - } - - public BigDecimal getBigDecimal() { - throw cannotConvert("BigDecimal"); - } - - public BigDecimal getBigDecimal(int scale) { - throw cannotConvert("BigDecimal with scale"); - } - - public byte[] getBytes() { - throw cannotConvert("byte[]"); - } - - public InputStream getAsciiStream() { - throw cannotConvert("InputStream (ascii)"); - } - - public InputStream getUnicodeStream() { - throw cannotConvert("InputStream (unicode)"); - } - - public InputStream getBinaryStream() { - throw cannotConvert("InputStream (binary)"); - } - - public Object getObject() { - return getter.getObject(); - } - - public Reader getCharacterStream() { - throw cannotConvert("Reader"); - } - - private RuntimeException cannotConvert(String targetType) { - return new RuntimeException("cannot convert to " + targetType + " (" - + this + ")"); - } - - public Object getObject(Map<String, Class<?>> map) { - throw cannotConvert("Object (with map)"); - } - - public Ref getRef() { - throw cannotConvert("Ref"); - } - - public Blob getBlob() { - throw cannotConvert("Blob"); - } - - public Clob getClob() { - throw cannotConvert("Clob"); - } - - public Array getArray() { - throw cannotConvert("Array"); - } - - public Struct getStruct() { - throw cannotConvert("Struct"); - } - - public Date getDate(Calendar calendar) { - throw cannotConvert("Date"); - } - - public Time getTime(Calendar calendar) { - throw cannotConvert("Time"); - } - - public Timestamp getTimestamp(Calendar calendar) { - throw cannotConvert("Timestamp"); - } - - public URL getURL() { - throw cannotConvert("URL"); - } - - public NClob getNClob() { - throw cannotConvert("NClob"); - } - - public SQLXML getSQLXML() { - throw cannotConvert("SQLXML"); - } - - public String getNString() { - throw cannotConvert("NString"); - } - - public Reader getNCharacterStream() { - throw cannotConvert("NCharacterStream"); - } - - public <T> T getObject(Class<T> type) { - throw cannotConvert("Object (with type)"); - } - } - - /** - * Accessor of exact numeric values. The subclass must implement the - * {@link #getLong()} method. - */ - private abstract static class ExactNumericAccessor extends AccessorImpl { - public ExactNumericAccessor(Getter getter) { - super(getter); - } - - public BigDecimal getBigDecimal(int scale) { - final long v = getLong(); - if (v == 0 && getter.wasNull()) { - return null; - } - return BigDecimal.valueOf(v).setScale(scale, RoundingMode.DOWN); - } - - public BigDecimal getBigDecimal() { - final long val = getLong(); - if (val == 0 && getter.wasNull()) { - return null; - } - return BigDecimal.valueOf(val); - } - - public double getDouble() { - return getLong(); - } - - public float getFloat() { - return getLong(); - } - - public abstract long getLong(); - } - - /** - * Accessor that assumes that the underlying value is a {@link Boolean}; - * corresponds to {@link java.sql.Types#BOOLEAN}. - */ - private static class BooleanAccessor extends ExactNumericAccessor { - public BooleanAccessor(Getter getter) { - super(getter); - } - - public boolean getBoolean() { - Boolean o = (Boolean) getObject(); - return o != null && o; - } - - public long getLong() { - return getBoolean() ? 1 : 0; - } - } - - /** - * Accessor that assumes that the underlying value is a {@link Byte}; - * corresponds to {@link java.sql.Types#TINYINT}. - */ - private static class ByteAccessor extends ExactNumericAccessor { - public ByteAccessor(Getter getter) { - super(getter); - } - - public byte getByte() { - Byte o = (Byte) getObject(); - return o == null ? 0 : o; - } - - public long getLong() { - return getByte(); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link Short}; - * corresponds to {@link java.sql.Types#SMALLINT}. - */ - private static class ShortAccessor extends ExactNumericAccessor { - public ShortAccessor(Getter getter) { - super(getter); - } - - public short getShort() { - Short o = (Short) getObject(); - return o == null ? 0 : o; - } - - public long getLong() { - return getShort(); - } - } - - /** - * Accessor that assumes that the underlying value is an {@link Integer}; - * corresponds to {@link java.sql.Types#INTEGER}. - */ - private static class IntAccessor extends ExactNumericAccessor { - public IntAccessor(Getter getter) { - super(getter); - } - - public int getInt() { - Integer o = (Integer) super.getObject(); - return o == null ? 0 : o; - } - - public long getLong() { - return getInt(); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link Long}; - * corresponds to {@link java.sql.Types#BIGINT}. - */ - private static class LongAccessor extends ExactNumericAccessor { - public LongAccessor(Getter getter) { - super(getter); - } - - public long getLong() { - Long o = (Long) super.getObject(); - return o == null ? 0 : o; - } - } - - /** - * Accessor of values that are {@link Double} or null. - */ - private abstract static class ApproximateNumericAccessor - extends AccessorImpl { - public ApproximateNumericAccessor(Getter getter) { - super(getter); - } - - public BigDecimal getBigDecimal(int scale) { - final double v = getDouble(); - if (v == 0d && getter.wasNull()) { - return null; - } - return BigDecimal.valueOf(v).setScale(scale, RoundingMode.DOWN); - } - - public BigDecimal getBigDecimal() { - final double v = getDouble(); - if (v == 0 && getter.wasNull()) { - return null; - } - return BigDecimal.valueOf(v); - } - - public abstract double getDouble(); - - public long getLong() { - return (long) getDouble(); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link Float}; - * corresponds to {@link java.sql.Types#FLOAT}. - */ - private static class FloatAccessor extends ApproximateNumericAccessor { - public FloatAccessor(Getter getter) { - super(getter); - } - - public float getFloat() { - Float o = (Float) getObject(); - return o == null ? 0f : o; - } - - public double getDouble() { - return getFloat(); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link Double}; - * corresponds to {@link java.sql.Types#DOUBLE}. - */ - private static class DoubleAccessor extends ApproximateNumericAccessor { - public DoubleAccessor(Getter getter) { - super(getter); - } - - public double getDouble() { - Double o = (Double) getObject(); - return o == null ? 0d : o; - } - } - - /** - * Accessor of exact numeric values. The subclass must implement the - * {@link #getLong()} method. - */ - private abstract static class BigNumberAccessor extends AccessorImpl { - public BigNumberAccessor(Getter getter) { - super(getter); - } - - protected abstract Number getNumber(); - - public double getDouble() { - Number number = getNumber(); - return number == null ? 0d : number.doubleValue(); - } - - public float getFloat() { - Number number = getNumber(); - return number == null ? 0f : number.floatValue(); - } - - public long getLong() { - Number number = getNumber(); - return number == null ? 0L : number.longValue(); - } - - public int getInt() { - Number number = getNumber(); - return number == null ? 0 : number.intValue(); - } - - public short getShort() { - Number number = getNumber(); - return number == null ? 0 : number.shortValue(); - } - - public byte getByte() { - Number number = getNumber(); - return number == null ? 0 : number.byteValue(); - } - - public boolean getBoolean() { - Number number = getNumber(); - return number != null && number.doubleValue() != 0; - } - } - - /** - * Accessor that assumes that the underlying value is a {@link BigDecimal}; - * corresponds to {@link java.sql.Types#DECIMAL}. - */ - private static class BigDecimalAccessor extends BigNumberAccessor { - public BigDecimalAccessor(Getter getter) { - super(getter); - } - - protected Number getNumber() { - return (Number) getObject(); - } - - public BigDecimal getBigDecimal(int scale) { - return (BigDecimal) getObject(); - } - - public BigDecimal getBigDecimal() { - return (BigDecimal) getObject(); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link Number}; - * corresponds to {@link java.sql.Types#NUMERIC}. - * - * <p>This is useful when numbers have been translated over JSON. JSON - * converts a 0L (0 long) value to the string "0" and back to 0 (0 int). - * So you cannot be sure that the source and target type are the same. - */ - static class NumberAccessor extends BigNumberAccessor { - private final int scale; - - public NumberAccessor(Getter getter, int scale) { - super(getter); - this.scale = scale; - } - - protected Number getNumber() { - return (Number) super.getObject(); - } - - public BigDecimal getBigDecimal(int scale) { - Number n = getNumber(); - if (n == null) { - return null; - } - BigDecimal decimal = AvaticaSite.toBigDecimal(n); - if (0 != scale) { - return decimal.setScale(scale, BigDecimal.ROUND_UNNECESSARY); - } - return decimal; - } - - public BigDecimal getBigDecimal() { - return getBigDecimal(scale); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link String}; - * corresponds to {@link java.sql.Types#CHAR} - * and {@link java.sql.Types#VARCHAR}. - */ - private static class StringAccessor extends AccessorImpl { - public StringAccessor(Getter getter) { - super(getter); - } - - public String getString() { - return (String) getObject(); - } - - @Override public byte[] getBytes() { - return super.getBytes(); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link String}; - * corresponds to {@link java.sql.Types#CHAR}. - */ - private static class FixedStringAccessor extends StringAccessor { - protected final Spacer spacer; - - public FixedStringAccessor(Getter getter, int length) { - super(getter); - this.spacer = new Spacer(length); - } - - public String getString() { - String s = super.getString(); - if (s == null) { - return null; - } - return spacer.padRight(s); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link String}; - * corresponds to {@link java.sql.Types#CHAR}. - */ - private static class StringFromCharAccessor extends FixedStringAccessor { - public StringFromCharAccessor(Getter getter, int length) { - super(getter, length); - } - - public String getString() { - Character s = (Character) super.getObject(); - if (s == null) { - return null; - } - return spacer.padRight(s.toString()); - } - } - - /** - * Accessor that assumes that the underlying value is an array of - * {@link org.apache.calcite.avatica.util.ByteString} values; - * corresponds to {@link java.sql.Types#BINARY} - * and {@link java.sql.Types#VARBINARY}. - */ - private static class BinaryAccessor extends AccessorImpl { - public BinaryAccessor(Getter getter) { - super(getter); - } - - //FIXME: Protobuf gets byte[] - @Override public byte[] getBytes() { - Object obj = getObject(); - try { - final ByteString o = (ByteString) obj; - return o == null ? null : o.getBytes(); - } catch (Exception ex) { - return obj == null ? null : (byte[]) obj; - } - } - - @Override public String getString() { - Object o = getObject(); - if (null == o) { - return null; - } - if (o instanceof byte[]) { - return new String((byte[]) o, StandardCharsets.UTF_8); - } else if (o instanceof ByteString) { - return ((ByteString) o).toString(); - } - throw new IllegalStateException("Unhandled value type: " + o.getClass()); - } - } - - /** - * Accessor that assumes that the underlying value is a {@link String}, - * encoding {@link java.sql.Types#BINARY} - * and {@link java.sql.Types#VARBINARY} values in Base64 format. - */ - private static class BinaryFromStringAccessor extends StringAccessor { - public BinaryFromStringAccessor(Getter getter) { - super(getter); - } - - @Override public Object getObject() { - return super.getObject(); - } - - @Override public byte[] getBytes() { - // JSON sends this as a base64-enc string, protobuf can do binary. - Object obj = getObject(); - - if (obj instanceof byte[]) { - // If we already have bytes, just send them back. - return (byte[]) obj; - } - - return getBase64Decoded(); - } - - private byte[] getBase64Decoded() { - final String string = super.getString(); - if (null == string) { - return null; - } - // Need to base64 decode the string. - return ByteString.parseBase64(string); - } - - @Override public String getString() { - final byte[] bytes = getBase64Decoded(); - if (null == bytes) { - return null; - } - // Need to base64 decode the string. - return new String(bytes, StandardCharsets.UTF_8); - } - } - - /** - * Accessor that assumes that the underlying value is a DATE, - * in its default representation {@code int}; - * corresponds to {@link java.sql.Types#DATE}. - */ - private static class DateFromNumberAccessor extends NumberAccessor { - private final Calendar localCalendar; - - public DateFromNumberAccessor(Getter getter, Calendar localCalendar) { - super(getter, 0); - this.localCalendar = localCalendar; - } - - @Override public Object getObject() { - return getDate(localCalendar); - } - - @Override public Date getDate(Calendar calendar) { - final Number v = getNumber(); - if (v == null) { - return null; - } - return longToDate(v.longValue() * DateTimeUtils.MILLIS_PER_DAY, calendar); - } - - @Override public Timestamp getTimestamp(Calendar calendar) { - final Number v = getNumber(); - if (v == null) { - return null; - } - return longToTimestamp(v.longValue() * DateTimeUtils.MILLIS_PER_DAY, - calendar); - } - - @Override public String getString() { - final Number v = getNumber(); - if (v == null) { - return null; - } - return dateAsString(v.intValue(), null); - } - } - - /** - * Accessor that assumes that the underlying value is a Time, - * in its default representation {@code int}; - * corresponds to {@link java.sql.Types#TIME}. - */ - private static class TimeFromNumberAccessor extends NumberAccessor { - private final Calendar localCalendar; - - public TimeFromNumberAccessor(Getter getter, Calendar localCalendar) { - super(getter, 0); - this.localCalendar = localCalendar; - } - - @Override public Object getObject() { - return getTime(localCalendar); - } - - @Override public Time getTime(Calendar calendar) { - final Number v = getNumber(); - if (v == null) { - return null; - } - return intToTime(v.intValue(), calendar); - } - - @Override public Timestamp getTimestamp(Calendar calendar) { - final Number v = getNumber(); - if (v == null) { - return null; - } - return longToTimestamp(v.longValue(), calendar); - } - - @Override public String getString() { - final Number v = getNumber(); - if (v == null) { - return null; - } - return timeAsString(v.intValue(), null); - } - } - - /** - * Accessor that assumes that the underlying value is a TIMESTAMP, - * in its default representation {@code long}; - * corresponds to {@link java.sql.Types#TIMESTAMP}. - */ - private static class TimestampFromNumberAccessor extends NumberAccessor { - private final Calendar localCalendar; - - public TimestampFromNumberAccessor(Getter getter, Calendar localCalendar) { - super(getter, 0); - this.localCalendar = localCalendar; - } - - @Override public Object getObject() { - return getTimestamp(localCalendar); - } - - @Override public Timestamp getTimestamp(Calendar calendar) { - final Number v = getNumber(); - if (v == null) { - return null; - } - return longToTimestamp(v.longValue(), calendar); - } - - @Override public Date getDate(Calendar calendar) { - final Timestamp timestamp = getTimestamp(calendar); - if (timestamp == null) { - return null; - } - return new Date(timestamp.getTime()); - } - - @Override public Time getTime(Calendar calendar) { - final Timestamp timestamp = getTimestamp(calendar); - if (timestamp == null) { - return null; - } - return new Time( - DateTimeUtils.floorMod(timestamp.getTime(), - DateTimeUtils.MILLIS_PER_DAY)); - } - - @Override public String getString() { - final Number v = getNumber(); - if (v == null) { - return null; - } - return timestampAsString(v.longValue(), null); - } - } - - /** - * Accessor that assumes that the underlying value is a DATE, - * represented as a java.sql.Date; - * corresponds to {@link java.sql.Types#DATE}. - */ - private static class DateAccessor extends ObjectAccessor { - public DateAccessor(Getter getter) { - super(getter); - } - - @Override public Date getDate(Calendar calendar) { - java.sql.Date date = (Date) getObject(); - if (date == null) { - return null; - } - if (calendar != null) { - long v = date.getTime(); - v -= calendar.getTimeZone().getOffset(v); - date = new Date(v); - } - return date; - } - - @Override public String getString() { - final int v = getInt(); - if (v == 0 && wasNull()) { - return null; - } - return dateAsString(v, null); - } - - @Override public long getLong() { - Date date = getDate(null); - return date == null - ? 0L - : (date.getTime() / DateTimeUtils.MILLIS_PER_DAY); - } - } - - /** - * Accessor that assumes that the underlying value is a TIME, - * represented as a java.sql.Time; - * corresponds to {@link java.sql.Types#TIME}. - */ - private static class TimeAccessor extends ObjectAccessor { - public TimeAccessor(Getter getter) { - super(getter); - } - - @Override public Time getTime(Calendar calendar) { - Time date = (Time) getObject(); - if (date == null) { - return null; - } - if (calendar != null) { - long v = date.getTime(); - v -= calendar.getTimeZone().getOffset(v); - date = new Time(v); - } - return date; - } - - @Override public String getString() { - final int v = getInt(); - if (v == 0 && wasNull()) { - return null; - } - return timeAsString(v, null); - } - - @Override public long getLong() { - Time time = getTime(null); - return time == null ? 0L - : (time.getTime() % DateTimeUtils.MILLIS_PER_DAY); - } - } - - /** - * Accessor that assumes that the underlying value is a TIMESTAMP, - * represented as a java.sql.Timestamp; - * corresponds to {@link java.sql.Types#TIMESTAMP}. - */ - private static class TimestampAccessor extends ObjectAccessor { - public TimestampAccessor(Getter getter) { - super(getter); - } - - @Override public Timestamp getTimestamp(Calendar calendar) { - Timestamp timestamp = (Timestamp) getObject(); - if (timestamp == null) { - return null; - } - if (calendar != null) { - long v = timestamp.getTime(); - v -= calendar.getTimeZone().getOffset(v); - timestamp = new Timestamp(v); - } - return timestamp; - } - - @Override public Date getDate(Calendar calendar) { - final Timestamp timestamp = getTimestamp(calendar); - if (timestamp == null) { - return null; - } - return new Date(timestamp.getTime()); - } - - @Override public Time getTime(Calendar calendar) { - final Timestamp timestamp = getTimestamp(calendar); - if (timestamp == null) { - return null; - } - return new Time( - DateTimeUtils.floorMod(timestamp.getTime(), - DateTimeUtils.MILLIS_PER_DAY)); - } - - @Override public String getString() { - final long v = getLong(); - if (v == 0 && wasNull()) { - return null; - } - return timestampAsString(v, null); - } - - @Override public long getLong() { - Timestamp timestamp = getTimestamp(null); - return timestamp == null ? 0 : timestamp.getTime(); - } - } - - /** - * Accessor that assumes that the underlying value is a TIMESTAMP, - * represented as a java.util.Date; - * corresponds to {@link java.sql.Types#TIMESTAMP}. - */ - private static class TimestampFromUtilDateAccessor extends ObjectAccessor { - private final Calendar localCalendar; - - public TimestampFromUtilDateAccessor(Getter getter, - Calendar localCalendar) { - super(getter); - this.localCalendar = localCalendar; - } - - @Override public Timestamp getTimestamp(Calendar calendar) { - java.util.Date date = (java.util.Date) getObject(); - if (date == null) { - return null; - } - long v = date.getTime(); - if (calendar != null) { - v -= calendar.getTimeZone().getOffset(v); - } - return new Timestamp(v); - } - - @Override public Date getDate(Calendar calendar) { - final Timestamp timestamp = getTimestamp(calendar); - if (timestamp == null) { - return null; - } - return new Date(timestamp.getTime()); - } - - @Override public Time getTime(Calendar calendar) { - final Timestamp timestamp = getTimestamp(calendar); - if (timestamp == null) { - return null; - } - return new Time( - DateTimeUtils.floorMod(timestamp.getTime(), - DateTimeUtils.MILLIS_PER_DAY)); - } - - @Override public String getString() { - java.util.Date date = (java.util.Date) getObject(); - if (date == null) { - return null; - } - return timestampAsString(date.getTime(), null); - } - - @Override public long getLong() { - Timestamp timestamp = getTimestamp(localCalendar); - return timestamp == null ? 0 : timestamp.getTime(); - } - } - - /** - * Accessor that assumes that the underlying value is a {@code int}; - * corresponds to {@link java.sql.Types#OTHER}. - */ - private static class IntervalYearMonthAccessor extends IntAccessor { - private final TimeUnitRange range; - - public IntervalYearMonthAccessor(Getter getter, TimeUnitRange range) { - super(getter); - this.range = range; - } - - @Override public String getString() { - final int v = getInt(); - if (v == 0 && wasNull()) { - return null; - } - return DateTimeUtils.intervalYearMonthToString(v, range); - } - } - - /** - * Accessor that assumes that the underlying value is a {@code long}; - * corresponds to {@link java.sql.Types#OTHER}. - */ - private static class IntervalDayTimeAccessor extends LongAccessor { - private final TimeUnitRange range; - private final int scale; - - public IntervalDayTimeAccessor(Getter getter, TimeUnitRange range, - int scale) { - super(getter); - this.range = range; - this.scale = scale; - } - - @Override public String getString() { - final long v = getLong(); - if (v == 0 && wasNull()) { - return null; - } - return DateTimeUtils.intervalDayTimeToString(v, range, scale); - } - } - - /** - * Accessor that assumes that the underlying value is an ARRAY; - * corresponds to {@link java.sql.Types#ARRAY}. - */ - static class ArrayAccessor extends AccessorImpl { - final ColumnMetaData.AvaticaType componentType; - final Accessor componentAccessor; - final SlotGetter componentSlotGetter; - final ArrayImpl.Factory factory; - - public ArrayAccessor(Getter getter, - ColumnMetaData.AvaticaType componentType, Accessor componentAccessor, - SlotGetter componentSlotGetter, ArrayImpl.Factory factory) { - super(getter); - this.componentType = componentType; - this.componentAccessor = componentAccessor; - this.componentSlotGetter = componentSlotGetter; - this.factory = factory; - } - - @Override public Object getObject() { - final Object object = super.getObject(); - if (object == null || object instanceof List) { - return object; - } - // The object can be java array in case of user-provided class for row - // storage. - return AvaticaUtils.primitiveList(object); - } - - @Override public Array getArray() { - final List list = (List) getObject(); - if (list == null) { - return null; - } - return new ArrayImpl(list, this); - } - - @Override public String getString() { - final Array array = getArray(); - return array == null ? null : array.toString(); - } - } - - /** - * Accessor that assumes that the underlying value is a STRUCT; - * corresponds to {@link java.sql.Types#STRUCT}. - */ - private static class StructAccessor extends AccessorImpl { - private final List<Accessor> fieldAccessors; - - public StructAccessor(Getter getter, List<Accessor> fieldAccessors) { - super(getter); - this.fieldAccessors = fieldAccessors; - } - - @Override public Object getObject() { - return getStruct(); - } - - @Override public Struct getStruct() { - final Object o = super.getObject(); - if (o == null) { - return null; - } else if (o instanceof List) { - return new StructImpl((List) o); - } else { - final List<Object> list = new ArrayList<>(); - for (Accessor fieldAccessor : fieldAccessors) { - try { - list.add(fieldAccessor.getObject()); - } catch (SQLException e) { - throw new RuntimeException(e); - } - } - return new StructImpl(list); - } - } - } - - /** - * Accessor that assumes that the underlying value is an OBJECT; - * corresponds to {@link java.sql.Types#JAVA_OBJECT}. - */ - private static class ObjectAccessor extends AccessorImpl { - public ObjectAccessor(Getter getter) { - super(getter); - } - } - - /** Gets a value from a particular field of the current record of this - * cursor. */ - protected interface Getter { - Object getObject(); - - boolean wasNull(); - } - - /** Abstract implementation of {@link Getter}. */ - protected abstract class AbstractGetter implements Getter { - public boolean wasNull() { - return wasNull[0]; - } - } - - /** Implementation of {@link Getter} that returns the current contents of - * a mutable slot. */ - public class SlotGetter implements Getter { - public Object slot; - - public Object getObject() { - return slot; - } - - public boolean wasNull() { - return slot == null; - } - } - - /** Implementation of {@link Getter} that returns the value of a given field - * of the current contents of another getter. */ - public class StructGetter implements Getter { - public final Getter getter; - private final ColumnMetaData columnMetaData; - - public StructGetter(Getter getter, ColumnMetaData columnMetaData) { - this.getter = getter; - this.columnMetaData = columnMetaData; - } - - public Object getObject() { - final Object o = getter.getObject(); - if (o instanceof Object[]) { - Object[] objects = (Object[]) o; - return objects[columnMetaData.ordinal]; - } - try { - final Field field = o.getClass().getField(columnMetaData.label); - return field.get(getter.getObject()); - } catch (IllegalAccessException | NoSuchFieldException e) { - throw new RuntimeException(e); - } - } - - public boolean wasNull() { - return getObject() == null; - } - } -} - -// End AbstractCursor.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java ---------------------------------------------------------------------- diff --git a/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java b/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java deleted file mode 100644 index b2d5ae9..0000000 --- a/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayImpl.java +++ /dev/null @@ -1,204 +0,0 @@ -/* - * 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.util; - -import org.apache.calcite.avatica.AvaticaUtils; -import org.apache.calcite.avatica.ColumnMetaData; - -import java.sql.Array; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** Implementation of JDBC {@link Array}. */ -public class ArrayImpl implements Array { - private final List list; - private final AbstractCursor.ArrayAccessor accessor; - - public ArrayImpl(List list, AbstractCursor.ArrayAccessor accessor) { - this.list = list; - this.accessor = accessor; - } - - public String getBaseTypeName() throws SQLException { - return accessor.componentType.name; - } - - public int getBaseType() throws SQLException { - return accessor.componentType.id; - } - - public Object getArray() throws SQLException { - return getArray(list); - } - - @Override public String toString() { - final Iterator iterator = list.iterator(); - if (!iterator.hasNext()) { - return "[]"; - } - final StringBuilder buf = new StringBuilder("["); - for (;;) { - accessor.componentSlotGetter.slot = iterator.next(); - try { - append(buf, accessor.componentAccessor.getString()); - } catch (SQLException e) { - throw new RuntimeException(e); - } - accessor.componentSlotGetter.slot = null; - if (!iterator.hasNext()) { - return buf.append("]").toString(); - } - buf.append(", "); - } - } - - private void append(StringBuilder buf, Object o) { - if (o == null) { - buf.append("null"); - } else if (o.getClass().isArray()) { - append(buf, AvaticaUtils.primitiveList(o)); - } else { - buf.append(o); - } - } - - /** - * Converts a list into an array. - * - * <p>If the elements of the list are primitives, converts to an array of - * primitives (e.g. {@code boolean[]}.</p> - * - * @param list List of objects - * - * @return array - * @throws ClassCastException if any element is not of the box type - * @throws NullPointerException if any element is null - */ - @SuppressWarnings("unchecked") - protected Object getArray(List list) throws SQLException { - int i = 0; - switch (accessor.componentType.rep) { - case PRIMITIVE_DOUBLE: - final double[] doubles = new double[list.size()]; - for (double v : (List<Double>) list) { - doubles[i++] = v; - } - return doubles; - case PRIMITIVE_FLOAT: - final float[] floats = new float[list.size()]; - for (float v : (List<Float>) list) { - floats[i++] = v; - } - return floats; - case PRIMITIVE_INT: - final int[] ints = new int[list.size()]; - for (int v : (List<Integer>) list) { - ints[i++] = v; - } - return ints; - case PRIMITIVE_LONG: - final long[] longs = new long[list.size()]; - for (long v : (List<Long>) list) { - longs[i++] = v; - } - return longs; - case PRIMITIVE_SHORT: - final short[] shorts = new short[list.size()]; - for (short v : (List<Short>) list) { - shorts[i++] = v; - } - return shorts; - case PRIMITIVE_BOOLEAN: - final boolean[] booleans = new boolean[list.size()]; - for (boolean v : (List<Boolean>) list) { - booleans[i++] = v; - } - return booleans; - case PRIMITIVE_BYTE: - final byte[] bytes = new byte[list.size()]; - for (byte v : (List<Byte>) list) { - bytes[i++] = v; - } - return bytes; - case PRIMITIVE_CHAR: - final char[] chars = new char[list.size()]; - for (char v : (List<Character>) list) { - chars[i++] = v; - } - return chars; - default: - // fall through - } - final Object[] objects = list.toArray(); - switch (accessor.componentType.id) { - case Types.ARRAY: - final AbstractCursor.ArrayAccessor componentAccessor = - (AbstractCursor.ArrayAccessor) accessor.componentAccessor; - for (i = 0; i < objects.length; i++) { - objects[i] = new ArrayImpl((List) objects[i], componentAccessor); - } - } - return objects; - } - - public Object getArray(Map<String, Class<?>> map) throws SQLException { - throw new UnsupportedOperationException(); // TODO - } - - public Object getArray(long index, int count) throws SQLException { - return getArray(list.subList((int) index, count)); - } - - public Object getArray(long index, int count, Map<String, Class<?>> map) - throws SQLException { - throw new UnsupportedOperationException(); // TODO - } - - public ResultSet getResultSet() throws SQLException { - return accessor.factory.create(accessor.componentType, list); - } - - public ResultSet getResultSet(Map<String, Class<?>> map) - throws SQLException { - throw new UnsupportedOperationException(); // TODO - } - - public ResultSet getResultSet(long index, int count) throws SQLException { - throw new UnsupportedOperationException(); // TODO - } - - public ResultSet getResultSet(long index, int count, - Map<String, Class<?>> map) throws SQLException { - throw new UnsupportedOperationException(); // TODO - } - - public void free() throws SQLException { - // nothing to do - } - - /** Factory that can create a result set based on a list of values. */ - public interface Factory { - ResultSet create(ColumnMetaData.AvaticaType elementType, - Iterable<Object> iterable); - } -} - -// End ArrayImpl.java http://git-wip-us.apache.org/repos/asf/calcite/blob/5cee486f/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayIteratorCursor.java ---------------------------------------------------------------------- diff --git a/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayIteratorCursor.java b/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayIteratorCursor.java deleted file mode 100644 index 0477984..0000000 --- a/avatica/src/main/java/org/apache/calcite/avatica/util/ArrayIteratorCursor.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.util; - -import java.util.Iterator; - -/** - * Implementation of {@link Cursor} on top of an - * {@link java.util.Iterator} that - * returns an array of {@link Object} for each row. - */ -public class ArrayIteratorCursor extends IteratorCursor<Object[]> { - /** - * Creates an ArrayEnumeratorCursor. - * - * @param iterator Iterator - */ - public ArrayIteratorCursor(Iterator<Object[]> iterator) { - super(iterator); - } - - protected Getter createGetter(int ordinal) { - return new ArrayGetter(ordinal); - } -} - -// End ArrayIteratorCursor.java
