clickhouse-java icon indicating copy to clipboard operation
clickhouse-java copied to clipboard

setTimestamp java.lang.NullPointerException

Open kuangye098 opened this issue 7 years ago • 1 comments

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

kuangye098 avatar Jan 18 '19 12:01 kuangye098

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());
        }
    }
  1. Use the server time zone as the local ClickHouse client time zone.
  2. 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 :).

kuangye098 avatar Jan 21 '19 03:01 kuangye098