ClickHouse / ClickHouse/clickhouse-java
Map(K, V) type support issue
- Dominant language
- Java
- Stars
- 1.6k
- Forks
- 636
- Avg merge
- 2d 16h
- Merged PRs (30d)
- 28
Description
## 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
Contributor guide
Assessment
This issue has not been assessed yet.