Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion jdbc/src/main/java/tech/ydb/jdbc/common/ColumnInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public ColumnInfo(String name, Type type) {
this.isOptional = desc.isOptional();
this.ydbType = desc.ydbType();

this.isTimestamp = ydbType == PrimitiveType.Timestamp;
this.isTimestamp = ydbType == PrimitiveType.Timestamp || ydbType == PrimitiveType.Timestamp64;
this.isNumber = ydbType == PrimitiveType.Int8 || ydbType == PrimitiveType.Uint8
|| ydbType == PrimitiveType.Int16 || ydbType == PrimitiveType.Uint16
|| ydbType == PrimitiveType.Int32 || ydbType == PrimitiveType.Uint32
Expand Down
84 changes: 82 additions & 2 deletions jdbc/src/main/java/tech/ydb/jdbc/common/MappingGetters.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@
import tech.ydb.table.values.Value;

public class MappingGetters {
private MappingGetters() { }
private MappingGetters() {
}

@SuppressWarnings("Convert2Lambda")
static Getters buildGetters(Type type) {
Expand Down Expand Up @@ -168,6 +169,14 @@ private static ValueToString valueToString(PrimitiveType id) {
return value -> String.valueOf(value.getTimestamp());
case Interval:
return value -> String.valueOf(value.getInterval());
case Date32:
return value -> String.valueOf(value.getDate32());
case Datetime64:
return value -> String.valueOf(value.getDatetime64());
case Timestamp64:
return value -> String.valueOf(value.getTimestamp64());
case Interval64:
return value -> String.valueOf(value.getInterval64());
case TzDate:
return value -> String.valueOf(value.getTzDate());
case TzDatetime:
Expand Down Expand Up @@ -376,6 +385,8 @@ private static ValueToInt valueToInt(PrimitiveType id) {
return value -> checkIntValue(id, value.getUint64());
case Date:
return value -> checkIntValue(id, value.getDate().toEpochDay());
case Date32:
return value -> checkIntValue(id, value.getDate32().toEpochDay());
default:
return castToIntNotSupported(id.name());
}
Expand Down Expand Up @@ -403,17 +414,25 @@ private static ValueToLong valueToLong(PrimitiveType id) {
return PrimitiveReader::getUint64;
case Date:
return value -> value.getDate().toEpochDay();
case Date32:
return value -> value.getDate32().toEpochDay();
case Datetime:
return value -> value.getDatetime().toEpochSecond(ZoneOffset.UTC);
case Datetime64:
return value -> value.getDatetime64().toEpochSecond(ZoneOffset.UTC);
case Timestamp:
return value -> value.getTimestamp().toEpochMilli();
case Timestamp64:
return value -> value.getTimestamp64().toEpochMilli();
case TzDate:
case TzDatetime:
case TzTimestamp:
ValueToInstant delegate = valueToInstant(id);
return value -> delegate.fromValue(value).toEpochMilli();
case Interval:
return value -> TimeUnit.NANOSECONDS.toMicros(value.getInterval().toNanos());
case Interval64:
return value -> TimeUnit.NANOSECONDS.toMicros(value.getInterval64().toNanos());
default:
return castToLongNotSupported(id.name());
}
Expand Down Expand Up @@ -515,6 +534,12 @@ private static ValueToInstant valueToInstant(PrimitiveType id) {
return ValueReader::getTimestamp;
case TzTimestamp:
return v -> v.getTzTimestamp().toInstant();
case Date32:
return v -> Instant.ofEpochSecond(v.getDate32().toEpochDay() * 24 * 60 * 60);
case Datetime64:
return v -> Instant.ofEpochSecond(v.getDatetime64().toEpochSecond(ZoneOffset.UTC));
case Timestamp64:
return ValueReader::getTimestamp64;
default:
return castToInstantNotSupported(id.name());
}
Expand Down Expand Up @@ -628,12 +653,16 @@ private static SqlType buildPrimitiveType(int sqlType, PrimitiveType id) {
case Double:
return new SqlType(sqlType, Double.class);
case Date:
case Date32:
return new SqlType(sqlType, LocalDate.class);
case Datetime:
case Datetime64:
return new SqlType(sqlType, LocalDateTime.class);
case Timestamp:
case Timestamp64:
return new SqlType(sqlType, Instant.class);
case Interval:
case Interval64:
return new SqlType(sqlType, Duration.class);
case TzDate:
case TzDatetime:
Expand Down Expand Up @@ -708,6 +737,14 @@ private static ValueToObject valueToObject(PrimitiveType id) {
return PrimitiveReader::getTzDatetime;
case TzTimestamp:
return PrimitiveReader::getTzTimestamp;
case Date32:
return PrimitiveReader::getDate32;
case Datetime64:
return PrimitiveReader::getDatetime64;
case Timestamp64:
return PrimitiveReader::getTimestamp64;
case Interval64:
return PrimitiveReader::getInterval64;
default:
// DyNumber
return value -> {
Expand Down Expand Up @@ -745,7 +782,7 @@ public <T> T fromValue(ValueReader reader, Class<T> clazz) throws SQLException {
}
}


@SuppressWarnings("MethodLength")
private static ValueToClass valueToClass(PrimitiveType id) {
ValueToClassBuilder builder = new ValueToClassBuilder(id);
switch (id) {
Expand Down Expand Up @@ -870,6 +907,49 @@ private static ValueToClass valueToClass(PrimitiveType id) {
return builder
.register(Duration.class, ValueReader::getInterval)
.build();
case Date32:
return builder
.register(long.class, v -> v.getDate32().toEpochDay())
.register(Long.class, v -> v.getDate32().toEpochDay())
.register(LocalDate.class, ValueReader::getDate32)
.register(LocalDateTime.class, v -> v.getDate32().atStartOfDay())
.register(java.sql.Date.class, v -> java.sql.Date.valueOf(v.getDate32()))
.register(java.sql.Timestamp.class,
v -> java.sql.Timestamp.valueOf(v.getDate32().atStartOfDay()))
.register(Instant.class, v -> v.getDate32().atStartOfDay(ZoneId.systemDefault()).toInstant())
.register(java.util.Date.class, v -> java.util.Date.from(
v.getDate32().atStartOfDay(ZoneId.systemDefault()).toInstant()))
.build();
case Datetime64:
return builder
.register(long.class, v -> v.getDatetime64().toEpochSecond(ZoneOffset.UTC))
.register(Long.class, v -> v.getDatetime64().toEpochSecond(ZoneOffset.UTC))
.register(LocalDate.class, v -> v.getDatetime64().toLocalDate())
.register(LocalDateTime.class, ValueReader::getDatetime64)
.register(java.sql.Date.class, v -> java.sql.Date.valueOf(v.getDatetime64().toLocalDate()))
.register(java.sql.Timestamp.class, v -> java.sql.Timestamp.valueOf(v.getDatetime64()))
.register(Instant.class, v -> v.getDatetime64().atZone(ZoneId.systemDefault()).toInstant())
.register(java.util.Date.class, v -> java.util.Date.from(
v.getDatetime64().atZone(ZoneId.systemDefault()).toInstant()))
.build();
case Timestamp64:
return builder
.register(long.class, v -> v.getTimestamp64().toEpochMilli())
.register(Long.class, v -> v.getTimestamp64().toEpochMilli())
.register(LocalDate.class, v -> v.getTimestamp64().atZone(ZoneId.systemDefault()).toLocalDate())
.register(LocalDateTime.class, v -> v.getTimestamp64()
.atZone(ZoneId.systemDefault()).toLocalDateTime())
.register(java.sql.Date.class, v -> java.sql.Date
.valueOf(v.getTimestamp64().atZone(ZoneId.systemDefault()).toLocalDate()))
.register(java.sql.Timestamp.class, v -> java.sql.Timestamp
.valueOf(v.getTimestamp64().atZone(ZoneId.systemDefault()).toLocalDateTime()))
.register(Instant.class, ValueReader::getTimestamp64)
.register(java.util.Date.class, v -> java.util.Date.from(v.getTimestamp64()))
.build();
case Interval64:
return builder
.register(Duration.class, ValueReader::getInterval64)
.build();
case TzDate:
return builder
.register(ZonedDateTime.class, ValueReader::getTzDate)
Expand Down
113 changes: 112 additions & 1 deletion jdbc/src/main/java/tech/ydb/jdbc/common/MappingSetters.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
public class MappingSetters {
private static final int DEFAULT_BUF_SIZE = 0x800;

private MappingSetters() { }
private MappingSetters() {
}

static Setters buildSetters(Type type) {
return buildToValueImpl(type);
Expand Down Expand Up @@ -97,6 +98,14 @@ private static Setters buildToValueImpl(Type type) {
return x -> PrimitiveValue.newTzDatetime(castAsZonedDateTime(id, x));
case TzTimestamp:
return x -> PrimitiveValue.newTzTimestamp(castAsZonedDateTime(id, x));
case Date32:
return x -> castToDate32(id, x);
case Datetime64:
return x -> castToDateTime64(id, x);
case Timestamp64:
return x -> castToTimestamp64(id, x);
case Interval64:
return x -> castToInterval64(id, x);
default:
return x -> {
throw castNotSupported(id, x);
Expand Down Expand Up @@ -502,6 +511,108 @@ private static PrimitiveValue castToTimestamp(PrimitiveType type, Object x) thro
throw castNotSupported(type, x);
}

private static PrimitiveValue castToInterval64(PrimitiveType type, Object x) throws SQLException {
if (x instanceof Duration) {
return PrimitiveValue.newInterval64((Duration) x);
} else if (x instanceof Long) {
return PrimitiveValue.newInterval64((Long) x);
} else if (x instanceof String) {
Duration parsed;
try {
parsed = Duration.parse((String) x);
} catch (DateTimeParseException e) {
throw castNotSupported(type, x, e);
}
return PrimitiveValue.newInterval64(parsed);
}
throw castNotSupported(type, x);
}

private static PrimitiveValue castToDate32(PrimitiveType type, Object x) throws SQLException {
if (x instanceof Instant) {
return PrimitiveValue.newDate32(((Instant) x).atZone(ZoneId.systemDefault()).toLocalDate());
} else if (x instanceof LocalDateTime) {
return PrimitiveValue.newDate32(((LocalDateTime) x).toLocalDate());
} else if (x instanceof LocalDate) {
return PrimitiveValue.newDate32((LocalDate) x);
} else if (x instanceof Integer) {
return PrimitiveValue.newDate32(LocalDate.ofEpochDay((Integer) x));
} else if (x instanceof Long) {
return PrimitiveValue.newDate32(LocalDate.ofEpochDay((Long) x));
} else if (x instanceof Timestamp) {
// Normalize date - use system timezone to detect correct date
Instant instant = Instant.ofEpochMilli(((Timestamp) x).getTime());
LocalDate ld = instant.atZone(ZoneId.systemDefault()).toLocalDate();
return PrimitiveValue.newDate32(ld);
} else if (x instanceof Date) {
// Normalize date - use system timezone to detect correct date
Instant instant = Instant.ofEpochMilli(((Date) x).getTime());
LocalDate ld = instant.atZone(ZoneId.systemDefault()).toLocalDate();
return PrimitiveValue.newDate32(ld);
} else if (x instanceof String) {
try {
return PrimitiveValue.newDate32(LocalDate.parse((String) x));
} catch (DateTimeParseException e) {
throw castNotSupported(type, x, e);
}
}
throw castNotSupported(type, x);
}

private static PrimitiveValue castToDateTime64(PrimitiveType type, Object x) throws SQLException {
if (x instanceof Instant) {
return PrimitiveValue.newDatetime64(((Instant) x).atZone(ZoneId.systemDefault()).toLocalDateTime());
} else if (x instanceof LocalDateTime) {
return PrimitiveValue.newDatetime64(((LocalDateTime) x));
} else if (x instanceof LocalDate) {
return PrimitiveValue.newDatetime64(((LocalDate) x).atStartOfDay());
} else if (x instanceof Long) {
return PrimitiveValue.newDatetime64(LocalDateTime.ofEpochSecond((Long) x, 0, ZoneOffset.UTC));
} else if (x instanceof Timestamp) {
// Normalize date - use system timezone to detect correct date
Instant instant = Instant.ofEpochMilli(((Timestamp) x).getTime());
LocalDateTime ldt = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
return PrimitiveValue.newDatetime64(ldt);
} else if (x instanceof Date) {
// Normalize date - use system timezone to detect correct date
Instant instant = Instant.ofEpochMilli(((Date) x).getTime());
LocalDate ld = instant.atZone(ZoneId.systemDefault()).toLocalDate();
return PrimitiveValue.newDatetime64(ld.atStartOfDay());
} else if (x instanceof String) {
try {
return PrimitiveValue.newDatetime64(LocalDateTime.parse((String) x));
} catch (DateTimeParseException e) {
throw castNotSupported(type, x, e);
}
}
throw castNotSupported(type, x);
}

private static PrimitiveValue castToTimestamp64(PrimitiveType type, Object x) throws SQLException {
if (x instanceof Instant) {
return PrimitiveValue.newTimestamp64((Instant) x);
} else if (x instanceof Long) {
return PrimitiveValue.newTimestamp64(Instant.ofEpochMilli((Long) x));
} else if (x instanceof LocalDate) {
return PrimitiveValue.newTimestamp64(((LocalDate) x).atStartOfDay().toInstant(ZoneOffset.UTC));
} else if (x instanceof LocalDateTime) {
long epochSeconds = ((LocalDateTime) x).toEpochSecond(ZoneOffset.UTC);
return PrimitiveValue.newTimestamp64(Instant.ofEpochSecond(epochSeconds));
} else if (x instanceof Timestamp) {
return PrimitiveValue.newTimestamp64(((Timestamp) x).toInstant());
} else if (x instanceof Date) {
Instant instant = ((Date) x).toLocalDate().atStartOfDay().toInstant(ZoneOffset.UTC);
return PrimitiveValue.newTimestamp64(instant);
} else if (x instanceof String) {
try {
return PrimitiveValue.newTimestamp64(Instant.parse((String) x));
} catch (DateTimeParseException e) {
throw castNotSupported(type, x, e);
}
}
throw castNotSupported(type, x);
}

private static DecimalValue validateValue(DecimalType type, DecimalValue value, Object x) throws SQLException {
if (value.isNan()) {
throw new SQLException(String.format(YdbConst.UNABLE_TO_CAST_TO_DECIMAL, type, toString(x), "NaN"));
Expand Down
21 changes: 19 additions & 2 deletions jdbc/src/main/java/tech/ydb/jdbc/impl/YdbTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ private YdbTypes() {
typeBySqlType.put(YdbConst.SQL_KIND_PRIMITIVE + 22, PrimitiveType.TzTimestamp);

typeBySqlType.put(YdbConst.SQL_KIND_PRIMITIVE + 23, PrimitiveType.JsonDocument);
typeBySqlType.put(YdbConst.SQL_KIND_PRIMITIVE + 24, PrimitiveType.DyNumber);

typeBySqlType.put(YdbConst.SQL_KIND_PRIMITIVE + 25, PrimitiveType.Date32);
typeBySqlType.put(YdbConst.SQL_KIND_PRIMITIVE + 26, PrimitiveType.Datetime64);
typeBySqlType.put(YdbConst.SQL_KIND_PRIMITIVE + 27, PrimitiveType.Timestamp64);
typeBySqlType.put(YdbConst.SQL_KIND_PRIMITIVE + 28, PrimitiveType.Interval64);

typeBySqlType.put(Types.VARCHAR, PrimitiveType.Text);
typeBySqlType.put(Types.BIGINT, PrimitiveType.Int64);
Expand Down Expand Up @@ -192,16 +198,19 @@ private int toSqlTypeImpl(Type type) {
case Int64:
case Uint64:
case Interval:
case Interval64:
return Types.BIGINT;
case Float:
return Types.FLOAT;
case Double:
return Types.DOUBLE;
case Date:
case Date32:
return Types.DATE;
case Datetime:
return Types.TIMESTAMP;
case Timestamp:
case Datetime64:
case Timestamp64:
return Types.TIMESTAMP;
case TzDate:
case TzDatetime:
Expand Down Expand Up @@ -294,7 +303,11 @@ private List<Type> getAllDatabaseTypesImpl() {
PrimitiveType.Datetime,
PrimitiveType.Timestamp,
PrimitiveType.Interval,
DecimalType.getDefault());
DecimalType.getDefault(),
PrimitiveType.Date32,
PrimitiveType.Datetime64,
PrimitiveType.Timestamp64,
PrimitiveType.Interval64);
}

private int getSqlPrecisionImpl(PrimitiveType type) {
Expand All @@ -314,6 +327,7 @@ private int getSqlPrecisionImpl(PrimitiveType type) {
case Uint64:
case Double:
case Interval:
case Interval64:
return 8;
case Bytes:
case Text:
Expand All @@ -324,10 +338,13 @@ private int getSqlPrecisionImpl(PrimitiveType type) {
case Uuid:
return 8 + 8;
case Date:
case Date32:
return "0000-00-00".length();
case Datetime:
case Datetime64:
return "0000-00-00 00:00:00".length();
case Timestamp:
case Timestamp64:
return "0000-00-00T00:00:00.000000".length();
case TzDate:
return "0000-00-00+00:00".length();
Expand Down
Loading