Skip to content

Commit ed4a6c9

Browse files
committed
Fixed parser issues
1 parent 801cf21 commit ed4a6c9

File tree

4 files changed

+91
-20
lines changed

4 files changed

+91
-20
lines changed

jdbc-v2/src/main/antlr4/com/clickhouse/jdbc/internal/ClickHouseParser.g4

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,20 @@ query
4141

4242
// CTE statement
4343
ctes
44-
: LPAREN? WITH namedQuery (',' namedQuery)* RPAREN?
44+
: LPAREN? WITH (cteUnboundCol COMMA)* namedQuery (COMMA namedQuery)* RPAREN?
4545
;
4646

4747
namedQuery
48-
: name = identifier (columnAliases)? AS '(' query ')'
48+
: name = identifier (columnAliases)? AS LPAREN query RPAREN
4949
;
5050

5151
columnAliases
52-
: '(' identifier (',' identifier)* ')'
52+
: LPAREN? identifier (',' identifier)* RPAREN?
53+
;
54+
55+
cteUnboundCol
56+
: (literal AS identifier) # CteUnboundColLiteral
57+
| (QUERY AS identifier) # CteUnboundColParam
5358
;
5459

5560
// ALTER statement
@@ -407,7 +412,7 @@ projectionSelectStmt
407412
// SELECT statement
408413

409414
selectUnionStmt
410-
: selectStmtWithParens (UNION ALL selectStmtWithParens)*
415+
: selectStmtWithParens (UNION (ALL|DISTINCT)? selectStmtWithParens)*
411416
;
412417

413418
selectStmtWithParens
@@ -1228,6 +1233,12 @@ keywordForAlias
12281233
| VIEW
12291234
| PRIMARY
12301235
| GRANT
1236+
| YEAR
1237+
| DAY
1238+
| MONTH
1239+
| HOUR
1240+
| MINUTE
1241+
| SECOND
12311242
;
12321243

12331244
alias

jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/ParsedPreparedStatement.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ public void enterColumnExprPrecedence3(ClickHouseParser.ColumnExprPrecedence3Con
172172
super.enterColumnExprPrecedence3(ctx);
173173
}
174174

175+
@Override
176+
public void enterCteUnboundColParam(ClickHouseParser.CteUnboundColParamContext ctx) {
177+
appendParameter(ctx.start.getStartIndex());
178+
}
179+
175180
@Override
176181
public void visitErrorNode(ErrorNode node) {
177182
setHasErrors(true);

jdbc-v2/src/test/java/com/clickhouse/jdbc/PreparedStatementTest.java

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,4 +1120,41 @@ public void testSelectWithTableAliasAsKeyword() throws Exception {
11201120
}
11211121
}
11221122
}
1123+
1124+
@Test(groups = {"integration"})
1125+
public void testCTEWithUnboundCol() throws Exception {
1126+
1127+
try (Connection conn = getJdbcConnection()) {
1128+
String cte = "with ? as text, numz as (select text, number from system.numbers limit 10) select * from numz";
1129+
try (PreparedStatement stmt = conn.prepareStatement(cte)) {
1130+
stmt.setString(1, "1000");
1131+
1132+
ResultSet rs = stmt.executeQuery();
1133+
assertTrue(rs.next());
1134+
assertEquals(rs.getString(1), "1000");
1135+
assertEquals(rs.getString(2), "0");
1136+
}
1137+
}
1138+
}
1139+
1140+
@Test(groups = {"integration"})
1141+
public void testWithInClause() throws Exception {
1142+
1143+
try (Connection conn = getJdbcConnection()) {
1144+
String cte = "select number from system.numbers where number in (?) limit 10";
1145+
Long[] filter = new Long[]{2L, 4L, 6L};
1146+
try (PreparedStatement stmt = conn.prepareStatement(cte)) {
1147+
stmt.setArray(1, conn.createArrayOf("Int64", filter));
1148+
ResultSet rs = stmt.executeQuery();
1149+
1150+
for (Long filterValue : filter) {
1151+
assertTrue(rs.next());
1152+
assertEquals(rs.getLong(1), filterValue);
1153+
}
1154+
Assert.assertFalse(rs.next());
1155+
}
1156+
}
1157+
}
1158+
1159+
11231160
}

jdbc-v2/src/test/java/com/clickhouse/jdbc/internal/SqlParserTest.java

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -307,31 +307,30 @@ public Object[][] testMiscStmtDp() {
307307
{"SELECT * FROM `test_data`.`categories` WHERE id = cast(1 as String) or id = ?", 1},
308308
{"select * from test_data.categories WHERE test_data.categories.name = ? limit 4", 1},
309309
{INSERT_INLINE_DATA, 0},
310-
{"select sum(value) from `uuid_filter_db`.`uuid_filter_table` WHERE `uuid_filter_db`.`uuid_filter_table`.`uuid` IN (CAST('36f7f85c-d7f4-49e2-af05-f45d5f6636ad' AS UUID))", 0},
311-
{"SELECT DISTINCT ON (column) FROM table WHER column > ?", 1},
312-
{"SELECT * FROM test_table \nUNION\n DISTINCT SELECT * FROM test_table", 0},
313-
{"SELECT * FROM test_table1 \nUNION\n SELECT * FROM test_table2 WHERE test_table2.column1 = ?", 1},
314-
{PARAMETRIZED_VIEW, 0},
315-
{COMPLEX_CTE, 0},
310+
{"select sum(value) from `uuid_filter_db`.`uuid_filter_table` WHERE `uuid_filter_db`.`uuid_filter_table`.`uuid` IN (CAST('36f7f85c-d7f4-49e2-af05-f45d5f6636ad' AS UUID))", 0},
311+
{"SELECT DISTINCT ON (column) FROM table WHERE column > ?", 1},
312+
{"SELECT * FROM test_table \nUNION\n DISTINCT SELECT * FROM test_table", 0},
313+
{"SELECT * FROM test_table \nUNION\n ALL SELECT * FROM test_table", 0},
314+
{"SELECT * FROM test_table1 \nUNION\n SELECT * FROM test_table2 WHERE test_table2.column1 = ?", 1},
315+
{COMPLEX_CTE, 4},
316+
{SIMPLE_CTE, 0},
317+
{CTE_CONSTANT_AS_VARIABLE, 1},
316318
{"select toYear(dt) year from test WHERE val=?", 1},
319+
{"select 1 year, 2 hour, 3 minute, 4 second", 0},
317320
{"select toYear(dt) AS year from test WHERE val=?", 1},
318321
{"select toYear(dt) AS yearx from test WHERE val=?", 1},
322+
{"SELECT v FROM t WHERE f in (?)", 1},
323+
{"SELECT v FROM t WHERE a > 10 AND event NOT IN (?)", 1},
324+
{"SELECT v FROM t WHERE f in (1, 2, 3)", 0},
325+
{"with ? as val1, numz as (select val1, number from system.numbers limit 10) select * from numz", 1}
319326
};
320327
}
321328

322329
private static final String INSERT_INLINE_DATA =
323330
"INSERT INTO `interval_15_XUTLZWBLKMNZZPRZSKRF`.`checkins` (`timestamp`, `id`) " +
324331
"VALUES ((`now64`(9) + INTERVAL -225 second), 1)";
325332

326-
private static final String PARAMETRIZED_VIEW = "CREATE VIEW default.test\n" +
327-
"AS \n" +
328-
"WITH \n" +
329-
" toDateTime({from:String}, 'Asia/Seoul') AS FROM, \n" +
330-
" date_add(FROM, INTERVAL 1 MINUTE) AS TO, \n" +
331-
" {target_id:String} AS TARGET_ID \n" +
332-
"SELECT FROM, TO, TARGET_ID";
333-
334-
private static final String COMPLEX_CTE = "WITH ? AS starting_time, ? AS ending_time, ? AS session_timeout, ? AS starting_event, ? AS ending_event, SessionData AS (\n" +
333+
private static final String COMPLEX_CTE = "WITH ? AS starting_time, ? AS ending_time, 0 AS session_timeout, '{start}' AS starting_event, '{end}' AS ending_event, SessionData AS (\n" +
335334
" WITH\n" +
336335
" date,\n" +
337336
" arraySort(\n" +
@@ -373,7 +372,7 @@ public Object[][] testMiscStmtDp() {
373372
" FROM tracking.event\n" +
374373
" WHERE\n" +
375374
" project=? AND time>=starting_time AND time<ending_time\n" +
376-
" AND event NOT IN (?, ?, ?, ?)\n" +
375+
" AND event NOT IN (?)\n" +
377376
" GROUP BY\n" +
378377
" date,\n" +
379378
" user_id\n" +
@@ -391,4 +390,23 @@ public Object[][] testMiscStmtDp() {
391390
" SessionOverallInfo\n" +
392391
"ORDER BY\n" +
393392
" SessionOverallInfo.date";
393+
394+
private static final String SIMPLE_CTE = "WITH cte_numbers AS\n" +
395+
"(\n" +
396+
" SELECT\n" +
397+
" num\n" +
398+
" FROM generateRandom('num UInt64', NULL)\n" +
399+
" LIMIT 1000000\n" +
400+
")\n" +
401+
"SELECT\n" +
402+
" count()\n" +
403+
"FROM cte_numbers\n" +
404+
"WHERE num IN (SELECT num FROM cte_numbers)";
405+
406+
private static final String CTE_CONSTANT_AS_VARIABLE = "WITH '2019-08-01 15:23:00' AS ts_upper_bound\n" +
407+
"SELECT *\n" +
408+
"FROM hits\n" +
409+
"WHERE\n" +
410+
" EventDate = toDate(?) AND\n" +
411+
" EventTime <= ts_upper_bound;";
394412
}

0 commit comments

Comments
 (0)