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
2 changes: 1 addition & 1 deletion .github/workflows/analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,5 +96,5 @@ jobs:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: |
mvn --batch-mode -DclickhouseVersion=$PREFERRED_LTS_VERSION \
-Panalysis verify org.sonarsource.scanner.maven:sonar-maven-plugin:sonar
-Panalysis org.sonarsource.scanner.maven:sonar-maven-plugin:sonar verify
continue-on-error: true
1 change: 1 addition & 0 deletions clickhouse-jdbc/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<javacc-plugin.version>4.1.4</javacc-plugin.version>
<spec.title>JDBC</spec.title>
<spec.version>4.2</spec.version>
<sonar.coverage.jacoco.xmlReportPaths>${project.basedir}/target/site/jacoco-aggregate/jacoco.xml</sonar.coverage.jacoco.xmlReportPaths>

<imageName>clickhouse-jdbc-bin</imageName>
<mainClass>com.clickhouse.jdbc.Main</mainClass>
Expand Down
1 change: 1 addition & 0 deletions client-v2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>

<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

Expand Down
1 change: 0 additions & 1 deletion jdbc-v2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
<javacc-plugin.version>4.1.4</javacc-plugin.version>
<spec.title>JDBC</spec.title>
<spec.version>4.2</spec.version>

<shade.base>${project.groupId}.shaded</shade.base>
</properties>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package com.clickhouse.jdbc;

import com.clickhouse.client.api.metadata.TableSchema;
import com.clickhouse.data.ClickHouseColumn;
import com.clickhouse.data.Tuple;
import com.clickhouse.jdbc.internal.ExceptionUtils;
import com.clickhouse.jdbc.internal.JdbcUtils;
import com.clickhouse.jdbc.metadata.ParameterMetaDataImpl;
import com.clickhouse.jdbc.metadata.ResultSetMetaDataImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -28,7 +30,6 @@
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLType;
import java.sql.SQLXML;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
Expand All @@ -45,6 +46,7 @@
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

Expand All @@ -64,24 +66,28 @@ public class PreparedStatementImpl extends StatementImpl implements PreparedStat
String [] valueSegments;
Object [] parameters;
String insertIntoSQL;

StatementType statementType;

private final ParameterMetaData parameterMetaData;

private ResultSetMetaData resultSetMetaData = null;

public PreparedStatementImpl(ConnectionImpl connection, String sql) throws SQLException {
super(connection);
this.originalSql = sql.trim();
//Split the sql string into an array of strings around question mark tokens
this.sqlSegments = splitStatement(originalSql);
this.statementType = parseStatementType(originalSql);

if (statementType == StatementType.INSERT) {
if (this.statementType == StatementType.INSERT) {
insertIntoSQL = originalSql.substring(0, originalSql.indexOf("VALUES") + 6);
valueSegments = originalSql.substring(originalSql.indexOf("VALUES") + 6).split("\\?");
}

//Create an array of objects to store the parameters
this.parameters = new Object[sqlSegments.length - 1];
this.defaultCalendar = connection.defaultCalendar;
this.parameterMetaData = new ParameterMetaDataImpl(this.parameters.length);
}

private String compileSql(String [] segments) {
Expand Down Expand Up @@ -303,7 +309,32 @@ public void setArray(int parameterIndex, Array x) throws SQLException {
@Override
public ResultSetMetaData getMetaData() throws SQLException {
checkClosed();
return null;

if (resultSetMetaData == null && currentResultSet == null) {
Copy link

Copilot AI Apr 17, 2025

Choose a reason for hiding this comment

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

Consider adding inline documentation clarifying that replacing question marks with 'NULL' is solely used for schema inference. This will help future maintainers understand potential limitations when the SQL contains literal question marks.

Copilot uses AI. Check for mistakes.
// before execution
if (statementType == StatementType.SELECT) {
try {
// Replace '?' with NULL to make SQL valid for DESCRIBE
String sql = JdbcUtils.replaceQuestionMarks(originalSql, JdbcUtils.NULL);
TableSchema tSchema = connection.getClient().getTableSchemaFromQuery(sql);
resultSetMetaData = new ResultSetMetaDataImpl(tSchema.getColumns(),
connection.getSchema(), connection.getCatalog(),
tSchema.getTableName(), JdbcUtils.DATA_TYPE_CLASS_MAP);
} catch (Exception e) {
LOG.warn("Failed to get schema for statement '{}'", originalSql);
}
}

if (resultSetMetaData == null) {
resultSetMetaData = new ResultSetMetaDataImpl(Collections.emptyList(),
connection.getSchema(), connection.getCatalog(),
"", JdbcUtils.DATA_TYPE_CLASS_MAP);
}
} else if (currentResultSet != null) {
resultSetMetaData = currentResultSet.getMetaData();
}

return resultSetMetaData;
}

@Override
Expand Down Expand Up @@ -350,10 +381,18 @@ public void setURL(int parameterIndex, URL x) throws SQLException {
parameters[parameterIndex - 1] = encodeObject(x);
}

/**
* Returned metadata has only minimal information about parameters. Currently only their count.
* Current implementation do not parse SQL to detect type of each parameter.
*
* @see ParameterMetaDataImpl
* @return {@link ParameterMetaDataImpl}
* @throws SQLException if the statement is close
*/
@Override
public ParameterMetaData getParameterMetaData() throws SQLException {
checkClosed();
return null;
return parameterMetaData;
}

@Override
Expand Down
57 changes: 41 additions & 16 deletions jdbc-v2/src/main/java/com/clickhouse/jdbc/ResultSetImpl.java
Original file line number Diff line number Diff line change
@@ -1,33 +1,49 @@
package com.clickhouse.jdbc;

import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
import com.clickhouse.client.api.metadata.TableSchema;
import com.clickhouse.client.api.query.QueryResponse;
import com.clickhouse.data.ClickHouseColumn;
import com.clickhouse.data.ClickHouseDataType;
import com.clickhouse.jdbc.internal.ExceptionUtils;
import com.clickhouse.jdbc.internal.JdbcUtils;
import com.clickhouse.jdbc.metadata.ResultSetMetaDataImpl;
import com.clickhouse.jdbc.types.Array;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.sql.SQLType;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.ZonedDateTime;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.clickhouse.client.api.data_formats.ClickHouseBinaryFormatReader;
import com.clickhouse.client.api.metadata.TableSchema;
import com.clickhouse.client.api.query.QueryResponse;
import com.clickhouse.data.ClickHouseColumn;
import com.clickhouse.data.ClickHouseDataType;
import com.clickhouse.jdbc.internal.ExceptionUtils;
import com.clickhouse.jdbc.internal.JdbcUtils;
import com.clickhouse.jdbc.types.Array;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ResultSetImpl implements ResultSet, JdbcV2Wrapper {
private static final Logger log = LoggerFactory.getLogger(ResultSetImpl.class);
private final ResultSetMetaData metaData;
private ResultSetMetaData metaData;
protected ClickHouseBinaryFormatReader reader;
private QueryResponse response;
private boolean closed;
Expand All @@ -39,7 +55,12 @@ public ResultSetImpl(StatementImpl parentStatement, QueryResponse response, Clic
this.parentStatement = parentStatement;
this.response = response;
this.reader = reader;
this.metaData = new com.clickhouse.jdbc.metadata.ResultSetMetaData(this);
TableSchema tableMetadata = reader.getSchema();

// Result set contains columns from one database (there is a special table engine 'Merge' to do cross DB queries)
this.metaData = new ResultSetMetaDataImpl(tableMetadata
.getColumns(), response.getSettings().getDatabase(), "", tableMetadata.getTableName(),
JdbcUtils.DATA_TYPE_CLASS_MAP);
this.closed = false;
this.wasNull = false;
this.defaultCalendar = parentStatement.connection.defaultCalendar;
Expand All @@ -49,7 +70,7 @@ protected ResultSetImpl(ResultSetImpl resultSet) {
this.parentStatement = resultSet.parentStatement;
this.response = resultSet.response;
this.reader = resultSet.reader;
this.metaData = new com.clickhouse.jdbc.metadata.ResultSetMetaData(this);
this.metaData = resultSet.metaData;
this.closed = false;
this.wasNull = false;
this.defaultCalendar = parentStatement.connection.defaultCalendar;
Expand Down Expand Up @@ -431,6 +452,10 @@ public ResultSetMetaData getMetaData() throws SQLException {
return metaData;
}

protected void setMetaData(ResultSetMetaDataImpl metaData) {
this.metaData = metaData;
}

@Override
public Object getObject(int columnIndex) throws SQLException {
return getObject(columnIndex, JdbcUtils.convertToJavaClass(getSchema().getColumnByIndex(columnIndex).getDataType()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
Expand Down Expand Up @@ -60,7 +59,7 @@ protected enum StatementType {
SELECT, INSERT, DELETE, UPDATE, CREATE, DROP, ALTER, TRUNCATE, USE, SHOW, DESCRIBE, EXPLAIN, SET, KILL, OTHER, INSERT_INTO_SELECT
}

protected static StatementType parseStatementType(String sql) {
public static StatementType parseStatementType(String sql) {
if (sql == null) {
return StatementType.OTHER;
}
Expand Down Expand Up @@ -184,6 +183,7 @@ public ResultSetImpl executeQuery(String sql, QuerySettings settings) throws SQL
mergedSettings.setQueryId(lastQueryId);
}
LOG.debug("Query ID: {}", lastQueryId);
mergedSettings.setDatabase(connection.getSchema());

try {
lastSql = parseJdbcEscapeSyntax(sql);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
package com.clickhouse.jdbc.internal;
public enum ClientInfoProperties {
APPLICATION_NAME("ApplicationName", 255, "", "Client application name."),
;
private String key;
private int maxValue;
private String defaultValue;
private String description;
ClientInfoProperties(String key, int maxValue, String defaultValue, String description) {
this.key = key;
this.maxValue = maxValue;
this.defaultValue = defaultValue;
this.description = description;
}
public String getKey() {
return key;
}
public int getMaxValue() {
return maxValue;
}
public String getDefaultValue() {
return defaultValue;
}
public String getDescription() {
return description;
}
}
package com.clickhouse.jdbc.internal;

public enum ClientInfoProperties {

APPLICATION_NAME("ApplicationName", 255, "", "Client application name."),
;

private String key;
private int maxValue;

private String defaultValue;

private String description;

ClientInfoProperties(String key, int maxValue, String defaultValue, String description) {
this.key = key;
this.maxValue = maxValue;
this.defaultValue = defaultValue;
this.description = description;
}

public String getKey() {
return key;
}

public int getMaxValue() {
return maxValue;
}

public String getDefaultValue() {
return defaultValue;
}

public String getDescription() {
return description;
}
}
Loading
Loading