setTimestamp java.lang.NullPointerException
JDBC version : 0.1.48 and JDK 1.8.171
ClickHouseProperties properties = new ClickHouseProperties();
properties.setUseServerTimeZone(false);
ClickHouseProperties withCredentials = properties.withCredentials(this.username, this.password);
this.clickHouseDataSource = new BalancedClickhouseDataSource(this.jdbcUrl, withCredentials);
```````
```````
```````
java.sql.Timestamp sqlTimestamp = new java.sql.Timestamp(
1548042771L);
preparedStatement.setTimestamp(columnIndex + 1, sqlTimestamp);
Caused by: java.lang.NullPointerException at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2342) at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2312) at java.util.Calendar.setTimeInMillis(Calendar.java:1804) at java.util.Calendar.setTime(Calendar.java:1770) at java.text.SimpleDateFormat.format(SimpleDateFormat.java:943) at java.text.SimpleDateFormat.format(SimpleDateFormat.java:936) at java.text.DateFormat.format(DateFormat.java:345) at ru.yandex.clickhouse.ClickHousePreparedStatementImpl.setTimestamp(ClickHousePreparedStatementImpl.java:247) at com.xx.datax.plugin.writer.clickhousewriter.CHWriter$Task.fillPreparedStatementColumnType(CHWriter.java:361) at com.xx.datax.plugin.writer.clickhousewriter.CHWriter$Task.fillPreparedStatement(CHWriter.java:272) at com.xx.datax.plugin.writer.clickhousewriter.CHWriter$Task.doBatchInsert(CHWriter.java:250) ... 5 more
It took me 2 hours of debugging and found that the time zone setting of the ClickHouse client was incorrect. The following code has logical processing that is not rigorous enough. I think it should be handled this way.
ClickHouseConnectionImpl.java
private void initTimeZone(ClickHouseProperties properties) {
if (properties.isUseServerTimeZone() && !Strings.isNullOrEmpty(properties.getUseTimeZone())) {
throw new IllegalArgumentException(String.format("only one of %s or %s must be enabled", ClickHouseConnectionSettings.USE_SERVER_TIME_ZONE.getKey(), ClickHouseConnectionSettings.USE_TIME_ZONE.getKey()));
}
if (properties.isUseServerTimeZone()) {
ResultSet rs = null;
try {
timezone = TimeZone.getTimeZone("UTC"); // just for next query
rs = createStatement().executeQuery("select timezone()");
rs.next();
String timeZoneName = rs.getString(1);
timezone = TimeZone.getTimeZone(timeZoneName);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
StreamUtils.close(rs);
}
} else if (!Strings.isNullOrEmpty(properties.getUseTimeZone())) {
timezone = TimeZone.getTimeZone(properties.getUseTimeZone());
}
}
- Use the server time zone as the local ClickHouse client time zone.
- The time zone set by the developer itself is the ClickHouse client time zone.
Obviously, the first IF statement in this code does not judge that their values are False, and then does not check the TimeZone value, causing the above exception to occur. But I think the JDK is also responsible, not doing a non-empty check :).