ClickHouse / ClickHouse/clickhouse-java

Map(K, V) type support issue

オープン
#3,047 コメント 1 件 リアクション 2 件 担当者 0 名 GitHub で見る
bug
主要言語
Java
スター
1.6k
フォーク
636
平均マージ
2日 23時間
マージ済み PR(30日)
29

説明

## Description
In Clickhouse `Map(K, V)` is not a collection of unique-by-key pairs, see https://clickhouse.com/docs/sql-reference/data-types/map :

> i.e. a map can contain two elements with the same key

But there is no way to obtain any representation other than a Map<,> of unique entries.

All the key-value pairs are being delivered by the underlying protocol, but they are effectively merged while reading an instance of a map in the corresponding [readMap(..)](https://github.com/ClickHouse/clickhouse-java/blob/601ade16364d667b71a4982bbabf60ed2d941dc1/client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/BinaryStreamReader.java#L969) method.

The issue affects all scenarios of map usage: top-level value, nested map-in-map, map-in-array, etc.

### Steps to reproduce
1. Execute minimal reproduction program:
```
public class Program {
public static void main(String[] args) throws SQLException {
String queryText = "select map('key', 'X', 'key', 'Y')";
try (
Connection cnn = DriverManager.getConnection("jdbc:clickhouse://localhost:11049/default", "default", "");
PreparedStatement stmt = cnn.prepareStatement(queryText);
ResultSet rs = stmt.executeQuery()
) {
if (rs.next()) {
System.out.println(rs.getObject(1)); // gives {key=Y}
} else {
throw new IllegalStateException();
}
}
}
}
```
2. Observe only one value per key returned.
3. Any attempt to get other value representations than what `getObject()` does gives the same or results in an exception being thrown.

### Expected Behavior

Supporting existing behavior by default, it is expected to be able to use type hints to affect the actual return value of the `getObject(..)` method of the `java.sql.ResultSet` implementation (such overloads as ` T getObject(int columnIndex, Class type)` and `Object getObject(int columnIndex, java.util.Map> map)` specifically, including their counterparts having `columnLabel` instead of `columnIndex`):

```
public class Program {
public static void main(String[] args) throws SQLException {
String queryText = "select map('key', 'X', 'key', 'Y')";
try (
Connection cnn = DriverManager.getConnection("jdbc:clickhouse://localhost:11049/default", "default", "");
PreparedStatement stmt = cnn.prepareStatement(queryText);
ResultSet rs = stmt.executeQuery()
) {
if (rs.next()) {
System.out.println(rs.getObject(1)); // gives {key=Y} by default

System.out.println(rs.getObject(1, List.class)); // to give [key=X, key=Y] only for top level
System.out.println(rs.getObject(1, Map.of("Map", List.class))); // to give [key=X, key=Y] same as above including nested values
} else {
throw new IllegalStateException();
}
}
}
}
```
Consider changing the default behavior by the time of a certain upcoming major release.

### Code Example

```sql
select map('key', 'X', 'key', 'Y');

```

#### Environment
* [ ] Cloud
* Client version: 0.10.0-rc2
* Language version: 21
* OS: Windows 11

#### ClickHouse Server
* ClickHouse Server version: 24.5.3.5

コントリビューションガイド

コントリビューションガイドを開く

調査の方向性

client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/BinaryStreamReader.java の readMap(..) から始め、次に issue で示されている JDBC ResultSet getObject オーバーロードを追跡します。重複キーのクエリを再現し、トップレベルの map、ネストされた map、array に含まれる map がどのように読み取られるかを調べます。デフォルトの動作が互換性を維持し、要求された型ヒントによって各記載シナリオで重複するキーと値のエントリが保持されれば完了です。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
java
領域
api, database
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
48/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。