Target client repo
ClickHouse/clickhouse-java
Severity
sev:1 — opt-in surface (only triggers when the BETA_ROW_BINARY_WRITER beta feature is enabled), visible exception (not silent corruption), and the workaround is a one-line edit (drop the backticks from the column list).
Description
When a PreparedStatement is created for an INSERT INTO t (\c1`, `c2`) VALUES (?, ?)-style SQL while the beta clickhouse.jdbc.beta.row_binary_writerdriver property is enabled,jdbc-v2's parser extracts the column names verbatim with the surrounding backticks. Those quoted names are then used as keys against TableSchema.colIndex, which stores bare (unquoted) names, and the lookup throws NoSuchColumnException`.
This is the JDBC-v2 mirror of clickhouse-go's conn_http_batch.go bug: column names parsed from the SQL are not unescaped before being matched against the server-reported schema.
Code path:
-
jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/SqlParserFacade.java line 343–348 (enterInsertStmt):
List<ClickHouseParser.NestedIdentifierContext> names = columns.nestedIdentifier();
String[] insertColumns = new String[names.size()];
for (int i = 0; i < names.size(); i++) {
insertColumns[i] = names.get(i).getText(); // raw token text, keeps backticks
}
parsedStatement.setInsertColumns(insertColumns);
Compare with the table identifier handling a few lines below, which does call ClickHouseSqlUtils.unescape(...).
-
jdbc-v2/src/main/java/com/clickhouse/jdbc/WriterStatementImpl.java line 57–63:
if (parsedStatement.getInsertColumns() != null) {
List<ClickHouseColumn> insertColumns = new ArrayList<>();
for (String column : parsedStatement.getInsertColumns()) {
insertColumns.add(tableSchema.getColumnByName(column)); // NoSuchColumnException
}
...
}
-
client-v2/src/main/java/com/clickhouse/client/api/metadata/TableSchema.java nameToIndex throws:
NoSuchColumnException: Result has no column with name '`field1`'
The PreparedStatementImpl (non-beta) path is unaffected because it forwards the SQL string to the server, which knows how to parse backtick-quoted identifiers itself.
ClickHouse server version
26.4.2.10 (SELECT version() against the local test server). Code analysis only — not run against the server.
Reproduction (jdbc-v2)
// Setup schema
try (Statement st = conn.createStatement()) {
st.execute("DROP TABLE IF EXISTS bt_cols");
st.execute("CREATE TABLE bt_cols (field1 String, field2 String) ENGINE = Memory");
}
// Enable beta RowBinary writer path
Properties props = new Properties();
props.setProperty("clickhouse.jdbc.beta.row_binary_writer", "true");
try (Connection conn = DriverManager.getConnection("jdbc:ch:http://localhost:8123/default", props)) {
String sql = "INSERT INTO bt_cols (`field1`, `field2`) VALUES (?, ?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
ps.setString(1, "a");
ps.setString(2, "b");
ps.executeUpdate(); // expected: 1 row inserted
}
}
Expected: one row ('a', 'b') inserted.
Actual: prepareStatement(...) (or executeUpdate() depending on where the column lookup runs first) throws NoSuchColumnException: Result has no column with name '\field1`'`.
Removing the backticks (INSERT INTO bt_cols (field1, field2) VALUES (?, ?)) succeeds. Disabling the beta row_binary_writer property also avoids the bug because the legacy PreparedStatementImpl path forwards the SQL to the server unchanged.
Suggested fix
In jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/SqlParserFacade.java, unescape each column identifier the same way table/database identifiers are unescaped a few lines below:
insertColumns[i] = ClickHouseSqlUtils.unescape(names.get(i).getText());
This matches the existing handling for tableId.identifier() and databaseIdentifier and should also handle double-quoted identifiers (\"col\") for free since unescape covers both quote styles.
Source bug
ClickHouse/clickhouse-go#848
Target client repo
ClickHouse/clickhouse-javaSeverity
sev:1— opt-in surface (only triggers when theBETA_ROW_BINARY_WRITERbeta feature is enabled), visible exception (not silent corruption), and the workaround is a one-line edit (drop the backticks from the column list).Description
When a
PreparedStatementis created for anINSERT INTO t (\c1`, `c2`) VALUES (?, ?)-style SQL while the betaclickhouse.jdbc.beta.row_binary_writerdriver property is enabled,jdbc-v2's parser extracts the column names verbatim with the surrounding backticks. Those quoted names are then used as keys againstTableSchema.colIndex, which stores bare (unquoted) names, and the lookup throwsNoSuchColumnException`.This is the JDBC-v2 mirror of clickhouse-go's
conn_http_batch.gobug: column names parsed from the SQL are not unescaped before being matched against the server-reported schema.Code path:
jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/SqlParserFacade.javaline 343–348 (enterInsertStmt):Compare with the table identifier handling a few lines below, which does call
ClickHouseSqlUtils.unescape(...).jdbc-v2/src/main/java/com/clickhouse/jdbc/WriterStatementImpl.javaline 57–63:client-v2/src/main/java/com/clickhouse/client/api/metadata/TableSchema.javanameToIndexthrows:The
PreparedStatementImpl(non-beta) path is unaffected because it forwards the SQL string to the server, which knows how to parse backtick-quoted identifiers itself.ClickHouse server version
26.4.2.10 (
SELECT version()against the local test server). Code analysis only — not run against the server.Reproduction (jdbc-v2)
Expected: one row
('a', 'b')inserted.Actual:
prepareStatement(...)(orexecuteUpdate()depending on where the column lookup runs first) throwsNoSuchColumnException: Result has no column with name '\field1`'`.Removing the backticks (
INSERT INTO bt_cols (field1, field2) VALUES (?, ?)) succeeds. Disabling the betarow_binary_writerproperty also avoids the bug because the legacyPreparedStatementImplpath forwards the SQL to the server unchanged.Suggested fix
In
jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/SqlParserFacade.java, unescape each column identifier the same way table/database identifiers are unescaped a few lines below:This matches the existing handling for
tableId.identifier()anddatabaseIdentifierand should also handle double-quoted identifiers (\"col\") for free sinceunescapecovers both quote styles.Source bug
ClickHouse/clickhouse-go#848