Skip to content

[jdbc-v2] Implements java.sql.PreparedStatement#getMetaData #2311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Apr 17, 2025

Conversation

chernser
Copy link
Contributor

@chernser chernser commented Apr 16, 2025

Summary

  • Implement java.sql.PreparedStatement#getMetaData
  • Returned metadata is either filled with columns (for SELECT) or an empty object with 0 columns.

Closes #2292
Closes #2311

Checklist

Delete items not relevant to your PR:

@chernser chernser requested review from Paultagoras and mzitnik and removed request for Paultagoras April 16, 2025 18:23
@chernser chernser requested a review from Paultagoras April 17, 2025 03:36
private static Map<ClickHouseDataType, Class<?>> getDataTypeClassMap() {
Map<ClickHouseDataType, Class<?>> map = new HashMap<>();
for (Map.Entry<ClickHouseDataType, SQLType> e : CLICKHOUSE_TO_SQL_TYPE_MAP.entrySet()) {
map.put(e.getKey(), SQL_TYPE_TO_CLASS_MAP.get(e.getValue()));
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this actually go the whole way from ClickHouseDataType -> SqlType -> Class?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes, but we need to make it more bound to actual code. I mean there should be a single source of truth.

assertNotNull(metadataRs);
assertEquals(metadataRs.getColumnCount(), colCountAfterExecution);
for (int i = 1; i <= metadataRs.getColumnCount(); i++) {
System.out.println("label=" + metadataRs.getColumnName(i) + " type=" + metadataRs.getColumnType(i));
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets remove it

@mshustov mshustov requested a review from Copilot April 17, 2025 08:51
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements the java.sql.PreparedStatement#getMetaData method to return metadata for SELECT queries (with column details) and an empty metadata object for non-SELECT queries. Key changes include:

  • Adding tests in PreparedStatementTest for getMetaData behavior.
  • Updating metadata implementations and utility methods across ResultSet, Statement, and PreparedStatement classes.
  • Refactoring and cleanup of unused imports and legacy metadata classes.

Reviewed Changes

Copilot reviewed 23 out of 26 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
jdbc-v2/src/test/java/com/clickhouse/jdbc/StatementTest.java Removed unused imports.
jdbc-v2/src/test/java/com/clickhouse/jdbc/PreparedStatementTest.java Added tests and data provider for PreparedStatement#getMetaData.
jdbc-v2/src/test/java/com/clickhouse/jdbc/JdbcIntegrationTest.java Cleaned up import statements.
jdbc-v2/src/test/java/com/clickhouse/jdbc/ConnectionTest.java Removed unused imports.
jdbc-v2/src/main/java/com/clickhouse/jdbc/types/Array.java Removed unused import.
jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/ResultSetMetaDataImpl.java Refactored to use a new column list and schema properties.
jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/ParameterMetaDataImpl.java New implementation providing minimal parameter metadata.
jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/ParameterMetaData.java Removed legacy metadata implementation.
jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/MetadataResultSet.java Updated to instantiate the new ResultSetMetaDataImpl.
jdbc-v2/src/main/java/com/clickhouse/jdbc/internal/JdbcUtils.java Adopted ImmutableMap for type maps and added a new replaceQuestionMarks utility.
jdbc-v2/src/main/java/com/clickhouse/jdbc/StatementImpl.java Made slight refactoring and ensured proper schema assignment.
jdbc-v2/src/main/java/com/clickhouse/jdbc/ResultSetImpl.java Adjusted metadata initialization and assignment.
jdbc-v2/src/main/java/com/clickhouse/jdbc/PreparedStatementImpl.java Updated getMetaData and getParameterMetaData implementations.
client-v2/src/main/java/com/clickhouse/client/api/metadata/TableSchema.java Removed unused imports.
.github/workflows/analysis.yml Updated sonar command parameters.
Files not reviewed (3)
  • clickhouse-jdbc/pom.xml: Language not supported
  • client-v2/pom.xml: Language not supported
  • jdbc-v2/pom.xml: Language not supported
Comments suppressed due to low confidence (1)

jdbc-v2/src/main/java/com/clickhouse/jdbc/metadata/ResultSetMetaDataImpl.java:35

  • [nitpick] Consider performing an explicit boundary check for 'column' instead of relying on catching IndexOutOfBoundsException. This could improve readability and make the error handling more intentional.
try { return columns.get(column - 1); } catch (IndexOutOfBoundsException e) {

@@ -303,7 +309,31 @@ 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
Preview

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.


public static final String NULL = "NULL";

private static final Pattern REPLACE_Q_MARK_PATTERN = Pattern.compile("(\"[^\"]*\"|`[^`]*`)|(\\?)");
Copy link
Preview

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.

The current regex pattern only handles double-quoted and backtick-quoted strings. Since SQL string literals are usually single-quoted, consider extending the pattern to also cover single-quoted strings to avoid unintended replacements.

Suggested change
private static final Pattern REPLACE_Q_MARK_PATTERN = Pattern.compile("(\"[^\"]*\"|`[^`]*`)|(\\?)");
private static final Pattern REPLACE_Q_MARK_PATTERN = Pattern.compile("(\"[^\"]*\"|`[^`]*`|'[^']*')|(\\?)");

Copilot uses AI. Check for mistakes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! That helped a lot!

Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
0.0% Coverage on New Code (required ≥ 80%)

See analysis details on SonarQube Cloud

@chernser chernser merged commit e62a180 into main Apr 17, 2025
24 of 25 checks passed
@chernser chernser deleted the jdbc_prepared_stmt_metadata branch April 17, 2025 18:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[jdbc-v2] Prepared statement metadata returns null
3 participants