Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions clickhouse-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
<configuration>
<excludes>
<exclude>META-INF/services/*</exclude>
<exclude>com/clickhouse/client/ClickHouseTestClient.class</exclude>
</excludes>
</configuration>
</execution>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ topClause

fromClause
: FROM joinExpr
| FROM identifier LPAREN QUERY RPAREN
;

arrayJoinClause
Expand Down
38 changes: 6 additions & 32 deletions jdbc-v2/src/main/java/com/clickhouse/jdbc/ConnectionImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,18 @@
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Savepoint;
import java.sql.ShardingKey;
import java.sql.Statement;
import java.sql.Struct;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;

public class ConnectionImpl implements Connection, JdbcV2Wrapper {
private static final Logger log = LoggerFactory.getLogger(ConnectionImpl.class);
Expand Down Expand Up @@ -548,7 +550,9 @@ public Properties getClientInfo() throws SQLException {
@Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
try {
return new com.clickhouse.jdbc.types.Array(List.of(elements), typeName, JdbcUtils.convertToSqlType(ClickHouseDataType.valueOf(typeName)).getVendorTypeNumber());
List<Object> list =
(elements == null || elements.length == 0) ? Collections.emptyList() : Arrays.stream(elements, 0, elements.length).collect(Collectors.toList());
return new com.clickhouse.jdbc.types.Array(list, typeName, JdbcUtils.convertToSqlType(ClickHouseDataType.valueOf(typeName)).getVendorTypeNumber());
Comment on lines +553 to +555
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Arrays.stream approach for handling array elements could potentially have issues with null elements within the array. Consider using a more robust approach that explicitly handles null elements within the array:

Suggested change
List<Object> list =
(elements == null || elements.length == 0) ? Collections.emptyList() : Arrays.stream(elements, 0, elements.length).collect(Collectors.toList());
return new com.clickhouse.jdbc.types.Array(list, typeName, JdbcUtils.convertToSqlType(ClickHouseDataType.valueOf(typeName)).getVendorTypeNumber());
List<Object> list = Collections.emptyList();
if (elements != null && elements.length > 0) {
list = Arrays.stream(elements)
.collect(Collectors.toList());
}

} catch (Exception e) {
throw new SQLException("Failed to create array", ExceptionUtils.SQL_STATE_CLIENT_ERROR, e);
}
Expand Down Expand Up @@ -601,36 +605,6 @@ public int getNetworkTimeout() throws SQLException {
return -1;
}

@Override
public void beginRequest() throws SQLException {
Connection.super.beginRequest();
}

@Override
public void endRequest() throws SQLException {
Connection.super.endRequest();
}

@Override
public boolean setShardingKeyIfValid(ShardingKey shardingKey, ShardingKey superShardingKey, int timeout) throws SQLException {
return Connection.super.setShardingKeyIfValid(shardingKey, superShardingKey, timeout);
}

@Override
public boolean setShardingKeyIfValid(ShardingKey shardingKey, int timeout) throws SQLException {
return Connection.super.setShardingKeyIfValid(shardingKey, timeout);
}

@Override
public void setShardingKey(ShardingKey shardingKey, ShardingKey superShardingKey) throws SQLException {
Connection.super.setShardingKey(shardingKey, superShardingKey);
}

@Override
public void setShardingKey(ShardingKey shardingKey) throws SQLException {
Connection.super.setShardingKey(shardingKey);
}

/**
* Returns instance of the client used to execute queries by this connection.
* @return - client instance
Expand Down
12 changes: 0 additions & 12 deletions jdbc-v2/src/main/java/com/clickhouse/jdbc/DataSourceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,8 @@
import javax.sql.DataSource;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ConnectionBuilder;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.ShardingKeyBuilder;
import java.util.Properties;
import java.util.logging.Logger;

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

@Override
public ConnectionBuilder createConnectionBuilder() throws SQLException {
return DataSource.super.createConnectionBuilder();
}

@Override
public Logger getParentLogger() throws SQLFeatureNotSupportedException {
throw new SQLFeatureNotSupportedException("Method not supported", ExceptionUtils.SQL_STATE_FEATURE_NOT_SUPPORTED);
}

@Override
public ShardingKeyBuilder createShardingKeyBuilder() throws SQLException {
return DataSource.super.createShardingKeyBuilder();
}
}
24 changes: 0 additions & 24 deletions jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -526,30 +526,6 @@ public long executeLargeUpdate(String sql, String[] columnNames) throws SQLExcep
return executeUpdate(sql, columnNames);
}

@Override
public String enquoteLiteral(String val) throws SQLException {
checkClosed();
return Statement.super.enquoteLiteral(val);
}

@Override
public String enquoteIdentifier(String identifier, boolean alwaysQuote) throws SQLException {
checkClosed();
return Statement.super.enquoteIdentifier(identifier, alwaysQuote);
}

@Override
public boolean isSimpleIdentifier(String identifier) throws SQLException {
checkClosed();
return Statement.super.isSimpleIdentifier(identifier);
}

@Override
public String enquoteNCharLiteral(String val) throws SQLException {
checkClosed();
return Statement.super.enquoteNCharLiteral(val);
}

/**
* Return query ID of last executed statement. It is not guaranteed when statements is used concurrently.
* @return query ID
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,13 @@ public void enterInsertParameter(ClickHouseParser.InsertParameterContext ctx) {
appendParameter(ctx.start.getStartIndex());
}

@Override
public void enterFromClause(ClickHouseParser.FromClauseContext ctx) {
if (ctx.QUERY() != null) {
appendParameter(ctx.QUERY().getSymbol().getStartIndex());
}
}

private void appendParameter(int startIndex) {
argCount++;
if (argCount > paramPositions.length) {
Expand Down
119 changes: 117 additions & 2 deletions jdbc-v2/src/test/java/com/clickhouse/jdbc/PreparedStatementTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
Expand Down Expand Up @@ -292,17 +295,129 @@ public void testTernaryOperator() throws Exception {

@Test(groups = "integration")
void testWithClause() throws Exception {
int count = 0;
try (Connection conn = getJdbcConnection()) {
try (PreparedStatement stmt = conn.prepareStatement("with data as (SELECT number FROM numbers(100)) select * from data ")) {
stmt.execute();
ResultSet rs = stmt.getResultSet();
int count = 0;
while (rs.next()) {
count++;
}
assertEquals(count, 100);
}
}
}

@Test(groups = "integration")
void testWithClauseWithParams() throws Exception {
final String table = "test_with_stmt";
try (Connection conn = getJdbcConnection()) {
try (Statement stmt = conn.createStatement()) {
stmt.execute("DROP TABLE IF EXISTS " + table);
stmt.execute("CREATE TABLE " + table + " (v1 String) Engine MergeTree ORDER BY ()");
stmt.execute("INSERT INTO " + table + " VALUES ('A'), ('B')");
}
final Timestamp target_time = Timestamp.valueOf(LocalDateTime.now());
try (PreparedStatement stmt = conn.prepareStatement("WITH " +
" toDateTime(?) as target_time, " +
" (SELECT 123) as magic_number" +
" SELECT *, target_time, magic_number FROM " + table)) {
stmt.setTimestamp(1, target_time);
stmt.execute();
ResultSet rs = stmt.getResultSet();
int count = 0;
assertEquals(rs.getMetaData().getColumnCount(), 3);
while (rs.next()) {
Assert.assertEquals(
rs.getTimestamp("target_time").toLocalDateTime().truncatedTo(ChronoUnit.SECONDS),
target_time.toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime().truncatedTo(ChronoUnit.SECONDS));
Assert.assertEquals(rs.getString("magic_number"), "123");
Assert.assertEquals(
rs.getTimestamp(2).toLocalDateTime().truncatedTo(ChronoUnit.SECONDS),
target_time.toInstant().atZone(ZoneId.of("UTC")).toLocalDateTime().truncatedTo(ChronoUnit.SECONDS));
Assert.assertEquals(rs.getString(3), "123");

count++;
}
assertEquals(count, 2, "Expected 2 rows");

}
}
}

@Test(groups = { "integration" })
void testMultipleWithClauses() throws Exception {
try (Connection conn = getJdbcConnection();
PreparedStatement stmt = conn.prepareStatement(
"WITH data1 AS (SELECT 1 AS a), " +
" data2 AS (SELECT a + 1 AS b FROM data1) " +
"SELECT * FROM data2")) {
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertFalse(rs.next());
}
}

@Test(groups = { "integration" })
void testRecursiveWithClause() throws Exception {
try (Connection conn = getJdbcConnection();
PreparedStatement stmt = conn.prepareStatement(
"WITH RECURSIVE numbers AS (" +
" SELECT 1 AS n " +
" UNION ALL " +
" SELECT n + 1 FROM numbers WHERE n < 5" +
") " +
"SELECT * FROM numbers ORDER BY n")) {
ResultSet rs = stmt.executeQuery();
for (int i = 1; i <= 5; i++) {
assertTrue(rs.next());
assertEquals(i, rs.getInt(1));
}
assertFalse(rs.next());
}
}

@Test(groups = { "integration" })
void testWithClauseWithMultipleParameters() throws Exception {
try (Connection conn = getJdbcConnection();
PreparedStatement stmt = conn.prepareStatement(
"WITH data AS (" +
" (SELECT number AS n " +
" FROM numbers(?) " +
" WHERE n > ?)" +
") " +
"SELECT * FROM data WHERE n < ?")) {
//"WITH data AS ( (SELECT number AS n FROM numbers(?) WHERE n > ?)) SELECT * FROM data WHERE n < ?"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This commented-out SQL query on line 391 should be removed as it appears to be for debugging purposes only.

stmt.setInt(1, 10); // numbers(10) = 0-9
stmt.setInt(2, 3); // n > 3
stmt.setInt(3, 7); // n < 7

ResultSet rs = stmt.executeQuery();
int count = 0;
int expected = 4; // 4,5,6
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a mismatch between the comment and the assertion. The comment on line 398 says expected is 4 for numbers 4,5,6 (which is actually 3 numbers), but the assertion on line 404 correctly checks for 3. Please update the comment to match the assertion.

while (rs.next()) {
count++;
int n = rs.getInt(1);
assertTrue(n > 3 && n < 7);
}
assertEquals(3, count);
}
}

@Test(groups = { "integration" })
void testSelectFromArray() throws Exception {
try (Connection conn = getJdbcConnection();
PreparedStatement stmt = conn.prepareStatement(
"SELECT * FROM numbers(?)")) {
stmt.setInt(1, 10); // numbers(10) = 0-9
ResultSet rs = stmt.executeQuery();
int count = 0;
while (rs.next()) {
count++;
}
assertEquals(10, count);
}
assertEquals(count, 100);
}

@Test(groups = { "integration" })
Expand Down
2 changes: 2 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -593,6 +593,8 @@
<configuration>
<source>${minJdk}</source>
<target>${minJdk}</target>
<testSource>17</testSource>
<testTarget>17</testTarget>
<showWarnings>true</showWarnings>
<compilerArgs>
<arg>-Xlint:all</arg>
Expand Down
Loading