protected Object convertDecimal(Column column, Field fieldDefn, Object data, DecimalMode mode) { SpecialValueDecimal value; BigDecimal newDecimal; if (data instanceof SpecialValueDecimal) { value = (SpecialValueDecimal)data; if (!value.getDecimalValue().isPresent()) { return SpecialValueDecimal.fromLogical(value, mode, column.name()); } } else { final Object o = toBigDecimal(column, fieldDefn, data); if (o == null || !(o instanceof BigDecimal)) { return o; } value = new SpecialValueDecimal((BigDecimal)o); } newDecimal = value.getDecimalValue().get(); if (column.scale().get() > newDecimal.scale()) { newDecimal = newDecimal.setScale(column.scale().get()); } if (isVariableScaleDecimal(column) && mode == DecimalMode.PRECISE) { newDecimal = newDecimal.stripTrailingZeros(); if (newDecimal.scale() < 0) { newDecimal = newDecimal.setScale(0); } return VariableScaleDecimal.fromLogical(fieldDefn.schema(), new SpecialValueDecimal(newDecimal)); } return SpecialValueDecimal.fromLogical(new SpecialValueDecimal(newDecimal), mode, column.name()); }
private SchemaBuilder numericSchema(Column column) { if (decimalMode == DecimalMode.PRECISE && isVariableScaleDecimal(column)) { return VariableScaleDecimal.builder(); } return SpecialValueDecimal.builder(decimalMode, column.length(), column.scale().get()); }
public static Object fromLogical(SpecialValueDecimal value, DecimalMode mode, String columnName) { if (value.getDecimalValue().isPresent()) { switch (mode) { case DOUBLE: return value.getDecimalValue().get().doubleValue(); case PRECISE: return value.getDecimalValue().get(); case STRING: return value.getDecimalValue().get().toString(); } throw new IllegalArgumentException("Unknown decimalMode"); } // special values (NaN, Infinity) can only be expressed when using "string" encoding switch (mode) { case STRING: return value.toString(); case DOUBLE: return value.toDouble(); default: throw new ConnectException("Got a special value (NaN/Infinity) for Decimal type in column " + columnName + " but current mode does not handle it. " + "If you need to support it then set decimal handling mode to 'string'."); } } }
/** * Converts a value object for an expected JDBC type of {@link Types#NUMERIC}. * * @param column the column definition describing the {@code data} value; never null * @param fieldDefn the field definition; never null * @param data the data object to be converted into a {@link Date Kafka Connect date} type; never null * @return the converted value, or null if the conversion could not be made and the column allows nulls * @throws IllegalArgumentException if the value could not be converted but the column does not allow nulls */ protected Object convertDecimal(Column column, Field fieldDefn, Object data) { if (data instanceof SpecialValueDecimal) { return SpecialValueDecimal.fromLogical((SpecialValueDecimal)data, decimalMode, column.name()); } Object decimal = toBigDecimal(column, fieldDefn, data); if (decimal instanceof BigDecimal) { return SpecialValueDecimal.fromLogical(new SpecialValueDecimal((BigDecimal)decimal), decimalMode, column.name()); } return decimal; }
/** * Factory method for creating instances from numbers in string format * * @param decimal a string containing valid decimal number * @return {@link SpecialValueDecimal} containing converted {@link BigDecimal} */ public static SpecialValueDecimal valueOf(String decimal) { return new SpecialValueDecimal(new BigDecimal(decimal)); }
@Test public void testVariableScaleDecimal() { final BigDecimal testValue = new BigDecimal("138.456"); final Struct struct = VariableScaleDecimal.fromLogical(VariableScaleDecimal.schema(), new SpecialValueDecimal(testValue)); final BigDecimal decodedValue = VariableScaleDecimal.toLogical(struct).getDecimalValue().get(); assertEquals("Number should be same after serde", testValue, decodedValue); } }
case "decimal": if (rawValue.isInteger()) { return new SpecialValueDecimal(new BigDecimal(rawValue.asInteger())); return new SpecialValueDecimal(new BigDecimal(rawValue.asLong())); return new SpecialValueDecimal(new BigDecimal(rawValue.asBigInteger())); return SpecialValueDecimal.valueOf(rawValue.asString());
/** * Converts a value from its logical format to its encoded format - a struct containing * the scale of the number and a binary representation of the number. * * @param schema of the encoded value * @param value the value or the decimal * * @return the encoded value */ public static Struct fromLogical(Schema schema, SpecialValueDecimal value) { return fromLogical(schema, value.getDecimalValue().orElse(null)); }
/** * Converts a value object for an expected JDBC type of {@link Types#DOUBLE}. * * @param column the column definition describing the {@code data} value; never null * @param fieldDefn the field definition; never null * @param data the data object to be converted into a {@link Date Kafka Connect date} type; never null * @return the converted value, or null if the conversion could not be made and the column allows nulls * @throws IllegalArgumentException if the value could not be converted but the column does not allow nulls */ protected Object convertDouble(Column column, Field fieldDefn, Object data) { return convertValue(column, fieldDefn, data, 0.0d, (r) -> { if (data instanceof Double) { r.deliver(data); } else if (data instanceof Number) { // Includes BigDecimal and other numeric values ... Number value = (Number) data; r.deliver(Double.valueOf(value.doubleValue())); } else if (data instanceof SpecialValueDecimal) { r.deliver(((SpecialValueDecimal)data).toDouble()); } else if (data instanceof Boolean) { r.deliver(NumberConversions.getDouble((Boolean) data)); } }); }
/** * Decodes the encoded value - see {@link #fromLogical(Schema, BigDecimal)} for encoding format * * @param value the encoded value * @return the decoded value */ public static SpecialValueDecimal toLogical(final Struct value) { return new SpecialValueDecimal(new BigDecimal(new BigInteger(value.getBytes(VALUE_FIELD)), value.getInt32(SCALE_FIELD))); } }
@Test public void testVariableScaleDecimal() { final BigDecimal testValue = new BigDecimal("138.456"); final Struct struct = VariableScaleDecimal.fromLogical(VariableScaleDecimal.schema(), new SpecialValueDecimal(testValue)); final BigDecimal decodedValue = VariableScaleDecimal.toLogical(struct).getDecimalValue().get(); assertEquals("Number should be same after serde", testValue, decodedValue); } }
/** * Converts a value object for an expected JDBC type of {@link Types#NUMERIC}. * * @param column the column definition describing the {@code data} value; never null * @param fieldDefn the field definition; never null * @param data the data object to be converted into a {@link Date Kafka Connect date} type; never null * @return the converted value, or null if the conversion could not be made and the column allows nulls * @throws IllegalArgumentException if the value could not be converted but the column does not allow nulls */ protected Object convertDecimal(Column column, Field fieldDefn, Object data) { if (data instanceof SpecialValueDecimal) { return SpecialValueDecimal.fromLogical((SpecialValueDecimal)data, decimalMode, column.name()); } Object decimal = toBigDecimal(column, fieldDefn, data); if (decimal instanceof BigDecimal) { return SpecialValueDecimal.fromLogical(new SpecialValueDecimal((BigDecimal)decimal), decimalMode, column.name()); } return decimal; }
case "decimal": if (rawValue.isInteger()) { return new SpecialValueDecimal(new BigDecimal(rawValue.asInteger())); return new SpecialValueDecimal(new BigDecimal(rawValue.asLong())); return new SpecialValueDecimal(new BigDecimal(rawValue.asBigInteger())); return SpecialValueDecimal.valueOf(rawValue.asString());
/** * Converts a value from its logical format to its encoded format - a struct containing * the scale of the number and a binary representation of the number. * * @param schema of the encoded value * @param value the value or the decimal * * @return the encoded value */ public static Struct fromLogical(Schema schema, SpecialValueDecimal value) { return fromLogical(schema, value.getDecimalValue().orElse(null)); }
/** * Converts a value object for an expected JDBC type of {@link Types#DOUBLE}. * * @param column the column definition describing the {@code data} value; never null * @param fieldDefn the field definition; never null * @param data the data object to be converted into a {@link Date Kafka Connect date} type; never null * @return the converted value, or null if the conversion could not be made and the column allows nulls * @throws IllegalArgumentException if the value could not be converted but the column does not allow nulls */ protected Object convertDouble(Column column, Field fieldDefn, Object data) { return convertValue(column, fieldDefn, data, 0.0d, (r) -> { if (data instanceof Double) { r.deliver(data); } else if (data instanceof Number) { // Includes BigDecimal and other numeric values ... Number value = (Number) data; r.deliver(Double.valueOf(value.doubleValue())); } else if (data instanceof SpecialValueDecimal) { r.deliver(((SpecialValueDecimal)data).toDouble()); } else if (data instanceof Boolean) { r.deliver(NumberConversions.getDouble((Boolean) data)); } }); }
protected Object convertDecimal(Column column, Field fieldDefn, Object data, DecimalMode mode) { SpecialValueDecimal value; BigDecimal newDecimal; if (data instanceof SpecialValueDecimal) { value = (SpecialValueDecimal)data; if (!value.getDecimalValue().isPresent()) { return SpecialValueDecimal.fromLogical(value, mode, column.name()); } } else { final Object o = toBigDecimal(column, fieldDefn, data); if (o == null || !(o instanceof BigDecimal)) { return o; } value = new SpecialValueDecimal((BigDecimal)o); } newDecimal = value.getDecimalValue().get(); if (column.scale().get() > newDecimal.scale()) { newDecimal = newDecimal.setScale(column.scale().get()); } if (isVariableScaleDecimal(column) && mode == DecimalMode.PRECISE) { newDecimal = newDecimal.stripTrailingZeros(); if (newDecimal.scale() < 0) { newDecimal = newDecimal.setScale(0); } return VariableScaleDecimal.fromLogical(fieldDefn.schema(), new SpecialValueDecimal(newDecimal)); } return SpecialValueDecimal.fromLogical(new SpecialValueDecimal(newDecimal), mode, column.name()); }
return value.isPresent() ? value.get() : new SpecialValueDecimal(rs.getBigDecimal(colIdx));
public static Object fromLogical(SpecialValueDecimal value, DecimalMode mode, String columnName) { if (value.getDecimalValue().isPresent()) { switch (mode) { case DOUBLE: return value.getDecimalValue().get().doubleValue(); case PRECISE: return value.getDecimalValue().get(); case STRING: return value.getDecimalValue().get().toString(); } throw new IllegalArgumentException("Unknown decimalMode"); } // special values (NaN, Infinity) can only be expressed when using "string" encoding switch (mode) { case STRING: return value.toString(); case DOUBLE: return value.toDouble(); default: throw new ConnectException("Got a special value (NaN/Infinity) for Decimal type in column " + columnName + " but current mode does not handle it. " + "If you need to support it then set decimal handling mode to 'string'."); } } }
@Override public SchemaBuilder schemaBuilder(Column column) { switch (column.jdbcType()) { // Numeric integers case Types.TINYINT: // values are an 8-bit unsigned integer value between 0 and 255, we thus need to store it in short int return SchemaBuilder.int16(); // Floating point case microsoft.sql.Types.SMALLMONEY: case microsoft.sql.Types.MONEY: return SpecialValueDecimal.builder(decimalMode, column.length(), column.scale().get()); case microsoft.sql.Types.DATETIMEOFFSET: return ZonedTimestamp.builder(); default: return super.schemaBuilder(column); } }
return PostgresValueConverter.toSpecialValue(s).orElseGet(() -> new SpecialValueDecimal(new BigDecimal(s)));