Skip to content

Commit 293e900

Browse files
authored
Merge pull request #373 from youngsofun/ts
feat: support mapping Interval to java.time.Duration.
2 parents 08e662d + 59483ce commit 293e900

File tree

5 files changed

+326
-21
lines changed

5 files changed

+326
-21
lines changed

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ The Databend type is mapped to Java type as follows:
106106
| Date | LocalDate |
107107
| Timestamp | ZonedDateTime |
108108
| Timestamp_TZ | OffsetDateTime |
109-
| Interval | String |
109+
| Interval | Duration |
110110
| Geometry | byte[] |
111111
| Bitmap | byte[] |
112112
| Array | String |
@@ -126,6 +126,7 @@ void setObject(int parameterIndex, Object x)
126126
- TIMESTAMP_TZ and TIMESTAMP map to `OffsetDateTime`, `ZonedDateTime`, `Instant` and `LocalDateTime` (TIMESTAMP_TZ can return `OffsetDateTime` but not `ZonedDateTime`).
127127
- Date maps to `LocalDate`
128128
- When parameters do not contain a timezone, Databend uses the session timezone (not the JVM zone) when storing/returning dates on databend-jdbc ≥ 0.4.3 AND databend-query ≥1.2.844.
129+
- Interval map to `java.time.Duration`.
129130

130131
old Timestamp/Date are also supported, note that:
131132

@@ -135,6 +136,8 @@ old Timestamp/Date are also supported, note that:
135136
- `setDate`/`getDate` still use the JVM timezone, `getDate(1)` is equivalent to `Date.valueOf(getObject(1, LocalDate.class))`, `setDate(1, date)` is equivalent to `setObject(1, date.toLocalDate())`.
136137

137138

139+
140+
138141
# Unwrapping to Databend-specific interfaces
139142

140143
## interface DatabendConnection

databend-jdbc/src/main/java/com/databend/jdbc/AbstractDatabendResultSet.java

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.databend.client.QueryRowField;
55
import com.databend.client.data.DatabendDataType;
66
import com.databend.client.data.DatabendRawType;
7+
import com.databend.client.data.DatabendTypes;
78
import com.databend.client.errors.QueryErrors;
89
import com.databend.jdbc.annotation.NotImplemented;
910
import com.databend.jdbc.exception.DatabendUnsupportedOperationException;
@@ -44,11 +45,8 @@
4445
import static java.util.Objects.requireNonNull;
4546

4647
abstract class AbstractDatabendResultSet implements ResultSet {
47-
protected AtomicLong lastRequestTime = new AtomicLong();
48-
4948
static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ISO_LOCAL_DATE;
5049

51-
private static final long SECONDS_PER_DAY = 86_400L;
5250
private static final long[] POWERS_OF_TEN = {
5351
1L,
5452
10L,
@@ -716,7 +714,18 @@ public ResultSetMetaData getMetaData()
716714
@Override
717715
public Object getObject(int columnIndex)
718716
throws SQLException {
719-
return column(columnIndex);
717+
Object value = column(columnIndex);
718+
if (value == null) {
719+
return null;
720+
}
721+
DatabendRawType databendRawType = this.databendColumnInfoList.get(columnIndex - 1).getType();
722+
if (DatabendRawType.startsWithIgnoreCase(databendRawType.getType(), DatabendTypes.INTERVAL)) {
723+
if (!(value instanceof String)) {
724+
throw new SQLDataException("Interval value is not textual: " + value.getClass().getName());
725+
}
726+
return Interval.decode((String) value);
727+
}
728+
return value;
720729
}
721730

722731
@Override
@@ -1028,25 +1037,25 @@ public void updateNull(String columnLabel)
10281037
@Override
10291038
public void updateObject(int columnIndex, Object x, SQLType targetSqlType, int scaleOrLength)
10301039
throws SQLException {
1031-
this.updateObject(columnIndex, x, targetSqlType, scaleOrLength);
1040+
throw new SQLFeatureNotSupportedException("updateObject");
10321041
}
10331042

10341043
@Override
10351044
public void updateObject(String columnLabel, Object x, SQLType targetSqlType, int scaleOrLength)
10361045
throws SQLException {
1037-
this.updateObject(columnLabel, x, targetSqlType, scaleOrLength);
1046+
throw new SQLFeatureNotSupportedException("updateObject");
10381047
}
10391048

10401049
@Override
10411050
public void updateObject(int columnIndex, Object x, SQLType targetSqlType)
10421051
throws SQLException {
1043-
this.updateObject(columnIndex, x, targetSqlType);
1052+
throw new SQLFeatureNotSupportedException("updateObject");
10441053
}
10451054

10461055
@Override
10471056
public void updateObject(String columnLabel, Object x, SQLType targetSqlType)
10481057
throws SQLException {
1049-
this.updateObject(columnLabel, x, targetSqlType);
1058+
throw new SQLFeatureNotSupportedException("updateObject");
10501059
}
10511060

10521061
@Override
@@ -1700,7 +1709,7 @@ public <T> T getObject(int columnIndex, Class<T> type)
17001709
DatabendRawType databendRawType = this.databendColumnInfoList.get(columnIndex - 1).getType();
17011710

17021711
if (type == LocalDate.class) {
1703-
return type.cast( LocalDate.parse((String)value));
1712+
return type.cast(LocalDate.parse((String) value));
17041713
}
17051714

17061715
if (type == Instant.class) {
@@ -1715,6 +1724,17 @@ public <T> T getObject(int columnIndex, Class<T> type)
17151724
return type.cast(getZonedDateTimeNotNull((String) value, databendRawType));
17161725
}
17171726

1727+
if (type == Duration.class) {
1728+
Object intervalValue = getObject(columnIndex);
1729+
if (intervalValue == null) {
1730+
return null;
1731+
}
1732+
if (!(intervalValue instanceof Duration)) {
1733+
throw new SQLDataException(invalidColumnType(databendRawType, "Duration"));
1734+
}
1735+
return type.cast(intervalValue);
1736+
}
1737+
17181738
return (T) value;
17191739
}
17201740

databend-jdbc/src/main/java/com/databend/jdbc/DatabendPreparedStatement.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,11 @@ public void setObject(int parameterIndex, Object x, int targetSqlType)
489489
case Types.NVARCHAR:
490490
case Types.LONGVARCHAR:
491491
case Types.LONGNVARCHAR:
492-
setString(parameterIndex, x.toString());
492+
if (x instanceof Duration) {
493+
setDurationLiteral(parameterIndex, (Duration) x);
494+
} else {
495+
setString(parameterIndex, x.toString());
496+
}
493497
return;
494498
case Types.BINARY:
495499
InputStream blobInputStream = new ByteArrayInputStream(x.toString().getBytes());
@@ -514,6 +518,13 @@ public void setObject(int parameterIndex, Object x, int targetSqlType)
514518
case Types.TIMESTAMP_WITH_TIMEZONE:
515519
setString(parameterIndex, toTimestampWithTimeZoneLiteral(x));
516520
return;
521+
case Types.OTHER:
522+
case Types.JAVA_OBJECT:
523+
if (x instanceof Duration) {
524+
setDurationLiteral(parameterIndex, (Duration) x);
525+
return;
526+
}
527+
break;
517528
}
518529
throw new SQLException("Unsupported target SQL type: " + targetSqlType);
519530
}
@@ -562,6 +573,8 @@ public void setObject(int parameterIndex, Object x)
562573
setString(parameterIndex, toTimestampLiteral(x));
563574
} else if (x instanceof ZonedDateTime) {
564575
setString(parameterIndex, toTimestampLiteral(x));
576+
} else if (x instanceof Duration) {
577+
setDurationLiteral(parameterIndex, (Duration) x);
565578
} else if (x instanceof Map) {
566579
setString(parameterIndex, convertToJsonString((Map<?, ?>) x));
567580
} else if (x instanceof Array) {
@@ -599,6 +612,14 @@ public static String convertArrayListToString(ArrayList<?> arrayList) {
599612
return builder.toString();
600613
}
601614

615+
private void setDurationLiteral(int parameterIndex, Duration duration) throws SQLException {
616+
try {
617+
setString(parameterIndex, Interval.encode(duration));
618+
} catch (IllegalArgumentException ex) {
619+
throw new SQLException("Failed to encode Duration for interval parameter", ex);
620+
}
621+
}
622+
602623
@Override
603624
public void addBatch()
604625
throws SQLException {

0 commit comments

Comments
 (0)