Skip to content

Commit 174532c

Browse files
committed
made date/time to be encoded allways as the string
1 parent c0c7938 commit 174532c

File tree

4 files changed

+154
-7
lines changed

4 files changed

+154
-7
lines changed

client-v2/src/main/java/com/clickhouse/client/api/DataTypeUtils.java

Lines changed: 77 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,22 @@
11
package com.clickhouse.client.api;
22

3-
import java.time.Instant;
4-
import java.time.ZoneId;
53
import com.clickhouse.client.api.data_formats.internal.BinaryStreamReader;
4+
import com.clickhouse.data.ClickHouseDataType;
65

6+
import java.sql.Time;
7+
import java.sql.Timestamp;
78
import java.time.Instant;
9+
import java.time.LocalDateTime;
810
import java.time.ZoneId;
11+
import java.time.ZoneOffset;
12+
import java.time.ZonedDateTime;
913
import java.time.format.DateTimeFormatter;
1014
import java.time.format.DateTimeFormatterBuilder;
1115
import java.time.temporal.ChronoField;
16+
import java.time.temporal.Temporal;
17+
import java.util.Date;
1218
import java.util.Objects;
1319

14-
import com.clickhouse.data.ClickHouseDataType;
15-
1620
import static com.clickhouse.client.api.data_formats.internal.BinaryStreamReader.BASES;
1721

1822
public class DataTypeUtils {
@@ -39,6 +43,19 @@ public class DataTypeUtils {
3943
.appendFraction(ChronoField.NANO_OF_SECOND, 9, 9, true)
4044
.toFormatter();
4145

46+
public static DateTimeFormatter TIME_FORMATTER = new DateTimeFormatterBuilder()
47+
.appendFraction(ChronoField.HOUR_OF_DAY, 1, 4, false)
48+
.appendFraction(ChronoField.MINUTE_OF_HOUR, 1, 3, false)
49+
.appendFraction(ChronoField.SECOND_OF_MINUTE, 1, 3, false)
50+
.toFormatter();
51+
52+
public static DateTimeFormatter TIME_WITH_NANOS_FORMATTER = new DateTimeFormatterBuilder()
53+
.appendFraction(ChronoField.HOUR_OF_DAY, 1, 4, false)
54+
.appendFraction(ChronoField.MINUTE_OF_HOUR, 1, 3, false)
55+
.appendFraction(ChronoField.SECOND_OF_MINUTE, 1, 3, false)
56+
.appendFraction(ChronoField.NANO_OF_SECOND, 9, 9, true)
57+
.toFormatter();
58+
4259
/**
4360
* Formats an {@link Instant} object for use in SQL statements or as query
4461
* parameter.
@@ -138,4 +155,60 @@ public static Instant instantFromTime64Integer(int precision, long value) {
138155

139156
return Instant.ofEpochSecond(value, nanoSeconds);
140157
}
158+
159+
/**
160+
* Converts a Java object to a temporal accessor suitable for date only operations.
161+
* It accepts Time and Date and converts to LocalDateTime
162+
* @param date
163+
* @return
164+
*/
165+
public static Temporal toLocalDateTemporal(Object date) {
166+
if (date instanceof Temporal) {
167+
return (Temporal) date;
168+
} else if (date instanceof java.sql.Date) {
169+
return ((java.sql.Date) date).toLocalDate();
170+
} else if (date instanceof Timestamp) {
171+
return ((java.sql.Timestamp) date).toLocalDateTime().toLocalDate();
172+
} else if (date instanceof java.util.Date) {
173+
return ((java.util.Date) date).toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
174+
}
175+
176+
throw new IllegalArgumentException("Object of type '" + date.getClass() + "' cannot be converted to local date because has no date part");
177+
}
178+
179+
/**
180+
* Converts a Java object to a temporal accessor suitable for date and time operations.
181+
* @param date
182+
* @return
183+
*/
184+
public static Temporal toLocalDateTimeTemporal(Object date) {
185+
if (date instanceof Temporal) {
186+
return (Temporal) date;
187+
} else if (date instanceof java.sql.Timestamp) {
188+
return ((java.sql.Timestamp) date).toLocalDateTime();
189+
} else if (date instanceof java.util.Date) {
190+
return ((java.util.Date) date).toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
191+
}
192+
193+
throw new IllegalArgumentException("Object of type '" + date.getClass() + "' cannot be converted to local date because has no date or time part");
194+
}
195+
196+
/**
197+
* Converts a Java object to a temporal accessor suitable for time only operations.
198+
* @param date
199+
* @return
200+
*/
201+
public static Temporal toLocalTimeTemporal(Object date) {
202+
if (date instanceof Temporal) {
203+
return (Temporal) date;
204+
} else if (date instanceof Timestamp) {
205+
return ((Timestamp) date).toLocalDateTime();
206+
} else if (date instanceof Time) {
207+
return ((Time) date).toLocalTime();
208+
} else if (date instanceof java.util.Date) {
209+
return ((java.util.Date) date).toInstant().atZone(ZoneId.systemDefault()).toLocalTime();
210+
}
211+
212+
throw new IllegalArgumentException("Object of type '" + date.getClass() + "' cannot be converted to local time because has no time part");
213+
}
141214
}

jdbc-v2/src/main/java/com/clickhouse/jdbc/PreparedStatementImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ public static String replaceQuestionMarks(String sql, final String replacement)
469469
@Override
470470
public void setDate(int parameterIndex, Date x, Calendar cal) throws SQLException {
471471
ensureOpen();
472-
values[parameterIndex - 1] = encodeObject(sqlDateToInstant(x, cal));
472+
values[parameterIndex - 1] = encodeObject(x);
473473
}
474474

475475
protected Instant sqlDateToInstant(Date x, Calendar cal) {
@@ -483,7 +483,7 @@ protected Instant sqlDateToInstant(Date x, Calendar cal) {
483483
@Override
484484
public void setTime(int parameterIndex, Time x, Calendar cal) throws SQLException {
485485
ensureOpen();
486-
values[parameterIndex - 1] = encodeObject(sqlTimeToInstant(x, cal));
486+
values[parameterIndex - 1] = encodeObject(x);
487487
}
488488

489489
protected Instant sqlTimeToInstant(Time x, Calendar cal) {

jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/DatabaseMetaDataImpl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,8 @@ public ResultSet getTables(String catalog, String schemaPattern, String tableNam
781781
" JOIN system.databases d ON system.tables.database = system.databases.name" +
782782
" WHERE t.database LIKE '" + (schemaPattern == null ? "%" : schemaPattern) + "'" +
783783
" AND t.name LIKE '" + (tableNamePattern == null ? "%" : tableNamePattern) + "'" +
784-
" AND TABLE_TYPE IN ('" + String.join("','", types) + "')";
784+
" AND TABLE_TYPE IN ('" + String.join("','", types) + "') " +
785+
" ORDER BY TABLE_SCHEM, TABLE_TYPE, TABLE_NAME";
785786

786787
try {
787788
return connection.createStatement().executeQuery(sql);

jdbc-v2/src/test/java/com/clickhouse/jdbc/DataTypeTests.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import java.sql.ResultSetMetaData;
2929
import java.sql.SQLException;
3030
import java.sql.Statement;
31+
import java.sql.Time;
3132
import java.sql.Timestamp;
33+
import java.sql.Types;
3234
import java.text.DecimalFormat;
3335
import java.time.Instant;
3436
import java.time.LocalDate;
@@ -1651,4 +1653,75 @@ public void testVariantTypesSimpleStatement() throws SQLException {
16511653
}
16521654
}
16531655
}
1656+
1657+
@Test(groups = { "integration" })
1658+
public void testDateWithExpressions() throws Exception {
1659+
try (Connection conn = getJdbcConnection()) {
1660+
try (PreparedStatement stmt = conn.prepareStatement("SELECT parseDateTimeBestEffort(?) as d1, " +
1661+
" parseDateTimeBestEffort(?) as d2, toYear(?) as d3, parseDateTimeBestEffort(?) as d4, parseDateTimeBestEffort(?) as d5")) {
1662+
Date date = Date.valueOf("2024-12-01");
1663+
Time time = Time.valueOf("12:00:00");
1664+
stmt.setDate(1, date);
1665+
stmt.setObject(2, date);
1666+
stmt.setObject(3, date, Types.DATE);
1667+
stmt.setTime(4, time);
1668+
stmt.setObject(5, time);
1669+
1670+
try (ResultSet rs = stmt.executeQuery()) {
1671+
assertTrue(rs.next());
1672+
assertEquals(rs.getString(1), "2024-12-01 00:00:00");
1673+
assertEquals(rs.getString(2), "2024-12-01 00:00:00");
1674+
assertEquals(rs.getString(3), "2024");
1675+
assertEquals(rs.getDate(1), date);
1676+
}
1677+
}
1678+
1679+
final String testTable = "test_date_expressions";
1680+
try (Statement stmt = conn.createStatement()) {
1681+
stmt.execute("DROP TABLE IF EXISTS " + testTable);
1682+
stmt.execute("CREATE TABLE " + testTable + " (d Date, event String) ENGINE = MergeTree() ORDER BY ()");
1683+
stmt.execute("INSERT INTO " + testTable + " VALUES ('2024-12-01', 'event1'), ('2024-12-02', 'event2'), ('2024-12-03', 'event3')");
1684+
}
1685+
1686+
try (PreparedStatement stmt = conn.prepareStatement("SELECT d, event FROM " + testTable + " WHERE d IN(?) ORDER BY event")){
1687+
Date[] dates = new Date[] { Date.valueOf("2024-12-01"), Date.valueOf("2024-12-03") };
1688+
stmt.setArray(1, conn.createArrayOf("Date", dates));
1689+
try (ResultSet rs = stmt.executeQuery()) {
1690+
String[] events = new String[] { "event1", "event3" };
1691+
String[] datesStr = new String[] { "2024-12-01", "2024-12-03" };
1692+
1693+
for (int i = 0; i < events.length; i++) {
1694+
assertTrue(rs.next());
1695+
assertEquals(rs.getString("event"), events[i]);
1696+
assertEquals(rs.getString("d"), datesStr[i]);
1697+
}
1698+
}
1699+
}
1700+
1701+
final String dateTimeTable = "test_date_time_expressions";
1702+
try (Statement stmt = conn.createStatement()) {
1703+
stmt.execute("DROP TABLE IF EXISTS " + dateTimeTable);
1704+
stmt.execute("CREATE TABLE " + dateTimeTable + " (t DateTime32, event String) ENGINE = MergeTree() ORDER BY ()");
1705+
stmt.execute("INSERT INTO " + dateTimeTable + " VALUES ('2024-12-01 00:10:00', 'event1'), ('2024-12-02 00:20:00', 'event2'), " +
1706+
"('2024-12-03 00:30:00', 'event3')");
1707+
}
1708+
try (PreparedStatement stmt = conn.prepareStatement("SELECT t, event FROM " + dateTimeTable + " WHERE t IN(?) ORDER BY event")){
1709+
Timestamp[] timestamps = new Timestamp[] {
1710+
Timestamp.valueOf("2024-12-01 00:10:00"),
1711+
Timestamp.valueOf("2024-12-03 00:30:00")
1712+
};
1713+
stmt.setArray(1, conn.createArrayOf("DateTime32", timestamps));
1714+
try (ResultSet rs = stmt.executeQuery()) {
1715+
String[] events = new String[] { "event1", "event3" };
1716+
String[] timestampsStr = new String[] { "2024-12-01 00:10:00", "2024-12-03 00:30:00" };
1717+
1718+
for (int i = 0; i < events.length; i++) {
1719+
assertTrue(rs.next());
1720+
assertEquals(rs.getString("event"), events[i]);
1721+
assertEquals(rs.getString("t"), timestampsStr[i]);
1722+
}
1723+
}
1724+
}
1725+
}
1726+
}
16541727
}

0 commit comments

Comments
 (0)