[jdbc-v2] Connection.createArrayOf / createStruct throw IllegalArgumentException instead of SQLException for an invalid type name
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 2/5
- Tempo estimado
- 1-3 horas
- Facilidade para iniciantes
- 85/100
Direção de pesquisa
Comece em jdbc-v2/src/main/java/com/clickhouse/jdbc/ConnectionImpl.java em createArrayOf (por volta da linha 652) e createStruct (por volta da linha 667) e acompanhe onde ClickHouseColumn.of lança IllegalArgumentException ou NumberFormatException. Está concluído quando os dois métodos lançam SQLException com a exceção do parser como causa e SQLState HY000, enquanto o comportamento com null, com conexão fechada e com tipos válidos permanece inalterado. Adicione um DataProvider com nomes de tipos rejeitados cobrindo os dois métodos e verifique a SQLException e a sua causa.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
Description
In jdbc-v2, Connection.createArrayOf(typeName, ...) and Connection.createStruct(typeName, ...) throw an unchecked IllegalArgumentException (or NumberFormatException) when the type-name parser rejects typeName. Both methods declare throws SQLException, and the JDBC API says that they throw SQLException. A caller that catches SQLException does not catch this error. Frameworks that translate SQLException (for example Spring's SQLExceptionTranslator) also do not see it.
All type names that the parser rejects are affected: an unknown type, a misspelled type, unbalanced parentheses, invalid type parameters, and an empty string. The server also rejects these names (see below), so an exception is correct. Only the exception type is wrong.
The two methods already throw SQLException for their other failures: a closed connection (08000), a non-Tuple type in createStruct (HY000, "Only Tuple datatype is supported for Struct"), and an error while createArrayOf builds the array (HY000, "Failed to create array"). Only the type-name parse step is outside this handling.
This is a different problem from #3344. #3344 is about one parse failure (Enum elements without numbers). After a fix for #3344, createArrayOf("NoSuchType", ...) still throws IllegalArgumentException.
Root cause
jdbc-v2/src/main/java/com/clickhouse/jdbc/ConnectionImpl.java:
createArrayOf, line 652:ClickHouseColumn.of("array", typeName)runs before thetry { ... } catch (Exception e) { throw new SQLException("Failed to create array", ...) }block. A parse exception is not wrapped.createStruct, line 667:ClickHouseColumn.of("v", typeName)has notry/catch.
ClickHouseColumn.of throws IllegalArgumentException for a type name that it cannot parse (for example from ClickHouseDataType.of, ClickHouseDataType.java:497), and NumberFormatException for an invalid numeric parameter.
Suggested fix
createArrayOf: moveClickHouseColumn.of(...)into the existingtry.createStruct: putClickHouseColumn.of(...)in atry, and rethrow a parse exception asSQLExceptionwithExceptionUtils.SQL_STATE_CLIENT_ERRORand the original exception as the cause. Put the type name in the message.- Keep the current behavior for:
typeName == null(SQLFeatureNotSupportedException), a closed connection (SQLException,08000), a non-Tuple type increateStruct, and all valid type names. - Test: one
@DataProviderof rejected type names (unknown type, unbalanced parentheses, invalid Decimal parameters, empty string) for both methods. AssertSQLExceptionand its cause.
Compatibility: a caller that catches IllegalArgumentException from these two methods gets SQLException after the fix. SQLException is already in both method signatures, so existing code still compiles.
Steps to reproduce
- Build
main(f73e372bc). Connect with jdbc-v2 to ClickHouse 26.9.1.1629. - Call
conn.createArrayOf("NoSuchType", new Object[] {1})intry { ... } catch (SQLException e) { ... }. - The
catchblock does not run.java.lang.IllegalArgumentException: Unknown data type: NoSuchTypegoes out of thetry.createStruct("Tuple(NoSuchType, UInt8)", ...)gives the same result.
Error Log or Exception StackTrace
java.lang.IllegalArgumentException: Unknown data type: NoSuchType
at com.clickhouse.data.ClickHouseDataType.of(ClickHouseDataType.java:497)
at com.clickhouse.data.ClickHouseColumn.readColumn(ClickHouseColumn.java:714)
at com.clickhouse.data.ClickHouseColumn.of(ClickHouseColumn.java:763)
at com.clickhouse.jdbc.ConnectionImpl.createArrayOf(ConnectionImpl.java:652)
java.lang.IllegalArgumentException: Unknown data type: NoSuchType
at com.clickhouse.data.ClickHouseDataType.of(ClickHouseDataType.java:497)
at com.clickhouse.data.ClickHouseColumn.readColumn(ClickHouseColumn.java:714)
at com.clickhouse.data.ClickHouseColumn.readColumn(ClickHouseColumn.java:544)
at com.clickhouse.data.ClickHouseColumn.of(ClickHouseColumn.java:763)
at com.clickhouse.jdbc.ConnectionImpl.createStruct(ConnectionImpl.java:667)
Results of the jdbc-v2 calls (same program, same connection):
createArrayOf("Int32") -> OK
createArrayOf("NoSuchType") -> java.lang.IllegalArgumentException: Unknown data type: NoSuchType
createArrayOf("Array(NoSuchType)") -> java.lang.IllegalArgumentException: Unknown data type: NoSuchType
createArrayOf("Nullable(Strng)") -> java.lang.IllegalArgumentException: Unknown data type: Strng
createArrayOf("Array(Int32") -> java.lang.IllegalArgumentException: Missing ')' for '(' at position 5
createArrayOf("Decimal(abc, 2)") -> java.lang.NumberFormatException: For input string: "abc"
createArrayOf("") -> java.lang.IllegalArgumentException: Non-empty typeName is required
createStruct("Tuple(Int8, String)") -> OK
createStruct("Int32") -> java.sql.SQLException (HY000): Only Tuple datatype is supported for Struct
createStruct("NoSuchType") -> java.lang.IllegalArgumentException: Unknown data type: NoSuchType
createStruct("Tuple(NoSuchType, UInt8)") -> java.lang.IllegalArgumentException: Unknown data type: NoSuchType
createStruct("Tuple(Int8, String") -> java.lang.IllegalArgumentException: Missing ')' for '(' at position 5
createStruct("Tuple(Decimal(abc, 2), UInt8)") -> java.lang.NumberFormatException: For input string: "abc"
createStruct("") -> java.lang.IllegalArgumentException: Non-empty typeName is required
createArrayOf(null) / createStruct(null) -> java.sql.SQLFeatureNotSupportedException: typeName cannot be null
closed connection, both methods -> java.sql.SQLException (08000): Connection is closed
The server rejects the same type names (SELECT toTypeName(defaultValueOfTypeName('<type>'))):
NoSuchType Code: 50. DB::Exception: Unknown data type family: NoSuchType ... (UNKNOWN_TYPE)
Nullable(Strng) Code: 50. DB::Exception: Unknown data type family: Strng. Maybe you meant: ['String'] ... (UNKNOWN_TYPE)
Tuple(NoSuchType, UInt8) Code: 50. DB::Exception: Unknown data type family: NoSuchType ... (UNKNOWN_TYPE)
Array(Int32 Code: 62. DB::Exception: Syntax error (data type): ... Unmatched parentheses: '(' at position 6 is never closed ...
Decimal(abc, 2) Code: 43. DB::Exception: Decimal argument precision is invalid ... (ILLEGAL_TYPE_OF_ARGUMENT)
Expected Behaviour
Both methods throw java.sql.SQLException for a type name that they cannot parse, with the parser exception as the cause. Use SQLState HY000, as the other client-side errors in these methods do.
java.sql.Connection Javadoc:
createArrayOf: "SQLException - if a database error occurs, the JDBC type is not appropriate for the typeName and the conversion is not supported, the typeName is null or this method is called on a closed connection"createStruct: "SQLException - if a database error occurs, typeName is null or this method is called on a closed connection"
Code Example
Properties props = new Properties();
props.setProperty("user", "default");
props.setProperty("password", "<password>");
try (Connection conn = DriverManager.getConnection("jdbc:clickhouse://<host>:8123/default", props)) {
try {
conn.createArrayOf("NoSuchType", new Object[] {1});
// same for: conn.createStruct("Tuple(NoSuchType, UInt8)", new Object[] {1, 2});
} catch (SQLException e) {
System.out.println("caught: " + e); // not reached
}
}
// Exception in thread "main" java.lang.IllegalArgumentException: Unknown data type: NoSuchType
Configuration
Client Configuration
// default jdbc-v2 configuration, no extra properties
Environment
- Cloud
- Client version: jdbc-v2
0.12.0-rc1-SNAPSHOT(main, f73e372bc) - Language version: OpenJDK 17.0.21
- OS: Linux (Docker)
ClickHouse Server
- ClickHouse Server version: 26.9.1.1629
- ClickHouse Server non-default settings, if any: none
CREATE TABLEstatements for tables involved: none- Sample data for all these tables: none
Found by automated analysis (Polyglot AI) while investigating #3344. Verified with a program against a live ClickHouse 26.9.1.1629 server, not only by reading the code.
- Linguagem predominante
- Java
- Estrelas
- 1.6k
- Forks
- 649
- Merge médio
- 1d 20h
- PRs com merge (30d)
- 39
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Tem um modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de ClickHouse/clickhouse-java
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
ClickHouse/clickhouse-java#3349 ·
Mantenedores costumam responder em até 1 dia
-
bug jdbc-v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 82/100
ClickHouse/clickhouse-java#3326 ·
Mantenedores costumam responder em até 1 dia
-
[client-v2] Enum8/Enum16 insert accepts a non-member integer and uses Enum.ordinal(), silently storing values that are not enum membersTalvez já em andamento @jaya232 assumiu há 6 dias. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
ClickHouse/clickhouse-java#3304 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
bug jdbc-v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 70/100
ClickHouse/clickhouse-java#3214 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
ClickHouse/clickhouse-java#3212 ·
Mantenedores costumam responder em até 1 dia
Todas as issues de ClickHouse/clickhouse-java
Issues semelhantes
-
bug
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 78/100
Mantenedores costumam responder em até 1 dia
-
bug:unconfirmed
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
UniversalMediaServer/UniversalMediaServer#6473 ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 1/5 Menos de uma hora Facilidade para iniciantes 82/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
StarRocks/starrocks#83246 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
Mantenedores costumam responder em até 2 dias