[client-v2] readVariant discards the active type discriminant — colliding Variant alternatives are indistinguishable
Los mantenedores suelen responder en 1 día
Nadie ha tomado este issue todavía.
Evaluación
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Aptitud para principiantes
- 45/100
- Tipo de issue
- Error
- Claridad
- Bastante claro
- Estado de actividad
- Tranquilo
- Stack tecnológico
- java
- Área
- api, backend-api-design
Línea de trabajo
Empieza en client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/BinaryStreamReader.java, en readVariant alrededor de las líneas 892-898, y luego sigue el caso Variant en readValue alrededor de las líneas 248-250. Compara los enfoques propuestos de wrapper o subtipo resuelto y comprueba el procesador RowBinary legacy de clickhouse-data para ver el mismo patrón. Se considera terminado cuando los llamadores pueden distinguir alternativas en conflicto como DateTime y DateTime64, con pruebas que cubran el discriminante.
Escrito por el modelo de indexación a partir del texto del issue.
Descripción
Description
BinaryStreamReader.readVariant(ClickHouseColumn) reads the 1-byte Variant discriminant (ordNum) only to select which nested column's reader to run, then returns just the decoded value and throws the discriminant away:
// client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/BinaryStreamReader.java:892
public Object readVariant(ClickHouseColumn column) throws IOException {
int ordNum = readByte() & 0xFF;
if (ordNum == 0xFF) {
return null;
}
return readValue(column.getNestedColumns().get(ordNum)); // ordNum (the active type) is discarded
}
For many Variants the active alternative can be inferred from the returned object's runtime class, but for alternatives whose readers produce the same Java runtime type the information is lost, and the consumer cannot recover which ClickHouse subtype was actually on the wire. Examples where the decoded objects are indistinguishable:
| Variant | both alternatives decode to | why ambiguous |
|---|---|---|
Variant(DateTime, DateTime64(3)) |
java.time.ZonedDateTime (lines 186-191 → convertDateTime, typeHint == null → returns ZonedDateTime) |
same class, same instant |
Variant(String, FixedString(N)) |
java.lang.String |
same class |
Variant(Decimal32(s), Decimal64(s)) |
java.math.BigDecimal |
same class/scale |
Because readVariant returns a bare Object, a downstream consumer (text/JSON renderer, type-aware formatter, or any caller inspecting the value) has no way to choose the correct subtype for formatting in these cases.
This is the Java analogue of ClickHouse/clickhouse-js#910. Note the specific examples in that JS issue do not collide here — clickhouse-java maps Enum8/Enum16 to a dedicated EnumValue (lines 172-181) and Date to LocalDate (line 183), so Variant(UInt8, Enum8(...)) and Variant(Date, DateTime) are recoverable from the runtime type. The underlying limitation — the discriminant index is not surfaced — is the same, and other type pairs (above) hit it.
ClickHouse server version
26.6.1.1193 (collision behavior determined by code analysis of the type→class mapping; not exercised end-to-end against the server).
Reproduction
A Variant(DateTime, DateTime64(3)) column: whichever alternative the server picks, readVariant returns a ZonedDateTime, so the caller cannot tell DateTime from DateTime64.
// Conceptual unit-level repro against BinaryStreamReader
ClickHouseColumn col = ClickHouseColumn.of("v", "Variant(DateTime, DateTime64(3))");
// Wire bytes: discriminant 0x01 selects the DateTime64 alternative (alternatives are
// sorted by ClickHouse's global type-name ordering), followed by its encoded value.
byte[] payload = /* 0x01 ++ encoded DateTime64 value */;
BinaryStreamReader reader = new BinaryStreamReader(
new ByteArrayInputStream(payload), null, LZ4_FACTORY, null);
Object value = reader.readVariant(col);
// EXPECTED: caller can determine the active alternative was DateTime64 (index 1)
// ACTUAL: value is a java.time.ZonedDateTime, identical to what the DateTime
// alternative (index 0) would have produced — the active type is unrecoverable.
assertTrue(value instanceof ZonedDateTime); // passes for BOTH alternatives
The same happens through the high-level reader path (readValue → case Variant at line 248-250): reading a Variant(String, FixedString(10)) column yields a String with no indication of which alternative it was.
Suggested fix
Surface the active alternative index alongside the value rather than discarding it — mirroring the upstream proposal. Options:
- Return a small wrapper, e.g.
VariantValue { int typeIndex; Object value; }, fromreadVariant(breaking change to the publicObject readVariant(...)signature — gate behind a minor/major bump), or - Expose the resolved subtype (
column.getNestedColumns().get(ordNum)) so a renderer can format with the exactClickHouseColumn.
Buggy code: BinaryStreamReader.readVariant at client-v2/src/main/java/com/clickhouse/client/api/data_formats/internal/BinaryStreamReader.java:892-898 (dispatched from readValue case Variant at line 248-250). The legacy clickhouse-data RowBinary processor should be checked for the same pattern.
Link
Relayed from ClickHouse/clickhouse-js#910.
- Lenguaje dominante
- Java
- Estrellas
- 1.6k
- Forks
- 638
- Merge medio
- 2 d 14 h
- PR fusionados (30 d)
- 44
Preparar el entorno
- Sin Dockerfile ni archivo de Docker Compose
- Tiene una plantilla de pull request
- Leer la guía de contribución
Primeros pasos
- Lee el issue completo y luego la guía de contribución del proyecto.
- Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
- Haz un fork del repositorio y trabaja en una rama.
- Abre un pull request que haga referencia al número del issue.
Más de ClickHouse/clickhouse-java
-
[examples] Remove old Spring examplePosiblemente ocupada @polyglotAI-bot la tomó hace 10 días. Abierto
Dificultad 1/5 Menos de una hora Aptitud para principiantes 85/100
ClickHouse/clickhouse-java#3111 · 1 comentario · 1 asignado ·
Los mantenedores suelen responder en 1 día
-
bug client-api-v2 test
Dificultad 2/5 1-3 horas Aptitud para principiantes 92/100
ClickHouse/clickhouse-java#3076 ·
Los mantenedores suelen responder en 1 día
-
area:sql-parser bug client-v1
Dificultad 1/5 1-3 horas Aptitud para principiantes 92/100
ClickHouse/clickhouse-java#3066 ·
Los mantenedores suelen responder en 1 día
-
bug client-api-v2 jdbc-v2
Dificultad 1/5 1-3 horas Aptitud para principiantes 78/100
ClickHouse/clickhouse-java#2957 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
bug client-v1 wontfix
Dificultad 2/5 1-3 horas Aptitud para principiantes 72/100
ClickHouse/clickhouse-java#2895 · 1 comentario ·
Los mantenedores suelen responder en 1 día
Todos los issues de ClickHouse/clickhouse-java
Issues similares
-
bug
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
apache/skywalking#14120 ·
Los mantenedores suelen responder en 1 día
-
[Feature] 关于启动游戏进度条显示的优化Abiertoenhancement
Dificultad 2/5 1-3 horas Aptitud para principiantes 75/100
HMCL-dev/HMCL#6943 · 1 comentario ·
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 85/100
micronaut-projects/micronaut-core#13677 ·
Los mantenedores suelen responder en 1 día
-
new feature
Dificultad 2/5 1-3 horas Aptitud para principiantes 62/100
Los mantenedores suelen responder en 1 día
-
Dificultad 2/5 1-3 horas Aptitud para principiantes 78/100
apache/rocketmq-dashboard#5594 ·
Los mantenedores suelen responder en 3 días