Skip to content

Commit bed84ee

Browse files
authored
Merge pull request #2392 from ClickHouse/fix_with_statement
[jdbc-v2] Added test for WITH statement with parameters.
2 parents cec335e + fe265b3 commit bed84ee

File tree

8 files changed

+134
-70
lines changed

8 files changed

+134
-70
lines changed

clickhouse-client/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
<configuration>
9292
<excludes>
9393
<exclude>META-INF/services/*</exclude>
94+
<exclude>com/clickhouse/client/ClickHouseTestClient.class</exclude>
9495
</excludes>
9596
</configuration>
9697
</execution>

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ topClause
382382

383383
fromClause
384384
: FROM joinExpr
385+
| FROM identifier LPAREN QUERY RPAREN
385386
;
386387

387388
arrayJoinClause

jdbc-v2/src/main/java/com/clickhouse/jdbc/ConnectionImpl.java

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,18 @@
3333
import java.sql.SQLWarning;
3434
import java.sql.SQLXML;
3535
import java.sql.Savepoint;
36-
import java.sql.ShardingKey;
3736
import java.sql.Statement;
3837
import java.sql.Struct;
38+
import java.util.Arrays;
3939
import java.util.Calendar;
40+
import java.util.Collections;
4041
import java.util.HashSet;
4142
import java.util.List;
4243
import java.util.Map;
4344
import java.util.Properties;
4445
import java.util.Set;
4546
import java.util.concurrent.Executor;
47+
import java.util.stream.Collectors;
4648

4749
public class ConnectionImpl implements Connection, JdbcV2Wrapper {
4850
private static final Logger log = LoggerFactory.getLogger(ConnectionImpl.class);
@@ -548,7 +550,9 @@ public Properties getClientInfo() throws SQLException {
548550
@Override
549551
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
550552
try {
551-
return new com.clickhouse.jdbc.types.Array(List.of(elements), typeName, JdbcUtils.convertToSqlType(ClickHouseDataType.valueOf(typeName)).getVendorTypeNumber());
553+
List<Object> list =
554+
(elements == null || elements.length == 0) ? Collections.emptyList() : Arrays.stream(elements, 0, elements.length).collect(Collectors.toList());
555+
return new com.clickhouse.jdbc.types.Array(list, typeName, JdbcUtils.convertToSqlType(ClickHouseDataType.valueOf(typeName)).getVendorTypeNumber());
552556
} catch (Exception e) {
553557
throw new SQLException("Failed to create array", ExceptionUtils.SQL_STATE_CLIENT_ERROR, e);
554558
}
@@ -601,36 +605,6 @@ public int getNetworkTimeout() throws SQLException {
601605
return -1;
602606
}
603607

604-
@Override
605-
public void beginRequest() throws SQLException {
606-
Connection.super.beginRequest();
607-
}
608-
609-
@Override
610-
public void endRequest() throws SQLException {
611-
Connection.super.endRequest();
612-
}
613-
614-
@Override
615-
public boolean setShardingKeyIfValid(ShardingKey shardingKey, ShardingKey superShardingKey, int timeout) throws SQLException {
616-
return Connection.super.setShardingKeyIfValid(shardingKey, superShardingKey, timeout);
617-
}
618-
619-
@Override
620-
public boolean setShardingKeyIfValid(ShardingKey shardingKey, int timeout) throws SQLException {
621-
return Connection.super.setShardingKeyIfValid(shardingKey, timeout);
622-
}
623-
624-
@Override
625-
public void setShardingKey(ShardingKey shardingKey, ShardingKey superShardingKey) throws SQLException {
626-
Connection.super.setShardingKey(shardingKey, superShardingKey);
627-
}
628-
629-
@Override
630-
public void setShardingKey(ShardingKey shardingKey) throws SQLException {
631-
Connection.super.setShardingKey(shardingKey);
632-
}
633-
634608
/**
635609
* Returns instance of the client used to execute queries by this connection.
636610
* @return - client instance

jdbc-v2/src/main/java/com/clickhouse/jdbc/DataSourceImpl.java

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55
import javax.sql.DataSource;
66
import java.io.PrintWriter;
77
import java.sql.Connection;
8-
import java.sql.ConnectionBuilder;
98
import java.sql.SQLException;
109
import java.sql.SQLFeatureNotSupportedException;
11-
import java.sql.ShardingKeyBuilder;
1210
import java.util.Properties;
1311
import java.util.logging.Logger;
1412

@@ -78,18 +76,8 @@ public int getLoginTimeout() throws SQLException {
7876
throw new SQLFeatureNotSupportedException("Method not supported", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED);
7977
}
8078

81-
@Override
82-
public ConnectionBuilder createConnectionBuilder() throws SQLException {
83-
return DataSource.super.createConnectionBuilder();
84-
}
85-
8679
@Override
8780
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
8881
throw new SQLFeatureNotSupportedException("Method not supported", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED);
8982
}
90-
91-
@Override
92-
public ShardingKeyBuilder createShardingKeyBuilder() throws SQLException {
93-
return DataSource.super.createShardingKeyBuilder();
94-
}
9583
}

jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -526,30 +526,6 @@ public long executeLargeUpdate(String sql, String[] columnNames) throws SQLExcep
526526
return executeUpdate(sql, columnNames);
527527
}
528528

529-
@Override
530-
public String enquoteLiteral(String val) throws SQLException {
531-
checkClosed();
532-
return Statement.super.enquoteLiteral(val);
533-
}
534-
535-
@Override
536-
public String enquoteIdentifier(String identifier, boolean alwaysQuote) throws SQLException {
537-
checkClosed();
538-
return Statement.super.enquoteIdentifier(identifier, alwaysQuote);
539-
}
540-
541-
@Override
542-
public boolean isSimpleIdentifier(String identifier) throws SQLException {
543-
checkClosed();
544-
return Statement.super.isSimpleIdentifier(identifier);
545-
}
546-
547-
@Override
548-
public String enquoteNCharLiteral(String val) throws SQLException {
549-
checkClosed();
550-
return Statement.super.enquoteNCharLiteral(val);
551-
}
552-
553529
/**
554530
* Return query ID of last executed statement. It is not guaranteed when statements is used concurrently.
555531
* @return query ID

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,13 @@ public void enterInsertParameter(ClickHouseParser.InsertParameterContext ctx) {
188188
appendParameter(ctx.start.getStartIndex());
189189
}
190190

191+
@Override
192+
public void enterFromClause(ClickHouseParser.FromClauseContext ctx) {
193+
if (ctx.QUERY() != null) {
194+
appendParameter(ctx.QUERY().getSymbol().getStartIndex());
195+
}
196+
}
197+
191198
private void appendParameter(int startIndex) {
192199
argCount++;
193200
if (argCount > paramPositions.length) {

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

Lines changed: 117 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
import java.sql.Types;
2121
import java.time.LocalDate;
2222
import java.time.LocalDateTime;
23+
import java.time.ZoneId;
24+
import java.time.temporal.ChronoUnit;
25+
import java.time.temporal.TemporalUnit;
2326
import java.util.ArrayList;
2427
import java.util.Arrays;
2528
import java.util.Collection;
@@ -292,17 +295,129 @@ public void testTernaryOperator() throws Exception {
292295

293296
@Test(groups = "integration")
294297
void testWithClause() throws Exception {
295-
int count = 0;
296298
try (Connection conn = getJdbcConnection()) {
297299
try (PreparedStatement stmt = conn.prepareStatement("with data as (SELECT number FROM numbers(100)) select * from data ")) {
298300
stmt.execute();
299301
ResultSet rs = stmt.getResultSet();
302+
int count = 0;
300303
while (rs.next()) {
301304
count++;
302305
}
306+
assertEquals(count, 100);
307+
}
308+
}
309+
}
310+
311+
@Test(groups = "integration")
312+
void testWithClauseWithParams() throws Exception {
313+
final String table = "test_with_stmt";
314+
try (Connection conn = getJdbcConnection()) {
315+
try (Statement stmt = conn.createStatement()) {
316+
stmt.execute("DROP TABLE IF EXISTS " + table);
317+
stmt.execute("CREATE TABLE " + table + " (v1 String) Engine MergeTree ORDER BY ()");
318+
stmt.execute("INSERT INTO " + table + " VALUES ('A'), ('B')");
319+
}
320+
final Timestamp target_time = Timestamp.valueOf(LocalDateTime.now());
321+
try (PreparedStatement stmt = conn.prepareStatement("WITH " +
322+
" toDateTime(?) as target_time, " +
323+
" (SELECT 123) as magic_number" +
324+
" SELECT *, target_time, magic_number FROM " + table)) {
325+
stmt.setTimestamp(1, target_time);
326+
stmt.execute();
327+
ResultSet rs = stmt.getResultSet();
328+
int count = 0;
329+
assertEquals(rs.getMetaData().getColumnCount(), 3);
330+
while (rs.next()) {
331+
Assert.assertEquals(
332+
rs.getTimestamp("target_time").toLocalDateTime().truncatedTo(ChronoUnit.SECONDS),
333+
target_time.toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime().truncatedTo(ChronoUnit.SECONDS));
334+
Assert.assertEquals(rs.getString("magic_number"), "123");
335+
Assert.assertEquals(
336+
rs.getTimestamp(2).toLocalDateTime().truncatedTo(ChronoUnit.SECONDS),
337+
target_time.toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime().truncatedTo(ChronoUnit.SECONDS));
338+
Assert.assertEquals(rs.getString(3), "123");
339+
340+
count++;
341+
}
342+
assertEquals(count, 2, "Expected 2 rows");
343+
344+
}
345+
}
346+
}
347+
348+
@Test(groups = { "integration" })
349+
void testMultipleWithClauses() throws Exception {
350+
try (Connection conn = getJdbcConnection();
351+
PreparedStatement stmt = conn.prepareStatement(
352+
"WITH data1 AS (SELECT 1 AS a), " +
353+
" data2 AS (SELECT a + 1 AS b FROM data1) " +
354+
"SELECT * FROM data2")) {
355+
ResultSet rs = stmt.executeQuery();
356+
assertTrue(rs.next());
357+
assertEquals(2, rs.getInt(1));
358+
assertFalse(rs.next());
359+
}
360+
}
361+
362+
@Test(groups = { "integration" })
363+
void testRecursiveWithClause() throws Exception {
364+
try (Connection conn = getJdbcConnection();
365+
PreparedStatement stmt = conn.prepareStatement(
366+
"WITH RECURSIVE numbers AS (" +
367+
" SELECT 1 AS n " +
368+
" UNION ALL " +
369+
" SELECT n + 1 FROM numbers WHERE n < 5" +
370+
") " +
371+
"SELECT * FROM numbers ORDER BY n")) {
372+
ResultSet rs = stmt.executeQuery();
373+
for (int i = 1; i <= 5; i++) {
374+
assertTrue(rs.next());
375+
assertEquals(i, rs.getInt(1));
376+
}
377+
assertFalse(rs.next());
378+
}
379+
}
380+
381+
@Test(groups = { "integration" })
382+
void testWithClauseWithMultipleParameters() throws Exception {
383+
try (Connection conn = getJdbcConnection();
384+
PreparedStatement stmt = conn.prepareStatement(
385+
"WITH data AS (" +
386+
" (SELECT number AS n " +
387+
" FROM numbers(?) " +
388+
" WHERE n > ?)" +
389+
") " +
390+
"SELECT * FROM data WHERE n < ?")) {
391+
//"WITH data AS ( (SELECT number AS n FROM numbers(?) WHERE n > ?)) SELECT * FROM data WHERE n < ?"
392+
stmt.setInt(1, 10); // numbers(10) = 0-9
393+
stmt.setInt(2, 3); // n > 3
394+
stmt.setInt(3, 7); // n < 7
395+
396+
ResultSet rs = stmt.executeQuery();
397+
int count = 0;
398+
int expected = 4; // 4,5,6
399+
while (rs.next()) {
400+
count++;
401+
int n = rs.getInt(1);
402+
assertTrue(n > 3 && n < 7);
403+
}
404+
assertEquals(3, count);
405+
}
406+
}
407+
408+
@Test(groups = { "integration" })
409+
void testSelectFromArray() throws Exception {
410+
try (Connection conn = getJdbcConnection();
411+
PreparedStatement stmt = conn.prepareStatement(
412+
"SELECT * FROM numbers(?)")) {
413+
stmt.setInt(1, 10); // numbers(10) = 0-9
414+
ResultSet rs = stmt.executeQuery();
415+
int count = 0;
416+
while (rs.next()) {
417+
count++;
303418
}
419+
assertEquals(10, count);
304420
}
305-
assertEquals(count, 100);
306421
}
307422

308423
@Test(groups = { "integration" })

pom.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,8 @@
593593
<configuration>
594594
<source>${minJdk}</source>
595595
<target>${minJdk}</target>
596+
<testSource>17</testSource>
597+
<testTarget>17</testTarget>
596598
<showWarnings>true</showWarnings>
597599
<compilerArgs>
598600
<arg>-Xlint:all</arg>

0 commit comments

Comments
 (0)