Skip to content
Closed
Show file tree
Hide file tree
Changes from 7 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
81 changes: 80 additions & 1 deletion 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 @@ -870,6 +907,48 @@ 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
Loading