From 5b5082ad6e03af7f7dddd9bab04b1456ecd45d76 Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Mon, 2 Mar 2026 10:54:52 -0800 Subject: [PATCH 1/2] fixed parser to handle '^' in statements --- jdbc-v2/src/main/javacc/ClickHouseSqlParser.jj | 7 ++++--- .../clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/jdbc-v2/src/main/javacc/ClickHouseSqlParser.jj b/jdbc-v2/src/main/javacc/ClickHouseSqlParser.jj index f076e1185..3140e04e8 100644 --- a/jdbc-v2/src/main/javacc/ClickHouseSqlParser.jj +++ b/jdbc-v2/src/main/javacc/ClickHouseSqlParser.jj @@ -831,7 +831,7 @@ void columnExpr(): { Token t; } { | (LOOKAHEAD(2) macro())+ | LOOKAHEAD(2, { !(tokenIn(1, INF, NAN, NULL) && tokenIn(2, DOT)) }) literal() | LOOKAHEAD(2, { getToken(2).kind == LPAREN }) functionExpr() { token_source.funcUsed = true; } - | anyIdentifier() (LOOKAHEAD(2) anyIdentifier())* + | anyIdentifier() (LOOKAHEAD(2) ()? anyIdentifier())* } // interested parts @@ -930,7 +930,7 @@ Token aliasExpr(): { Token t = null; } { } void nestedIdentifier(): {} { - ( | anyIdentifier()) (LOOKAHEAD(2) ( | anyIdentifier()))* + ( | anyIdentifier()) (LOOKAHEAD(2) ()? ( | anyIdentifier()))* } void tableIdentifier(boolean record): { } { @@ -1029,7 +1029,7 @@ Token numberLiteral(): { Token t = null; StringBuilder sb = new StringBuilder(); } void operator(): {} { - ( | | | | | | + ( | | | | | | | | | | | | | | | ) } @@ -1286,6 +1286,7 @@ TOKEN: { | | | + | | <#UNDERSCORE: "_"> } diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java index cdb26a519..cc93a43a6 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java @@ -652,7 +652,8 @@ public static Object[][] testStatementWithoutResultSetDP() { {"CHECK GRANT SELECT(col2) ON table_2", 0, true}, {"CHECK TABLE test_table", 0, true}, {"CHECK TABLE t0 PARTITION ID '201003' FORMAT PrettyCompactMonoBlock SETTINGS check_query_single_value_result = 0", 0, true}, - + {"select toJSONString(data.^header_index) from database.analyzed limit 1;", 0, true}, + {"select toJSONString(data.^header_index), ? as text from database.analyzed limit 1;", 1, true}, /* no result set */ {"INSERT INTO test_table VALUES (1, ?)", 1, false}, From 3624efdded324e4e38af10d37974b2d36fb5e429 Mon Sep 17 00:00:00 2001 From: Sergey Chernov Date: Mon, 2 Mar 2026 11:03:08 -0800 Subject: [PATCH 2/2] Added verification tests for a few specific statements --- .../jdbc/internal/BaseSqlParserFacadeTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java b/jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java index cc93a43a6..48366f911 100644 --- a/jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java +++ b/jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/BaseSqlParserFacadeTest.java @@ -454,6 +454,10 @@ public Object[][] testMiscStmtDp() { {"select countIf(*, 1 = ?)", 1}, {"select count(*) filter (where 1 = ?)", 1}, {WHEN_HAS_ARRAY, 0}, + {EXTEND_JOIN_ALIAS_SYNTAX, 0}, + {"SELECT * FROM t WHERE hasToken(message, 'DDLWorker')", 0}, + {"SELECT * FROM t WHERE hasAllTokens(message, ['peak', 'memory'])", 0}, + {"SELECT * FROM t WHERE hasAnyTokens(message, tokens('01442_merge_detach_attach'))", 0}, }; } @@ -569,6 +573,11 @@ public Object[][] testMiscStmtDp() { " END AS action_to_do\n" + "FROM db.table1"; + private static final String EXTEND_JOIN_ALIAS_SYNTAX = "SELECT *\n" + + "FROM (SELECT 1) AS t(a)\n" + + "JOIN (SELECT 1) AS u(b)\n" + + "ON a = b"; + @Test(dataProvider = "testStatementWithoutResultSetDP") public void testStatementsForResultSet(String sql, int args, boolean hasResultSet) { System.out.println("sql: " + sql);