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
16 changes: 10 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ on:
- master
paths-ignore:
- "**.md"
- "docs/**"
- "**/docs/**"
- "**/CHANGELOG"
- "**/LICENSE"
- "**/NOTICE"

pull_request:
types:
Expand All @@ -17,8 +19,10 @@ on:
- reopened
paths-ignore:
- "**.md"
- "docs/**"
- "**/docs/**"
- "**/CHANGELOG"
- "**/LICENSE"
- "**/NOTICE"

workflow_dispatch:
inputs:
Expand Down Expand Up @@ -58,7 +62,7 @@ jobs:
runs-on: ubuntu-latest
needs: compile
timeout-minutes: 10
name: CLI client against ClickHouse 22.8
name: CLI client + CH 22.8
steps:
- name: Check out repository
uses: actions/checkout@v3
Expand Down Expand Up @@ -102,7 +106,7 @@ jobs:
clickhouse: ["21.8", "22.3", "22.8", "latest"]
fail-fast: false
timeout-minutes: 15
name: Java client against ClickHouse ${{ matrix.clickhouse }}
name: Java client + CH ${{ matrix.clickhouse }}
steps:
- name: Check out repository
uses: actions/checkout@v3
Expand Down Expand Up @@ -162,7 +166,7 @@ jobs:
protocol: grpc
fail-fast: false
timeout-minutes: 15
name: JDBC driver against ClickHouse ${{ matrix.clickhouse }} (${{ matrix.protocol }})
name: JDBC driver + CH ${{ matrix.clickhouse }} (${{ matrix.protocol }})
steps:
- name: Check out repository
uses: actions/checkout@v3
Expand Down Expand Up @@ -222,7 +226,7 @@ jobs:
r2dbc: ["1.0.0.RELEASE", "0.9.1.RELEASE"]
fail-fast: false
timeout-minutes: 10
name: R2DBC ${{ matrix.r2dbc }} against ClickHouse ${{ matrix.clickhouse }} (${{ matrix.protocol }})
name: R2DBC ${{ matrix.r2dbc }} + CH ${{ matrix.clickhouse }} (${{ matrix.protocol }})
steps:
- name: Check out repository
uses: actions/checkout@v3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ public static Map<ClickHouseOption, Serializable> toClientOptions(Map<?, ?> prop
}

String key = e.getKey().toString();
// no need to enable option overidding for now
ClickHouseOption o = ClickHouseClientOption.fromKey(key);
if (o == null) {
o = customOptions.get(key);
Expand Down Expand Up @@ -190,6 +191,7 @@ public static Map<ClickHouseOption, Serializable> toClientOptions(Map<?, ?> prop
private final int maxQueuedRequests;
private final long maxResultRows;
private final int maxThreads;
private final String productName;
private final int nodeCheckInterval;
private final int failover;
private final int retry;
Expand Down Expand Up @@ -297,6 +299,7 @@ public ClickHouseConfig(Map<ClickHouseOption, Serializable> options, ClickHouseC
this.maxQueuedRequests = getIntOption(ClickHouseClientOption.MAX_QUEUED_REQUESTS);
this.maxResultRows = getLongOption(ClickHouseClientOption.MAX_RESULT_ROWS);
this.maxThreads = getIntOption(ClickHouseClientOption.MAX_THREADS_PER_CLIENT);
this.productName = getStrOption(ClickHouseClientOption.PRODUCT_NAME);
this.nodeCheckInterval = getIntOption(ClickHouseClientOption.NODE_CHECK_INTERVAL);
this.failover = getIntOption(ClickHouseClientOption.FAILOVER);
this.retry = getIntOption(ClickHouseClientOption.RETRY);
Expand Down Expand Up @@ -525,6 +528,10 @@ public int getMaxThreadsPerClient() {
return maxThreads;
}

public String getProductName() {
return productName;
}

public int getFailover() {
return failover;
}
Expand Down Expand Up @@ -642,6 +649,60 @@ public TimeZone getUseTimeZone() {
return useTimeZone;
}

/**
* Same as {@link ClickHouseClientOption#PRODUCT_VERSION}.
*
* @return non-empty semantic version
*/
public final String getProductVersion() {
return ClickHouseClientOption.PRODUCT_VERSION;
}

/**
* Same as {@link ClickHouseClientOption#PRODUCT_REVISION}.
*
* @return non-empty revision
*/
public final String getProductRevision() {
return ClickHouseClientOption.PRODUCT_REVISION;
}

/**
* Same as {@link ClickHouseClientOption#CLIENT_OS_INFO}.
*
* @return non-empty O/S information
*/
public final String getClientOsInfo() {
return ClickHouseClientOption.CLIENT_OS_INFO;
}

/**
* Same as {@link ClickHouseClientOption#CLIENT_JVM_INFO}.
*
* @return non-empty JVM information
*/
public final String getClientJvmInfo() {
return ClickHouseClientOption.CLIENT_JVM_INFO;
}

/**
* Same as {@link ClickHouseClientOption#CLIENT_USER}.
*
* @return non-empty user name
*/
public final String getClientUser() {
return ClickHouseClientOption.CLIENT_USER;
}

/**
* Same as {@link ClickHouseClientOption#CLIENT_HOST}.
*
* @return non-empty host name
*/
public final String getClientHost() {
return ClickHouseClientOption.CLIENT_HOST;
}

public ClickHouseCredentials getDefaultCredentials() {
return this.credentials;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,24 @@ private static <T> T findFirstService(Class<? extends T> serviceInterface) {
return service;
}

public static String toJavaByteArrayExpression(byte[] bytes) {
if (bytes == null) {
return "null";
}
int len = bytes.length;
if (len == 0) {
return "{}";
}

String prefix = "(byte)0x";
StringBuilder builder = new StringBuilder(10 * len).append('{');
for (int i = 0; i < len; i++) {
builder.append(prefix).append(String.format("%02X", 0xFF & bytes[i])).append(',');
}
builder.setCharAt(builder.length() - 1, '}');
return builder.toString();
}

public static int indexOf(byte[] bytes, byte[] search) {
if (bytes == null || search == null) {
return -1;
Expand All @@ -172,7 +190,7 @@ public static int indexOf(byte[] bytes, byte[] search) {
}
int blen = bytes.length;

outer: for (int i = 0, len = blen - slen + 1; i < len; i++) {
outer: for (int i = 0, len = blen - slen + 1; i < len; i++) { // NOSONAR
for (int j = 0; j < slen; j++) {
if (bytes[i + j] != search[j]) {
continue outer;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.clickhouse.client.config;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -115,7 +117,7 @@ public enum ClickHouseClientOption implements ClickHouseOption {
/**
* Client name.
*/
CLIENT_NAME("client_name", "ClickHouse Java Client",
CLIENT_NAME("client_name", DEFAULT_CLIENT_NAME,
"Client name, which is either 'client_name' or 'http_user_agent' shows up in system.query_log table."),
/**
* Whether server will compress response to client or not.
Expand Down Expand Up @@ -201,6 +203,10 @@ public enum ClickHouseClientOption implements ClickHouseOption {
*/
MAX_THREADS_PER_CLIENT("max_threads_per_client", 0,
"Size of thread pool for each client instance, 0 or negative number means the client will use shared thread pool."),
/**
* Product name usered in user agent.
*/
PRODUCT_NAME("product_name", DEFAULT_PRODUCT_NAME, "Product name used in user agent."),
/**
* Method to rename response columns.
*/
Expand Down Expand Up @@ -376,16 +382,105 @@ public enum ClickHouseClientOption implements ClickHouseOption {

private static final Map<String, ClickHouseClientOption> options;

static final String UNKNOWN = "unknown";

/**
* Semantic version of the product.
*/
public static final String PRODUCT_VERSION;
/**
* Revision(shortened git commit hash) of the product.
*/
public static final String PRODUCT_REVISION;
/**
* Client O/S information in format of {@code <o/s name>/<o/s version>}.
*/
public static final String CLIENT_OS_INFO;
/**
* Client JVM information in format of {@code <jvm name>/<jvm version>}.
*/
public static final String CLIENT_JVM_INFO;
/**
* Client user name.
*/
public static final String CLIENT_USER;
/**
* Client host name.
*/
public static final String CLIENT_HOST;

static {
Map<String, ClickHouseClientOption> map = new HashMap<>();

for (ClickHouseClientOption o : values()) {
if (map.put(o.getKey(), o) != null) {
throw new IllegalStateException("Duplicated key found: " + o.getKey());
}
}

options = Collections.unmodifiableMap(map);

// <artifact-id> <version> (revision: <revision>)
String ver = ClickHouseClientOption.class.getPackage().getImplementationVersion();
String[] parts = ver == null || ver.isEmpty() ? null : ver.split("\\s");
if (parts != null && parts.length == 4 && parts[1].length() > 0 && parts[3].length() > 1
&& ver.charAt(ver.length() - 1) == ')') {
PRODUCT_VERSION = parts[1];
ver = parts[3];
PRODUCT_REVISION = ver.substring(0, ver.length() - 1);
} else { // perhaps try harder by checking version from pom.xml?
PRODUCT_VERSION = UNKNOWN;
PRODUCT_REVISION = UNKNOWN;
}
CLIENT_OS_INFO = new StringBuilder().append(getSystemConfig("os.name", "O/S")).append('/')
.append(getSystemConfig("os.version", UNKNOWN)).toString();
String javaVersion = System.getProperty("java.vendor.version");
if (javaVersion == null || javaVersion.isEmpty() || javaVersion.indexOf(' ') >= 0) {
javaVersion = getSystemConfig("java.vm.version", getSystemConfig("java.version", UNKNOWN));
}
CLIENT_JVM_INFO = new StringBuilder().append(getSystemConfig("java.vm.name", "Java")).append('/')
.append(javaVersion).toString();
CLIENT_USER = getSystemConfig("user.name", UNKNOWN);
try {
ver = InetAddress.getLocalHost().getHostName();
} catch (UnknownHostException e1) {
// ignore
}
CLIENT_HOST = ver == null || ver.isEmpty() ? UNKNOWN : ver;
}

/**
* Builds user-agent based on given product name. The user-agent will be
* something look like
* {@code <product name>/<product version> (<o/s name>/<o/s version>; <jvm name>/<jvm version>[; <additionalProperty>]; rv:<product revision>)}.
*
* @param productName product name, null or blank string is treated as
* {@code ClickHouse Java Client}
* @param additionalProperty additional property if any
* @return non-empty user-agent
*/
public static final String buildUserAgent(String productName, String additionalProperty) {
productName = productName == null || productName.isEmpty() ? DEFAULT_PRODUCT_NAME : productName.trim();
StringBuilder builder = new StringBuilder(productName).append('/').append(PRODUCT_VERSION).append(" (")
.append(CLIENT_OS_INFO).append("; ").append(CLIENT_JVM_INFO);
if (additionalProperty != null && !additionalProperty.isEmpty()) {
builder.append("; ").append(additionalProperty.trim());
}
return builder.append("; rv:").append(PRODUCT_REVISION).append(')').toString();
}

/**
* Gets system property and fall back to the given value as needed.
*
* @param propertyName non-null property name
* @param defaultValue default value, only useful if it's not null
* @return property value
*/
public static String getSystemConfig(String propertyName, String defaultValue) {
final String propertyValue = System.getProperty(propertyName);
if (defaultValue == null) {
return propertyValue;
}

return propertyValue == null || propertyValue.isEmpty() ? defaultValue : propertyValue;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,22 @@
* description.
*/
public interface ClickHouseOption extends Serializable {
/**
* Default client name.
*/
static final String DEFAULT_CLIENT_NAME = "ClickHouse Java Client";
/**
* Default product name.
*/
static final String DEFAULT_PRODUCT_NAME = "ClickHouse-JavaClient";

/**
* Converts given string to key value pairs.
*
* @param str string
* @return non-null key value pairs
*/
public static Map<String, String> toKeyValuePairs(String str) {
static Map<String, String> toKeyValuePairs(String str) {
if (str == null || str.isEmpty()) {
return Collections.emptyMap();
}
Expand Down Expand Up @@ -76,7 +85,7 @@ public static Map<String, String> toKeyValuePairs(String str) {
* @return non-null typed value
*/
@SuppressWarnings("unchecked")
public static <T extends Serializable> T fromString(String value, Class<T> clazz) {
static <T extends Serializable> T fromString(String value, Class<T> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Non-null value type is required");
} else if (value == null) {
Expand Down Expand Up @@ -143,7 +152,7 @@ public static <T extends Serializable> T fromString(String value, Class<T> clazz
* @return non-null typed value
*/
@SuppressWarnings("unchecked")
public static <T extends Serializable> T fromString(String value, T defaultValue) {
static <T extends Serializable> T fromString(String value, T defaultValue) {
if (defaultValue == null) {
throw new IllegalArgumentException("Non-null default value is required");
}
Expand Down
Loading