Skip to content

Commit 9302048

Browse files
committed
Merge branch 'main' into add-more-v2-examples
2 parents 6c9cb9a + abe31c6 commit 9302048

File tree

18 files changed

+246
-36
lines changed

18 files changed

+246
-36
lines changed

.github/workflows/nightly.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ on:
1212

1313
env:
1414
CHC_BRANCH: "main"
15-
CHC_VERSION: "0.6.0"
15+
CHC_VERSION: "0.6.1"
1616

1717
jobs:
1818
nightly:
@@ -69,8 +69,8 @@ jobs:
6969
maven_args: -q --batch-mode
7070
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
7171
gpg_passphrase: ${{ secrets.GPG_PASSPHRASE }}
72-
nexus_username: ${{ secrets.SONATYPE_USER }}
73-
nexus_password: ${{ secrets.SONATYPE_PASSWD }}
72+
nexus_username: ${{ secrets.SONATYPE_TOKEN_USER }}
73+
nexus_password: ${{ secrets.SONATYPE_TOKEN }}
7474
- name: Release R2DBC 0.9.1 Snapshot
7575
uses: samuelmeuli/action-maven-publish@v1
7676
with:
@@ -79,5 +79,5 @@ jobs:
7979
maven_args: -q --batch-mode -Dr2dbc-spi.version=0.9.1.RELEASE
8080
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
8181
gpg_passphrase: ${{ secrets.GPG_PASSPHRASE }}
82-
nexus_username: ${{ secrets.SONATYPE_USER }}
83-
nexus_password: ${{ secrets.SONATYPE_PASSWD }}
82+
nexus_username: ${{ secrets.SONATYPE_TOKEN_USER }}
83+
nexus_password: ${{ secrets.SONATYPE_TOKEN }}

.github/workflows/release.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ on:
66
version:
77
description: "Release version"
88
required: true
9-
default: "0.6.0-SNAPSHOT"
9+
default: "0.6.1-SNAPSHOT"
1010

1111
jobs:
1212
release:
@@ -57,8 +57,8 @@ jobs:
5757
maven_args: -q --batch-mode
5858
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
5959
gpg_passphrase: ${{ secrets.GPG_PASSPHRASE }}
60-
nexus_username: ${{ secrets.SONATYPE_USER }}
61-
nexus_password: ${{ secrets.SONATYPE_PASSWD }}
60+
nexus_username: ${{ secrets.SONATYPE_TOKEN_USER }}
61+
nexus_password: ${{ secrets.SONATYPE_TOKEN }}
6262
- name: Release R2DBC 0.9.1
6363
uses: samuelmeuli/action-maven-publish@v1
6464
with:
@@ -67,8 +67,8 @@ jobs:
6767
maven_args: -q --batch-mode -Dr2dbc-spi.version=0.9.1.RELEASE
6868
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
6969
gpg_passphrase: ${{ secrets.GPG_PASSPHRASE }}
70-
nexus_username: ${{ secrets.SONATYPE_USER }}
71-
nexus_password: ${{ secrets.SONATYPE_PASSWD }}
70+
nexus_username: ${{ secrets.SONATYPE_TOKEN_USER }}
71+
nexus_password: ${{ secrets.SONATYPE_TOKEN }}
7272
- name: Create Pre-release on Github
7373
uses: "zhicwu/action-automatic-releases@latest"
7474
with:

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
## Latest
22

3+
### New Features
4+
- Describe non-executed SELECT queries in prepared statements to provide metadata (https://github.com/ClickHouse/clickhouse-java/issues/1430)
5+
36
## 0.6.1
47

58
### New Features

clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseNode.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,10 @@ public static ClickHouseNode of(String uri, Map<?, ?> options) {
787787
String scheme = normalizedUri.getScheme();
788788
ClickHouseProtocol protocol = ClickHouseProtocol.fromUriScheme(scheme);
789789
int port = extract(scheme, normalizedUri.getPort(), protocol, params);
790-
790+
if ((options == null || options.get(ClickHouseClientOption.SSL.getKey()) == null)
791+
&& scheme.equalsIgnoreCase("https")) {
792+
params.put(ClickHouseClientOption.SSL.getKey(), "true");
793+
}
791794
ClickHouseCredentials credentials = extract(normalizedUri.getRawUserInfo(), params, null);
792795

793796
return new ClickHouseNode(normalizedUri.getHost(), protocol, port, credentials, params, tags);

clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/ClickHousePreparedStatement.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,17 @@ default void setClob(int parameterIndex, Clob x) throws SQLException {
109109
@Override
110110
default ResultSetMetaData getMetaData() throws SQLException {
111111
ResultSet currentResult = getResultSet();
112-
return currentResult != null ? currentResult.getMetaData() : null;
112+
if (currentResult != null) {
113+
return currentResult.getMetaData();
114+
} else if (getLargeUpdateCount() != -1L) {
115+
return null; // Update query
116+
}
117+
118+
return describeQueryResult();
119+
}
120+
121+
default ResultSetMetaData describeQueryResult() throws SQLException {
122+
return null;
113123
}
114124

115125
@Override

clickhouse-jdbc/src/main/java/com/clickhouse/jdbc/internal/SqlBasedPreparedStatement.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import java.sql.Date;
66
import java.sql.ParameterMetaData;
77
import java.sql.ResultSet;
8+
import java.sql.ResultSetMetaData;
89
import java.sql.SQLException;
10+
import java.sql.Statement;
911
import java.sql.Time;
1012
import java.sql.Timestamp;
1113
import java.time.LocalDate;
@@ -35,7 +37,9 @@
3537
import com.clickhouse.data.value.ClickHouseStringValue;
3638
import com.clickhouse.logging.Logger;
3739
import com.clickhouse.logging.LoggerFactory;
40+
import com.clickhouse.jdbc.ClickHouseConnection;
3841
import com.clickhouse.jdbc.ClickHousePreparedStatement;
42+
import com.clickhouse.jdbc.ClickHouseResultSetMetaData;
3943
import com.clickhouse.jdbc.JdbcParameterizedQuery;
4044
import com.clickhouse.jdbc.SqlExceptionUtils;
4145
import com.clickhouse.jdbc.parser.ClickHouseSqlStatement;
@@ -239,6 +243,42 @@ protected int getMaxParameterIndex() {
239243
return templates.length;
240244
}
241245

246+
@Override
247+
public ResultSetMetaData describeQueryResult() throws SQLException {
248+
// No metadata unless query has been recognized as SELECT
249+
if (!parsedStmt.isRecognized() || !parsedStmt.isQuery()) {
250+
return null;
251+
}
252+
253+
final String[] vals;
254+
if (batch.isEmpty()) {
255+
vals = new String[values.length];
256+
System.arraycopy(this.values, 0, vals, 0, values.length);
257+
} else {
258+
vals = batch.get(0);
259+
}
260+
for (int i = 0; i < values.length; i++) {
261+
if (vals[i] == null) {
262+
vals[i] = ClickHouseValues.NULL_EXPR;
263+
}
264+
}
265+
266+
StringBuilder sb = new StringBuilder("desc (");
267+
preparedQuery.apply(sb, vals);
268+
sb.append(')');
269+
270+
List<ClickHouseColumn> columns = new LinkedList<>();
271+
ClickHouseConnection conn = getConnection();
272+
try (Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sb.toString())) {
273+
while (rs.next()) {
274+
columns.add(ClickHouseColumn.of(rs.getString(1), rs.getString(2)));
275+
}
276+
}
277+
278+
return ClickHouseResultSetMetaData.of(conn.getJdbcConfig(), conn.getCurrentDatabase(), "",
279+
Collections.unmodifiableList(new ArrayList<>(columns)), mapper, conn.getTypeMap());
280+
}
281+
242282
@Override
243283
public ResultSet executeQuery() throws SQLException {
244284
ensureParams();

clickhouse-jdbc/src/test/java/com/clickhouse/jdbc/ClickHousePreparedStatementTest.java

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.File;
55
import java.io.IOException;
66
import java.math.BigDecimal;
7+
import java.math.BigInteger;
78
import java.net.Inet4Address;
89
import java.net.Inet6Address;
910
import java.net.MalformedURLException;
@@ -16,6 +17,7 @@
1617
import java.sql.ParameterMetaData;
1718
import java.sql.PreparedStatement;
1819
import java.sql.ResultSet;
20+
import java.sql.ResultSetMetaData;
1921
import java.sql.SQLException;
2022
import java.sql.Statement;
2123
import java.sql.Timestamp;
@@ -2006,6 +2008,80 @@ public void testInsertWithSettings() throws SQLException {
20062008
}
20072009
}
20082010

2011+
@Test(groups = "integration")
2012+
public void testGetMetadataTypes() throws SQLException {
2013+
try (Connection conn = newConnection(new Properties());
2014+
PreparedStatement ps = conn.prepareStatement("select ? a, ? b")) {
2015+
ResultSetMetaData md = ps.getMetaData();
2016+
Assert.assertEquals(md.getColumnCount(), 2);
2017+
Assert.assertEquals(md.getColumnName(1), "a");
2018+
Assert.assertEquals(md.getColumnTypeName(1), "Nullable(Nothing)");
2019+
Assert.assertEquals(md.getColumnName(2), "b");
2020+
Assert.assertEquals(md.getColumnTypeName(2), "Nullable(Nothing)");
2021+
2022+
ps.setString(1, "x");
2023+
md = ps.getMetaData();
2024+
Assert.assertEquals(md.getColumnCount(), 2);
2025+
Assert.assertEquals(md.getColumnName(1), "a");
2026+
Assert.assertEquals(md.getColumnTypeName(1), "String");
2027+
Assert.assertEquals(md.getColumnName(2), "b");
2028+
Assert.assertEquals(md.getColumnTypeName(2), "Nullable(Nothing)");
2029+
2030+
ps.setObject(2, new BigInteger("12345"));
2031+
md = ps.getMetaData();
2032+
Assert.assertEquals(md.getColumnCount(), 2);
2033+
Assert.assertEquals(md.getColumnName(1), "a");
2034+
Assert.assertEquals(md.getColumnTypeName(1), "String");
2035+
Assert.assertEquals(md.getColumnName(2), "b");
2036+
Assert.assertEquals(md.getColumnTypeName(2), "UInt16");
2037+
2038+
ps.addBatch();
2039+
ps.setInt(1, 2);
2040+
md = ps.getMetaData();
2041+
Assert.assertEquals(md.getColumnCount(), 2);
2042+
Assert.assertEquals(md.getColumnName(1), "a");
2043+
Assert.assertEquals(md.getColumnTypeName(1), "String");
2044+
Assert.assertEquals(md.getColumnName(2), "b");
2045+
Assert.assertEquals(md.getColumnTypeName(2), "UInt16");
2046+
2047+
ps.clearBatch();
2048+
ps.clearParameters();
2049+
md = ps.getMetaData();
2050+
Assert.assertEquals(md.getColumnCount(), 2);
2051+
Assert.assertEquals(md.getColumnName(1), "a");
2052+
Assert.assertEquals(md.getColumnTypeName(1), "Nullable(Nothing)");
2053+
Assert.assertEquals(md.getColumnName(2), "b");
2054+
Assert.assertEquals(md.getColumnTypeName(2), "Nullable(Nothing)");
2055+
}
2056+
}
2057+
2058+
@Test(groups = "integration")
2059+
public void testGetMetadataStatements() throws SQLException {
2060+
try (Connection conn = newConnection(new Properties());
2061+
PreparedStatement createPs = conn.prepareStatement("create table test_get_metadata_statements (col String) Engine=Log");
2062+
PreparedStatement selectPs = conn.prepareStatement("select 'Hello, World!'");
2063+
PreparedStatement insertPs = conn.prepareStatement(
2064+
"insert into test_get_metadata_statements select 'Hello, World!'");
2065+
PreparedStatement updatePs = conn.prepareStatement(
2066+
"update test_get_metadata_statements set col = 'Bye, World!'");
2067+
PreparedStatement grantPs = conn.prepareStatement("grant select on * to default");
2068+
PreparedStatement commitPS = conn.prepareStatement("commit");) {
2069+
2070+
// Only select shall have valid metadata
2071+
ResultSetMetaData selectMetaData = selectPs.getMetaData();
2072+
Assert.assertNotNull(selectMetaData);
2073+
Assert.assertEquals(selectMetaData.getColumnCount(), 1);
2074+
Assert.assertEquals(selectMetaData.getColumnTypeName(1), "String");
2075+
2076+
// The rest shall return null
2077+
Assert.assertNull(createPs.getMetaData());
2078+
Assert.assertNull(insertPs.getMetaData());
2079+
Assert.assertNull(updatePs.getMetaData());
2080+
Assert.assertNull(grantPs.getMetaData());
2081+
Assert.assertNull(commitPS.getMetaData());
2082+
}
2083+
}
2084+
20092085
@Test(groups = "integration")
20102086
public void testGetParameterMetaData() throws SQLException {
20112087
try (Connection conn = newConnection(new Properties());

client-v2/src/main/java/com/clickhouse/client/api/Client.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,11 @@ public Builder addEndpoint(Protocol protocol, String host, int port, boolean sec
191191
ValidationUtils.checkNonBlank(host, "host");
192192
ValidationUtils.checkNotNull(protocol, "protocol");
193193
ValidationUtils.checkRange(port, 1, ValidationUtils.TCP_PORT_NUMBER_MAX, "port");
194-
194+
if (secure) {
195+
// For some reason com.clickhouse.client.http.ApacheHttpConnectionImpl.newConnection checks only client config
196+
// for SSL, so we need to set it here. But it actually should be set for each node separately.
197+
this.configuration.put(ClickHouseClientOption.SSL.getKey(), "true");
198+
}
195199
String endpoint = String.format("%s%s://%s:%d", protocol.toString().toLowerCase(), secure ? "s": "", host, port);
196200
this.addEndpoint(endpoint);
197201
return this;

client-v2/src/main/java/com/clickhouse/client/api/insert/InsertResponse.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,12 @@ public long getServerTime() {
8585
public long getResultRows() {
8686
return operationMetrics.getMetric(ServerMetrics.RESULT_ROWS).getLong();
8787
}
88+
89+
/**
90+
* Alias for {@link OperationMetrics#getQueryId()}
91+
* @return number of returned bytes
92+
*/
93+
public String getQueryId() {
94+
return operationMetrics.getQueryId();
95+
}
8896
}

client-v2/src/main/java/com/clickhouse/client/api/internal/ClientV1AdaptorHelper.java

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,29 @@
1818

1919
public class ClientV1AdaptorHelper {
2020

21-
private static void copyProxySettings(Map<ClickHouseOption, Serializable> target, Map<String, String> config) {
22-
ClickHouseClientOption opt = ClickHouseClientOption.PROXY_HOST;
23-
String value = config.get(opt.getKey());
24-
if (value != null) {
25-
target.put(opt, value);
26-
}
27-
opt = ClickHouseClientOption.PROXY_PORT;
28-
value = config.get(opt.getKey());
29-
if (value != null) {
30-
target.put(opt, Integer.parseInt(value));
31-
}
32-
opt = ClickHouseClientOption.PROXY_TYPE;
33-
value = config.get(opt.getKey());
34-
if (value != null) {
35-
target.put(opt, ClickHouseProxyType.valueOf(value));
21+
private static void copyClientOptions(Map<ClickHouseOption, Serializable> target, Map<String, String> config) {
22+
23+
for (ClickHouseClientOption opt : ClickHouseClientOption.values()) {
24+
String value = config.get(opt.getKey());
25+
if (value == null) {
26+
continue;
27+
}
28+
29+
if (opt.getValueType().isAssignableFrom(Integer.class)) {
30+
target.put(opt, Integer.parseInt(value));
31+
} else if (opt.getValueType().isAssignableFrom(Boolean.class)) {
32+
target.put(opt, Boolean.parseBoolean(value));
33+
} else if (opt.getValueType().isEnum()) {
34+
target.put(opt, Enum.valueOf((Class<Enum>) opt.getValueType(), value));
35+
} else if (opt.getValueType().isAssignableFrom(String.class)) {
36+
target.put(opt, value);
37+
}
3638
}
3739
}
3840

3941
public static ClickHouseClient createClient(Map<String, String> configuration) {
4042
Map<ClickHouseOption, Serializable> config = new HashMap<>();
41-
copyProxySettings(config, configuration);
43+
copyClientOptions(config, configuration);
4244

4345
ClickHouseConfig clientConfig = new ClickHouseConfig(config);
4446

0 commit comments

Comments
 (0)