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

Insert Fails for Array(Tuple) in JDBC v2 (Worked in v1)

Open aira-xite opened this issue 7 months ago • 1 comments

We previously encountered a similar issue (#1862), and the suggested solution worked at that time. However, after migrating to jdbc-v2 (version 0.8.4), the same approach no longer works.

Currently, we're attempting to insert data into a column of type Array(Tuple(String, String)) using the method recommended in this comment, but the operation now fails with the following error:

Failed to create array
java.sql.SQLException: 
	at com.clickhouse.jdbc.ConnectionImpl.createArrayOf(ConnectionImpl.java:515)
	at com.zaxxer.hikari.pool.HikariProxyConnection.createArrayOf(HikariProxyConnection.java)
.....
.....
Caused by: java.lang.IllegalArgumentException: No enum constant com.clickhouse.data.ClickHouseDataType.Tuple(String, String)
	at java.base/java.lang.Enum.valueOf(Enum.java:273)
	at com.clickhouse.data.ClickHouseDataType.valueOf(ClickHouseDataType.java:50)
	at com.clickhouse.jdbc.ConnectionImpl.createArrayOf(ConnectionImpl.java:513)
	at com.zaxxer.hikari.pool.HikariProxyConnection.createArrayOf(HikariProxyConnection.java)

This used to work on 0.7.2 and jdbc-v1. Is there an updated way to insert an Array(Tuple(String, String)) column using jdbc-v2?

aira-xite avatar May 14 '25 15:05 aira-xite

@aira-xite thank you for reporting! We will look into it.

chernser avatar May 16 '25 16:05 chernser

@aira-xite would you please check this test com.clickhouse.jdbc.DataTypeTests#testArrayTypes:

creating table

        runQuery("CREATE TABLE test_arrays (order Int8, "
                + "array Array(Int8), arraystr Array(String), arraytuple Array(Tuple(Int8, String)), arraydate Array(Date)"
                + ") ENGINE = MergeTree ORDER BY ()");

create values

  Tuple[] arraytuple = new Tuple[rand.nextInt(10) + 1];
  for (int i = 0; i < arraytuple.length; i++) {
      arraytuple[i] = new Tuple(rand.nextInt(256) - 128, "string" + rand.nextInt(1000));
  }

inserting values

 try (Connection conn = getConnection()) {
      try (PreparedStatement stmt = conn.prepareStatement("INSERT INTO test_arrays VALUES ( 1, ?, ?, ?, ?)")) {
          stmt.setArray(1, conn.createArrayOf("Int8", array));
          stmt.setArray(2, conn.createArrayOf("String", arraystr));
          stmt.setArray(3, conn.createArrayOf("Tuple", arraytuple)); // < ---- 
          stmt.setArray(4, conn.createArrayOf("Date", arraydate));
          stmt.executeUpdate();
      }
  }

So just an array of Tuple.

Please let me know if this works for you.

We will do more tests around that.

chernser avatar Jun 27 '25 22:06 chernser

Good day, @aira-xite!

I'm currently working on the issue:

  • Tuple is eventually a structure without field names.
  • Using java.sql.Array as Tuple is not correct way to solve your case because Array may contain elements of only one data type.
  • In the new release we are going to utilize java.sql.Struct to represent nested types like Tuple
  • We will fix the issue but in this case you would need to pass array of Struct not Array. Sorry about that.

A few questions:

  • what is the source or array of Tuple(String, String? is it a collection?
  • Would it be more convenient to pass collection/array or Tuples to setObject() ?

Thanks!

chernser avatar Aug 20 '25 22:08 chernser