ClickHouse / clickhouse-java

ClickHouse Java Clients & JDBC Driver
https://clickhouse.com
Apache License 2.0
1.45k stars 534 forks source link

ResultSet getObject with class return null values filled as it was not null #979

Closed FDoKE closed 2 years ago

FDoKE commented 2 years ago

When selecting values from table with getObject(index, Class) simple types (like float/int/boolean) return 0/false as result (when null is expected).

CREATE TABLE db.tbl
   (
   id int not null,
   double_col double,
   float_col float,
   varchar_col varchar(36),
   boolean_col boolean,
   int_col int,
   bigint_col bigint,
   char_col char(10),
   int32_col int32
   primary key (id)
   )
   distributed by (id)

Expected: [1, null, null, null, null, null, null, null, null] Actual: [1, 0.0, 0.0, null, false, 0, 0, null, 0]

getObject(int columnIndex) returns null as expected.

Is that expected behaivor? (it breaks Vertx jdbc client as it always uses getObject with expected class)

zhicwu commented 2 years ago

Hi @FDoKE, it's not expected. Which version of the driver you're using? Are you using com.clickhouse.jdbc.Driver?

FDoKE commented 2 years ago

@zhicwu on 0.3.2-patch10, yes, from com.clickhouse.jdbc I traced down problem to ClickHouseFloatValue asFloat return value, which is initilized with 0.0, but actual value is null. (same with other simple types) called from :

    @Override
    public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
        return getValue(columnIndex).asObject(type);
    }
zhicwu commented 2 years ago

Thanks for the details information @FDoKE. Is that possible that you set nullAsDefault to 2? Or, it's related to the distributed tables?

Just tried below case in DBeaver using patch10 driver and it works fine.

drop table tbl if exists;
create table tbl(a Int8, b Nullable(Int32))engine=Memory;
insert into tbl values(1, null);
select * from tbl;
FDoKE commented 2 years ago

@zhicwu dbeaver probably using getObject(index) to retrieve column values simple reproducer:

Connection connection = DriverManager.getConnection("jdbc:clickhouse://clickhouse:8123/default");
Statement statement = connection.createStatement();
statement.execute("select double_col from db.table");
ResultSet resultSet = statement.getResultSet();
resultSet.next();
Object object1 = resultSet.getObject(1); // returns null
Double object2 = resultSet.getObject(1, Double.class); // returns 0.0
zhicwu commented 2 years ago

it breaks Vertx jdbc client as it always uses getObject with expected class

Not sure if it's a good idea to use getObject(int, Class), because it's always the slowest mainly for two reasons: 1) autoboxing; and 2) type conversion.

FDoKE commented 2 years ago

Yeah, that seems strange to me too, why would they do that if it perfectly worked with getObject(int), I made an issue for them too to get their idea behind this change.