T nonNull(T value, String name) {
+ if (value == null) {
+ throw newException("Non-null %s is required", name);
+ }
+
+ return value;
+ }
+
+ /**
+ * Checks if the given {@code value} is NOT less than {@code minValue} and
+ * throws a customized {@link IllegalArgumentException} if it is.
+ *
+ * @param value the value to check
+ * @param name name of the value
+ * @param minValue minimum value to compare with
+ * @return the exact same value
+ * @throws IllegalArgumentException if the {@code value} is less than
+ * {@code minValue}
+ */
+ public static int notLessThan(int value, String name, int minValue) {
+ if (value < minValue) {
+ throw newException(ERR_SHOULD_GE, name, value, minValue);
+ }
+
+ return value;
+ }
+
+ /**
+ * Checks if the given {@code value} is NOT less than {@code minValue} and
+ * throws a customized {@link IllegalArgumentException} if it is.
+ *
+ * @param value the value to check
+ * @param name name of the value
+ * @param minValue minimum value to compare with
+ * @return the exact same value
+ * @throws IllegalArgumentException if the {@code value} is less than
+ * {@code minValue}
+ */
+ public static long notLessThan(long value, String name, long minValue) {
+ if (value < minValue) {
+ throw newException(ERR_SHOULD_GE, name, value, minValue);
+ }
+
+ return value;
+ }
+
+ /**
+ * Checks if the given {@code value} is NOT less than {@code minValue} and
+ * throws a customized {@link IllegalArgumentException} if it is.
+ *
+ * @param value the value to check
+ * @param name name of the value
+ * @param minValue minimum value to compare with
+ * @return the exact same value
+ * @throws IllegalArgumentException if the {@code value} is less than
+ * {@code minValue}
+ */
+ public static BigInteger notLessThan(BigInteger value, String name, BigInteger minValue) {
+ if (value.compareTo(minValue) < 0) {
+ throw newException(ERR_SHOULD_GE, name, value, minValue);
+ }
+
+ return value;
+ }
+
+ /**
+ * Checks if length of the given byte array is NOT greater than {@code length}
+ * and throws a customized {@link IllegalArgumentException} if it is.
+ *
+ * @param value the byte array to check
+ * @param name name of the byte array
+ * @param maxLength maximum length of the byte array
+ * @return the exact same byte array
+ * @throws IllegalArgumentException if length of the byte array is greater than
+ * {@code maxlength}
+ */
+ public static byte[] notLongerThan(byte[] value, String name, int maxLength) {
+ int length = value == null ? 0 : value.length;
+ if (length > maxLength) {
+ throw newException("length of byte array %s is %d, which should NOT longer than %d", name, length,
+ maxLength);
+ }
+
+ return value;
+ }
+
+ /**
+ * Checks if length of the given byte array is NOT different from
+ * {@code expectedLength} and throws a customized
+ * {@link IllegalArgumentException} if it is.
+ *
+ * @param value the byte array to check
+ * @param expectedLength execpted length of the byte array
+ * @return the exact same byte array
+ * @throws IllegalArgumentException if length of the byte array is not same as
+ * {@code expectedLength}
+ */
+ public static byte[] notWithDifferentLength(byte[] value, int expectedLength) {
+ return notWithDifferentLength(value, DEFAULT_NAME, expectedLength);
+ }
+
+ /**
+ * Checks if length of the given byte array is NOT different from
+ * {@code expectedLength} and throws a customized
+ * {@link IllegalArgumentException} if it is.
+ *
+ * @param value the byte array to check
+ * @param name name of the byte array
+ * @param expectedLength execpted length of the byte array
+ * @return the exact same byte array
+ * @throws IllegalArgumentException if length of the byte array is not same as
+ * {@code expectedLength}
+ */
+ public static byte[] notWithDifferentLength(byte[] value, String name, int expectedLength) {
+ int length = value == null ? 0 : value.length;
+ if (length != expectedLength) {
+ throw newException("length of byte array %s is %d, but it should be %d", name, length, expectedLength);
+ }
+
+ return value;
+ }
+
+ public static String notWithDifferentLength(String value, int expectedLength) {
+ return notWithDifferentLength(value, null, DEFAULT_NAME, expectedLength);
+ }
+
+ public static String notWithDifferentLength(String value, Charset charset, int expectedLength) {
+ return notWithDifferentLength(value, charset, DEFAULT_NAME, expectedLength);
+ }
+
+ /**
+ * Checks if byte length of the given string is NOT different from
+ * {@code expectedLength} and throws a customized
+ * {@link IllegalArgumentException} if it is.
+ *
+ * @param value the string to check
+ * @param charset charset used to decode the string for byte length
+ * comparison, null means utf8
+ * @param name name of the byte array
+ * @param expectedLength execpted length of the string
+ * @return the exact same string
+ * @throws IllegalArgumentException if length of the byte array is not same as
+ * {@code expectedLength}
+ */
+ public static String notWithDifferentLength(String value, Charset charset, String name, int expectedLength) {
+ if (charset == null) {
+ charset = StandardCharsets.UTF_8;
+ }
+ int length = value == null ? 0 : value.getBytes(charset).length;
+ if (length != expectedLength) {
+ throw newException("length of byte array %s is %d, but it should be %d", name, length, expectedLength);
+ }
+
+ return value;
+ }
+
+ private ClickHouseChecker() {
+ }
+}
diff --git a/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java
new file mode 100644
index 000000000..8b429c72c
--- /dev/null
+++ b/clickhouse-client/src/main/java/com/clickhouse/client/ClickHouseClient.java
@@ -0,0 +1,604 @@
+package com.clickhouse.client;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Function;
+import com.clickhouse.client.config.ClickHouseClientOption;
+import com.clickhouse.client.config.ClickHouseDefaults;
+import com.clickhouse.client.data.ClickHousePipedStream;
+import com.clickhouse.client.exception.ClickHouseException;
+import com.clickhouse.client.exception.ClickHouseExceptionSpecifier;
+
+/**
+ * A unified interface defines Java client for ClickHouse. A client can only
+ * connect to one {@link ClickHouseNode} at a time. When switching from one node
+ * to another, connection made to previous node will be closed automatically
+ * before new connection being established.
+ *
+ *
+ * To decouple from concrete implementation tied to specific protocol, it is
+ * recommended to use {@link #builder()} for instantiation. In order to register
+ * a new type of client, please add
+ * {@code META-INF/services/com.clickhouse.client.ClickHouseClient} into your
+ * artifact, so that {@code java.util.SerivceLoader} can discover the
+ * implementation properly in runtime.
+ */
+public interface ClickHouseClient extends AutoCloseable {
+ /**
+ * Empty stringified parameters.
+ */
+ static final List