protected List<Object> getParameterJDBCValues() { List<TypedValue> typeValues = getParameterValues(); List<Object> jdbcValues = new ArrayList<Object>(typeValues.size()); for (TypedValue typeValue : typeValues) { jdbcValues.add(typeValue.toJdbc(getCalendar())); } return jdbcValues; }
private TypedValue wrap(ColumnMetaData.Rep rep, Object o, Calendar calendar) { return TypedValue.ofJdbc(rep, o, calendar); }
/** 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 local representation. */ public static TypedValue ofLocal(ColumnMetaData.Rep rep, Object value) { return new TypedValue(rep, localToSerial(rep, value)); }
@Test public void testArrays() { List<Object> serialObj = Arrays.<Object>asList(1, 2, 3, 4); ArrayImpl.Factory factory = new ArrayFactoryImpl(Unsafe.localCalendar().getTimeZone()); ScalarType scalarType = ColumnMetaData.scalar(Types.INTEGER, "INTEGER", Rep.INTEGER); Array a1 = factory.createArray(scalarType, serialObj); TypedValue tv1 = TypedValue.ofJdbc(Rep.ARRAY, a1, Unsafe.localCalendar()); Object jdbcObj = tv1.toJdbc(Unsafe.localCalendar()); assertTrue("The JDBC object is an " + jdbcObj.getClass(), jdbcObj instanceof Array); Object localObj = tv1.toLocal(); assertTrue("The local object is an " + localObj.getClass(), localObj instanceof List); Common.TypedValue protoTv1 = tv1.toProto(); assertEquals(serialObj.size(), protoTv1.getArrayValueCount()); TypedValue tv1Copy = TypedValue.fromProto(protoTv1); Object jdbcObjCopy = tv1Copy.toJdbc(Unsafe.localCalendar()); assertTrue("The JDBC object is an " + jdbcObjCopy.getClass(), jdbcObjCopy instanceof Array); Object localObjCopy = tv1Copy.toLocal(); assertTrue("The local object is an " + localObjCopy.getClass(), localObjCopy instanceof List); } }
@Test public void testDecimal() { final BigDecimal decimal = new BigDecimal("1.2345"); final TypedValue decimalTypedValue = TypedValue.ofLocal(Rep.NUMBER, decimal); serializeAndEqualityCheck(decimalTypedValue); final Common.TypedValue protoTypedValue = decimalTypedValue.toProto(); assertEquals(Common.Rep.BIG_DECIMAL, protoTypedValue.getType()); final String strValue = protoTypedValue.getStringValue(); assertNotNull(strValue); assertEquals(decimal.toPlainString(), strValue); }
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)); case ARRAY: if (null == value) { } else if (o instanceof TypedValue) { copy.add(((TypedValue) o).toJdbc(calendar)); } else { copy.add(serialToJdbc(componentRep, null, o, calendar)); return new ArrayFactoryImpl(calendar.getTimeZone()).createArray(elementType, copy); default: return serialToLocal(type, value);
@Test public void testLegacyDecimalParsing() { final BigDecimal decimal = new BigDecimal("123451234512345"); final Calendar calendar = DateTimeUtils.calendar(); // CALCITE-1103 Decimals were (incorrectly) getting serialized as normal "numbers" which // caused them to use the numberValue field. TypedValue should still be able to handle // values like this (but large values will be truncated and return bad values). Common.TypedValue oldProtoStyle = Common.TypedValue.newBuilder().setType(Common.Rep.NUMBER) .setNumberValue(decimal.longValue()).build(); TypedValue fromProtoTv = TypedValue.fromProto(oldProtoStyle); Object o = fromProtoTv.toJdbc(calendar); assertEquals(decimal, o); }
static Object deserializeScalarValue(Common.TypedValue protoElement) { // ByteString is a single case where TypedValue is representing the data differently // (in its "local" form) than Frame does. We need to unwrap the Base64 encoding. if (Common.Rep.BYTE_STRING == protoElement.getType()) { // Protobuf is sending native bytes (not b64) across the wire. B64 bytes is only for // TypedValue's benefit return protoElement.getBytesValue().toByteArray(); } // Again, let TypedValue deserialize things for us. return TypedValue.fromProto(protoElement).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; }
static Common.TypedValue serializeScalar(Object element) { final Common.TypedValue.Builder valueBuilder = Common.TypedValue.newBuilder(); // Let TypedValue handle the serialization for us. TypedValue.toProto(valueBuilder, element); return valueBuilder.build(); }
@JsonCreator public static TypedValue create(@JsonProperty("type") String type, @JsonProperty("value") Object value) { if (value == null) { return EXPLICIT_NULL; } ColumnMetaData.Rep rep = ColumnMetaData.Rep.valueOf(type); return ofLocal(rep, serialToLocal(rep, value)); }
writeToProtoWithType(builder, o, Common.Rep.BYTE); return Common.Rep.BYTE; } else if (o instanceof Short) { writeToProtoWithType(builder, o, Common.Rep.SHORT); return Common.Rep.SHORT; } else if (o instanceof Integer) { writeToProtoWithType(builder, o, Common.Rep.INTEGER); return Common.Rep.INTEGER; } else if (o instanceof Long) { writeToProtoWithType(builder, o, Common.Rep.LONG); return Common.Rep.LONG; } else if (o instanceof Double) { writeToProtoWithType(builder, o, Common.Rep.DOUBLE); return Common.Rep.DOUBLE; } else if (o instanceof Float) { writeToProtoWithType(builder, ((Float) o).longValue(), Common.Rep.FLOAT); return Common.Rep.FLOAT; } else if (o instanceof BigDecimal) { writeToProtoWithType(builder, o, Common.Rep.BIG_DECIMAL); return Common.Rep.BIG_DECIMAL; writeToProtoWithType(builder, o, Common.Rep.STRING); return Common.Rep.STRING; } else if (o instanceof Character) { writeToProtoWithType(builder, o.toString(), Common.Rep.CHARACTER); return Common.Rep.CHARACTER; writeToProtoWithType(builder, o, Common.Rep.BYTE_STRING); return Common.Rep.BYTE_STRING;
/** * Constructs a {@link TypedValue} from the protocol buffer representation. * * @param proto The protobuf Typedvalue * @return A {@link TypedValue} instance */ public static TypedValue fromProto(Common.TypedValue proto) { ColumnMetaData.Rep rep = ColumnMetaData.Rep.fromProto(proto.getType()); ColumnMetaData.Rep componentRep = ColumnMetaData.Rep.fromProto(proto.getComponentType()); Object value = getSerialFromProto(proto); return new TypedValue(rep, componentRep, value); }
/** * Extracts the JDBC value from protobuf-TypedValue representation. * * @param protoValue Protobuf TypedValue * @param calendar Instance of a calendar * @return The JDBC representation of this TypedValue */ public static Object protoToJdbc(Common.TypedValue protoValue, Calendar calendar) { Object o = getSerialFromProto(Objects.requireNonNull(protoValue)); // Shortcircuit the null if (null == o) { return o; } return serialToJdbc(Rep.fromProto(protoValue.getType()), null, o, calendar); }
@Test public void testBase64() { byte[] bytes = "qwertyasdf".getBytes(UTF_8); // Plain bytes get put into protobuf for simplicitly Common.TypedValue proto = Common.TypedValue.newBuilder().setBytesValue( com.google.protobuf.ByteString.copyFrom(bytes)) .setType(Common.Rep.BYTE_STRING).build(); // But we should get back a b64-string to make sure TypedValue doesn't get confused. Object deserializedObj = TypedValue.getSerialFromProto(proto); assertThat(deserializedObj, is(instanceOf(String.class))); assertEquals(new ByteString(bytes).toBase64String(), (String) deserializedObj); // But we should get a non-b64 byte array as the JDBC representation deserializedObj = TypedValue.protoToJdbc(proto, DateTimeUtils.calendar()); assertThat(deserializedObj, is(instanceOf(byte[].class))); assertArrayEquals(bytes, (byte[]) deserializedObj); }
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); } }