diff --git a/pom.xml b/pom.xml index 8942378e1..eb23adcd4 100644 --- a/pom.xml +++ b/pom.xml @@ -117,6 +117,7 @@ vertx-mysql-client vertx-mssql-client vertx-db2-client + vertx-clickhouse-binary-client vertx-sql-client-templates vertx-oracle-client diff --git a/vertx-clickhouse-binary-client/pom.xml b/vertx-clickhouse-binary-client/pom.xml new file mode 100644 index 000000000..d50acfa67 --- /dev/null +++ b/vertx-clickhouse-binary-client/pom.xml @@ -0,0 +1,204 @@ + + + + + 4.0.0 + + + io.vertx + vertx-sql-client-parent + 4.4.0-SNAPSHOT + + + vertx-clickhouse-binary-client + + Vertx Clickhouse binary Client + https://github.com/eclipse-vertx/vertx-sql-client + The Reactive Clickhouse Client + + + false + ${project.basedir}/src/main/docs + ${project.basedir}/src/main/generated + 11 + 11 + + + 2.19.0 + + + + + + + io.vertx + vertx-core + + + io.vertx + vertx-codegen + true + + + io.vertx + vertx-docgen + true + + + io.vertx + vertx-sql-client + + + + org.lz4 + lz4-java + 1.8.0 + + + + io.vertx + vertx-sql-client + test-jar + test + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-yaml + test + + + + org.testcontainers + clickhouse + ${testcontainers.version} + test + + + + com.clickhouse + clickhouse-jdbc + 0.3.2-patch11 + test + + + + org.slf4j + slf4j-api + 2.0.3 + test + + + + org.apache.logging.log4j + log4j-slf4j2-impl + ${log4j.version} + test + + + + org.apache.logging.log4j + log4j-api + ${log4j.version} + test + + + + org.apache.logging.log4j + log4j-core + ${log4j.version} + test + + + + org.apache.logging.log4j + log4j-jul + ${log4j.version} + test + + + + + org.openjdk.jmh + jmh-core + ${jmh.version} + test + + + org.openjdk.jmh + jmh-generator-annprocess + ${jmh.version} + test + + + + + + + + maven-surefire-plugin + + -Xmx1024M + + ${project.build.directory} + ${embedded.clickhouse.version} + ${connection.uri} + + + + + + + + + + org.bsc.maven + maven-processor-plugin + + + generate-sources + + + ${project.basedir}/../vertx-sql-client/src/main/asciidoc/*.adoc,${asciidoc.dir}/*.adoc + + + + + + + maven-assembly-plugin + + + + package-sources + + + ${project.basedir}/../assembly/sources.xml + + + none + + true + + + + + + + + diff --git a/vertx-clickhouse-binary-client/src/main/generated/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnectOptionsConverter.java b/vertx-clickhouse-binary-client/src/main/generated/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnectOptionsConverter.java new file mode 100644 index 000000000..9b9f5d747 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/generated/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnectOptionsConverter.java @@ -0,0 +1,33 @@ +package io.vertx.clickhouseclient.binary; + +import io.vertx.core.json.JsonObject; +import io.vertx.core.json.JsonArray; +import io.vertx.core.json.impl.JsonUtil; +import java.time.Instant; +import java.time.format.DateTimeFormatter; +import java.util.Base64; + +/** + * Converter and mapper for {@link io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions}. + * NOTE: This class has been automatically generated from the {@link io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions} original class using Vert.x codegen. + */ +public class ClickhouseBinaryConnectOptionsConverter { + + + private static final Base64.Decoder BASE64_DECODER = JsonUtil.BASE64_DECODER; + private static final Base64.Encoder BASE64_ENCODER = JsonUtil.BASE64_ENCODER; + + public static void fromJson(Iterable> json, ClickhouseBinaryConnectOptions obj) { + for (java.util.Map.Entry member : json) { + switch (member.getKey()) { + } + } + } + + public static void toJson(ClickhouseBinaryConnectOptions obj, JsonObject json) { + toJson(obj, json.getMap()); + } + + public static void toJson(ClickhouseBinaryConnectOptions obj, java.util.Map json) { + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/examples/SqlClientExamples.java b/vertx-clickhouse-binary-client/src/main/java/examples/SqlClientExamples.java new file mode 100644 index 000000000..1548aff47 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/examples/SqlClientExamples.java @@ -0,0 +1,334 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package examples; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryPool; +import io.vertx.core.AbstractVerticle; +import io.vertx.core.DeploymentOptions; +import io.vertx.core.Vertx; +import io.vertx.core.tracing.TracingPolicy; +import io.vertx.docgen.Source; +import io.vertx.sqlclient.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Source +public class SqlClientExamples { + public void queries01(SqlClient client) { + client + .query("SELECT * FROM users WHERE id='julien'") + .execute(ar -> { + if (ar.succeeded()) { + RowSet result = ar.result(); + System.out.println("Got " + result.size() + " rows "); + } else { + System.out.println("Failure: " + ar.cause().getMessage()); + } + }); + } + + + public void queries02(SqlClient client) { + client + .preparedQuery("SELECT * FROM users WHERE id=?") + .execute(Tuple.of("julien"), ar -> { + if (ar.succeeded()) { + RowSet rows = ar.result(); + System.out.println("Got " + rows.size() + " rows "); + } else { + System.out.println("Failure: " + ar.cause().getMessage()); + } + }); + } + + public void queries03(SqlClient client) { + client + .preparedQuery("SELECT first_name, last_name FROM users") + .execute(ar -> { + if (ar.succeeded()) { + RowSet rows = ar.result(); + for (Row row : rows) { + System.out.println("User " + row.getString(0) + " " + row.getString(1)); + } + } else { + System.out.println("Failure: " + ar.cause().getMessage()); + } + }); + } + + public void queries04(SqlClient client) { + client + .preparedQuery("INSERT INTO users (first_name, last_name) VALUES (?, ?)") + .execute(Tuple.of("Julien", "Viet"), ar -> { + if (ar.succeeded()) { + RowSet rows = ar.result(); + System.out.println(rows.rowCount()); + } else { + System.out.println("Failure: " + ar.cause().getMessage()); + } + }); + } + + public void queries05(Row row) { + System.out.println("User " + row.getString(0) + " " + row.getString(1)); + } + + public void queries06(Row row) { + System.out.println("User " + row.getString("first_name") + " " + row.getString("last_name")); + } + + public void queries07(Row row) { + + String firstName = row.getString("first_name"); + Boolean male = row.getBoolean("male"); + Integer age = row.getInteger("age"); + + // ... + + } + + public void queries08(SqlClient client) { + + // Add commands to the batch + List batch = new ArrayList<>(); + batch.add(Tuple.of("julien", "Julien Viet")); + batch.add(Tuple.of("emad", "Emad Alblueshi")); + + // Execute the prepared batch + client + .preparedQuery("INSERT INTO USERS (id, name) VALUES (?, ?)") + .executeBatch(batch, res -> { + if (res.succeeded()) { + + // Process rows + RowSet rows = res.result(); + } else { + System.out.println("Batch failed " + res.cause()); + } + }); + } + + public void queries09(SqlClient client, SqlConnectOptions connectOptions) { + + // Enable prepare statements caching + connectOptions.setCachePreparedStatements(true); + client + .preparedQuery("SELECT * FROM users WHERE id = ?") + .execute(Tuple.of("julien"), ar -> { + if (ar.succeeded()) { + RowSet rows = ar.result(); + System.out.println("Got " + rows.size() + " rows "); + } else { + System.out.println("Failure: " + ar.cause().getMessage()); + } + }); + } + + public void queries10(SqlConnection sqlConnection) { + sqlConnection + .prepare("SELECT * FROM users WHERE id = ?", ar -> { + if (ar.succeeded()) { + PreparedStatement preparedStatement = ar.result(); + preparedStatement.query() + .execute(Tuple.of("julien"), ar2 -> { + if (ar2.succeeded()) { + RowSet rows = ar2.result(); + System.out.println("Got " + rows.size() + " rows "); + preparedStatement.close(); + } else { + System.out.println("Failure: " + ar2.cause().getMessage()); + } + }); + } else { + System.out.println("Failure: " + ar.cause().getMessage()); + } + }); + } + + public void usingConnections01(Vertx vertx, Pool pool) { + + pool + .getConnection() + .compose(connection -> + connection + .preparedQuery("INSERT INTO Users (first_name,last_name) VALUES (?, ?)") + .executeBatch(Arrays.asList( + Tuple.of("Julien", "Viet"), + Tuple.of("Emad", "Alblueshi") + )) + .compose(res -> connection + // Do something with rows + .query("SELECT COUNT(*) FROM Users") + .execute() + .map(rows -> rows.iterator().next().getInteger(0))) + // Return the connection to the pool + .eventually(v -> connection.close()) + ).onSuccess(count -> { + System.out.println("Insert users, now the number of users is " + count); + }); + } + + public void usingConnections02(SqlConnection connection) { + connection + .prepare("SELECT * FROM users WHERE first_name LIKE ?") + .compose(pq -> + pq.query() + .execute(Tuple.of("Julien")) + .eventually(v -> pq.close()) + ).onSuccess(rows -> { + // All rows + }); + } + + public void usingConnections03(Pool pool) { + pool.withConnection(connection -> + connection + .preparedQuery("INSERT INTO Users (first_name,last_name) VALUES (?, ?)") + .executeBatch(Arrays.asList( + Tuple.of("Julien", "Viet"), + Tuple.of("Emad", "Alblueshi") + )) + .compose(res -> connection + // Do something with rows + .query("SELECT COUNT(*) FROM Users") + .execute() + .map(rows -> rows.iterator().next().getInteger(0))) + ).onSuccess(count -> { + System.out.println("Insert users, now the number of users is " + count); + }); + } + + public void transaction01(Pool pool) { + //transactions are not supported + } + + public void transaction02(Transaction tx) { + //transactions are not supported + } + + public void transaction03(Pool pool) { + //transactions are not supported + } + + public void usingCursors01(SqlConnection connection) { + connection.prepare("SELECT * FROM users WHERE age > ?", ar1 -> { + if (ar1.succeeded()) { + PreparedStatement pq = ar1.result(); + + // Create a cursor + Cursor cursor = pq.cursor(Tuple.of(18)); + + // Read 50 rows + cursor.read(50, ar2 -> { + if (ar2.succeeded()) { + RowSet rows = ar2.result(); + + // Check for more ? + if (cursor.hasMore()) { + // Repeat the process... + } else { + // No more rows - close the cursor + cursor.close(); + } + } + }); + } + }); + } + + public void usingCursors02(Cursor cursor) { + cursor.read(50, ar2 -> { + if (ar2.succeeded()) { + // Close the cursor + cursor.close(); + } + }); + } + + public void usingCursors03(SqlConnection connection) { + connection.prepare("SELECT * FROM users WHERE age > ?", ar1 -> { + if (ar1.succeeded()) { + PreparedStatement pq = ar1.result(); + + // Fetch 50 rows at a time + RowStream stream = pq.createStream(50, Tuple.of(18)); + + // Use the stream + stream.exceptionHandler(err -> { + System.out.println("Error: " + err.getMessage()); + }); + stream.endHandler(v -> { + System.out.println("End of stream"); + }); + stream.handler(row -> { + System.out.println("User: " + row.getString("last_name")); + }); + } + }); + } + + public void tracing01(ClickhouseBinaryConnectOptions options) { + options.setTracingPolicy(TracingPolicy.ALWAYS); + } + + public void poolConfig01(ClickhouseBinaryConnectOptions server1, ClickhouseBinaryConnectOptions server2, ClickhouseBinaryConnectOptions server3, PoolOptions options) { + ClickhouseBinaryPool pool = ClickhouseBinaryPool.pool(Arrays.asList(server1, server2, server3), options); + } + + public void poolConfig02(ClickhouseBinaryPool pool, String sql) { + pool.connectHandler(conn -> { + conn.query(sql).execute().onSuccess(res -> { + // Release the connection to the pool, ready to be used by the application + conn.close(); + }); + }); + } + + public void poolSharing1(Vertx vertx, ClickhouseBinaryConnectOptions database, int maxSize) { + ClickhouseBinaryPool pool = ClickhouseBinaryPool.pool(database, new PoolOptions().setMaxSize(maxSize)); + vertx.deployVerticle(() -> new AbstractVerticle() { + @Override + public void start() throws Exception { + // Use the pool + } + }, new DeploymentOptions().setInstances(4)); + } + + public void poolSharing2(Vertx vertx, ClickhouseBinaryConnectOptions database, int maxSize) { + vertx.deployVerticle(() -> new AbstractVerticle() { + ClickhouseBinaryPool pool; + @Override + public void start() { + // Get or create a shared pool + // this actually creates a lease to the pool + // when the verticle is undeployed, the lease will be released automaticaly + pool = ClickhouseBinaryPool.pool(database, new PoolOptions() + .setMaxSize(maxSize) + .setShared(true) + .setName("my-pool")); + } + }, new DeploymentOptions().setInstances(4)); + } + + public static void poolSharing3(Vertx vertx, ClickhouseBinaryConnectOptions database, int maxSize) { + ClickhouseBinaryPool pool = ClickhouseBinaryPool.pool(database, new PoolOptions() + .setMaxSize(maxSize) + .setShared(true) + .setName("my-pool") + .setEventLoopSize(4)); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnectOptions.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnectOptions.java new file mode 100644 index 000000000..b375e6383 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnectOptions.java @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryConnectionUriParser; +import io.vertx.codegen.annotations.DataObject; +import io.vertx.core.json.JsonObject; +import io.vertx.sqlclient.SqlConnectOptions; + +@DataObject(generateConverter = true) +public class ClickhouseBinaryConnectOptions extends SqlConnectOptions { + + public static ClickhouseBinaryConnectOptions wrap(SqlConnectOptions options) { + if (options instanceof ClickhouseBinaryConnectOptions) { + return (ClickhouseBinaryConnectOptions) options; + } else { + return new ClickhouseBinaryConnectOptions(options); + } + } + + public static ClickhouseBinaryConnectOptions fromUri(String connectionUri) throws IllegalArgumentException { + JsonObject parsedConfiguration = ClickhouseBinaryConnectionUriParser.parse(connectionUri); + return new ClickhouseBinaryConnectOptions(parsedConfiguration); + } + + public ClickhouseBinaryConnectOptions() { + super(); + } + + public ClickhouseBinaryConnectOptions(JsonObject json) { + super(json); + ClickhouseBinaryConnectOptionsConverter.fromJson(json, this); + } + + public ClickhouseBinaryConnectOptions(SqlConnectOptions other) { + super(other); + } + + public ClickhouseBinaryConnectOptions(ClickhouseBinaryConnectOptions other) { + super(other); + } + +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnection.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnection.java new file mode 100644 index 000000000..2286fb721 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryConnection.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryConnectionImpl; +import io.vertx.codegen.annotations.VertxGen; +import io.vertx.core.AsyncResult; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.core.impl.ContextInternal; +import io.vertx.sqlclient.SqlConnection; + +@VertxGen +public interface ClickhouseBinaryConnection extends SqlConnection { + static void connect(Vertx vertx, ClickhouseBinaryConnectOptions connectOptions, Handler> handler) { + Future fut = connect(vertx, connectOptions); + if (handler != null) { + fut.onComplete(handler); + } + } + + static Future connect(Vertx vertx, ClickhouseBinaryConnectOptions connectOptions) { + return ClickhouseBinaryConnectionImpl.connect((ContextInternal) vertx.getOrCreateContext(), connectOptions); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryPool.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryPool.java new file mode 100644 index 000000000..755136909 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseBinaryPool.java @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import io.vertx.clickhouseclient.binary.spi.ClickhouseBinaryDriver; +import io.vertx.codegen.annotations.VertxGen; +import io.vertx.core.Vertx; +import io.vertx.sqlclient.Pool; +import io.vertx.sqlclient.PoolOptions; + +import java.util.Collections; +import java.util.List; + +@VertxGen +public interface ClickhouseBinaryPool extends Pool { + static ClickhouseBinaryPool pool(ClickhouseBinaryConnectOptions database, PoolOptions options) { + return pool(null, database, options); + } + + static ClickhouseBinaryPool pool(Vertx vertx, ClickhouseBinaryConnectOptions database, PoolOptions options) { + return pool(vertx, Collections.singletonList(database), options); + } + + static ClickhouseBinaryPool pool(List databases, PoolOptions options) { + return pool(null, databases, options); + } + + static ClickhouseBinaryPool pool(Vertx vertx, List databases, PoolOptions options) { + return (ClickhouseBinaryPool) ClickhouseBinaryDriver.INSTANCE.createPool(vertx, databases, options); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseConstants.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseConstants.java new file mode 100644 index 000000000..6b6f9e9c4 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/ClickhouseConstants.java @@ -0,0 +1,67 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +public class ClickhouseConstants { + public static final int DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES = 50264; + public static final int DBMS_MIN_REVISION_WITH_TOTAL_ROWS_IN_PROGRESS = 51554; + public static final int DBMS_MIN_REVISION_WITH_BLOCK_INFO = 51903; + + public static final int DBMS_MIN_REVISION_WITH_CLIENT_INFO = 54032; + public static final int DBMS_MIN_REVISION_WITH_SERVER_TIMEZONE = 54058; + public static final int DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO = 54060; + public static final int DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME = 54372; + public static final int DBMS_MIN_REVISION_WITH_VERSION_PATCH = 54401; + public static final int DBMS_MIN_REVISION_WITH_SERVER_LOGS = 54406; + public static final int DBMS_MIN_REVISION_WITH_COLUMN_DEFAULTS_METADATA = 54410; + public static final int DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO = 54420; + public static final int DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS = 54429; + public static final int DBMS_MIN_REVISION_WITH_INTERSERVER_SECRET = 54441; + + public static final int CLIENT_VERSION_MAJOR = 20; + public static final int CLIENT_VERSION_MINOR = 10; + public static final int CLIENT_VERSION_PATCH = 2; + public static final int CLIENT_REVISION = 54441; + + public static final String OPTION_APPLICATION_NAME = "application_name"; + public static final String OPTION_INITIAL_USER = "initial_user"; + public static final String OPTION_INITIAL_QUERY_ID = "initial_query_id"; + public static final String OPTION_INITIAL_ADDRESS = "initial_address"; + public static final String OPTION_INITIAL_USERNAME = "initial_username"; + public static final String OPTION_INITIAL_HOSTNAME = "initial_hostname"; + public static final String OPTION_COMPRESSOR = "compressor"; + public static final String OPTION_STRING_CHARSET = "string_charset"; + public static final String OPTION_DEFAULT_ZONE_ID = "default_zone_id"; + public static final String OPTION_YEAR_DURATION = "days_in_year"; + public static final String OPTION_QUARTER_DURATION = "days_in_quarter"; + public static final String OPTION_MONTH_DURATION = "days_in_month"; + public static final String OPTION_SEND_LOGS_LEVEL = "send_logs_level"; + public static final String OPTION_DATETIME64_EXTRA_NANOS_MODE = "dt64_extra_nanos"; + public static final String OPTION_ENUM_RESOLUTION = "enum_resolution"; + public static final String OPTION_MAX_BLOCK_SIZE = "max_block_size"; + public static final String OPTION_REMOVE_TRAILING_ZEROS_WHEN_ENCODE_FIXED_STRINGS = "remove_trailing_zeros_when_encode_fixed_strings"; + + public static final short COMPRESSION_METHOD_LZ4 = 0x82; + public static final short COMPRESSION_METHOD_ZSTD = 0x90; + + public static final Set NON_QUERY_OPTIONS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList( + OPTION_APPLICATION_NAME, OPTION_INITIAL_USER, OPTION_INITIAL_QUERY_ID, OPTION_INITIAL_ADDRESS, OPTION_INITIAL_USERNAME, + OPTION_INITIAL_HOSTNAME, OPTION_COMPRESSOR, OPTION_STRING_CHARSET, OPTION_DEFAULT_ZONE_ID, OPTION_YEAR_DURATION, OPTION_QUARTER_DURATION, + OPTION_MONTH_DURATION, OPTION_DATETIME64_EXTRA_NANOS_MODE, OPTION_ENUM_RESOLUTION, OPTION_REMOVE_TRAILING_ZEROS_WHEN_ENCODE_FIXED_STRINGS))); +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/BaseBlock.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/BaseBlock.java new file mode 100644 index 000000000..501b3ff80 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/BaseBlock.java @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumnReader; +import io.vertx.sqlclient.desc.ColumnDescriptor; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +public class BaseBlock { + private final Map columnsWithTypes; + protected final ClickhouseBinaryRowDesc rowDesc; + private final List data; + private final BlockInfo blockInfo; + protected final ClickhouseBinaryDatabaseMetadata md; + + public BaseBlock(Map columnsWithTypes, + List data, BlockInfo blockInfo, ClickhouseBinaryDatabaseMetadata md) { + this.columnsWithTypes = columnsWithTypes; + this.rowDesc = buildRowDescriptor(columnsWithTypes); + this.data = data; + this.blockInfo = blockInfo; + this.md = md; + } + + public Map getColumnsWithTypes() { + return columnsWithTypes; + } + + public List getData() { + return data; + } + + public BlockInfo getBlockInfo() { + return blockInfo; + } + + public ClickhouseBinaryDatabaseMetadata getMd() { + return md; + } + + public ClickhouseBinaryRowDesc rowDesc() { + return rowDesc; + } + + private ClickhouseBinaryRowDesc buildRowDescriptor(Map columnsWithTypes) { + ClickhouseBinaryColumnDescriptor[] columnTypes = columnsWithTypes.values().toArray(ClickhouseBinaryRowDesc.EMPTY_DESCRIPTORS); + return new ClickhouseBinaryRowDesc(columnTypes); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/BlockInfo.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/BlockInfo.java new file mode 100644 index 000000000..01e7a2bd1 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/BlockInfo.java @@ -0,0 +1,102 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; + +public class BlockInfo { + private static final Logger LOG = LoggerFactory.getLogger(BlockInfo.class); + + private Boolean isOverflows; + private Integer bucketNum; + private boolean complete; + private Integer fieldNum; + + public BlockInfo() { + isOverflows = false; + bucketNum = -1; + } + + public BlockInfo(Boolean isOverflows, Integer bucketNum) { + this.isOverflows = isOverflows; + this.bucketNum = bucketNum; + } + + public void serializeTo(ClickhouseStreamDataSink sink) { + sink.writeULeb128(1); + sink.writeByte(isOverflows ? 1 : 0); + sink.writeULeb128(2); + sink.writeIntLE(bucketNum); + sink.writeULeb128(0); + } + + public boolean isComplete() { + return complete; + } + + public boolean isPartial() { + return !complete; + } + + public void readFrom(ClickhouseStreamDataSource in) { + while (isPartial()) { + if (fieldNum == null) { + fieldNum = in.readULeb128(); + if (fieldNum == null) { + return; + } + } + if (LOG.isDebugEnabled()) { + LOG.debug("fieldNum: " + fieldNum + "(" + Integer.toHexString(fieldNum) + ")"); + } + if (fieldNum == 0) { + complete = true; + return; + } + if (fieldNum == 1) { + if (in.readableBytes() >= 1) { + isOverflows = in.readBoolean(); + fieldNum = null; + if (LOG.isDebugEnabled()) { + LOG.debug("isOverflows: " + isOverflows); + } + } else { + return; + } + } else if (fieldNum == 2) { + int readable = in.readableBytes(); + if (readable >= 4) { + bucketNum = in.readIntLE(); + fieldNum = null; + if (LOG.isDebugEnabled()) { + LOG.debug("bucketNum: " + bucketNum); + } + } else { + return; + } + } + } + } + + @Override + public String toString() { + return "BlockInfo{" + + "isOverflows=" + isOverflows + + ", bucketNum=" + bucketNum + + '}'; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionFactory.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionFactory.java new file mode 100644 index 000000000..2d07a98c3 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionFactory.java @@ -0,0 +1,109 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.core.Context; +import io.vertx.core.Future; +import io.vertx.core.impl.ContextInternal; +import io.vertx.core.impl.EventLoopContext; +import io.vertx.core.impl.VertxInternal; +import io.vertx.core.impl.future.PromiseInternal; +import io.vertx.core.net.NetClientOptions; +import io.vertx.core.net.NetSocket; +import io.vertx.core.net.SocketAddress; +import io.vertx.core.net.impl.NetSocketInternal; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.SqlConnection; +import io.vertx.sqlclient.impl.Connection; +import io.vertx.sqlclient.impl.ConnectionFactoryBase; +import io.vertx.sqlclient.impl.tracing.QueryTracer; +import net.jpountz.lz4.LZ4Factory; + +public class ClickhouseBinaryConnectionFactory extends ConnectionFactoryBase { + public static final String LZ4_FASTEST_JAVA = "lz4_fastest_java"; + + private final LZ4Factory lz4Factory; + + public ClickhouseBinaryConnectionFactory(VertxInternal vertx, ClickhouseBinaryConnectOptions options) { + super(vertx, options); + this.lz4Factory = lz4FactoryForName(options.getProperties().getOrDefault(ClickhouseConstants.OPTION_COMPRESSOR, LZ4_FASTEST_JAVA)); + } + + private LZ4Factory lz4FactoryForName(String name) { + if ("lz4_native".equals(name)) { + return LZ4Factory.nativeInstance(); + } else if ("lz4_fastest".equals(name)) { + return LZ4Factory.fastestInstance(); + } else if (LZ4_FASTEST_JAVA.equals(name)) { + return LZ4Factory.fastestJavaInstance(); + } else if ("lz4_safe".equals(name)) { + return LZ4Factory.safeInstance(); + } else if ("lz4_unsafe".equals(name)) { + return LZ4Factory.unsafeInstance(); + } + return null; + } + + @Override + protected void initializeConfiguration(SqlConnectOptions connectOptions) { + } + + @Override + protected void configureNetClientOptions(NetClientOptions netClientOptions) { + netClientOptions.setSsl(false); + } + + @Override + protected Future doConnectInternal(SocketAddress server, String username, String password, String database, EventLoopContext context) { + return doConnect(server, context).flatMap(conn -> { + ClickhouseBinarySocketConnection socket = (ClickhouseBinarySocketConnection) conn; + socket.init(); + return Future.future(p -> socket.sendStartupMessage(username, password, database, properties, p)) + .map(conn); + }); + } + + private Future doConnect(SocketAddress server, EventLoopContext ctx) { + Future soFut; + try { + soFut = netClient.connect(server, (String) null); + } catch (Exception e) { + // Client is closed + return ctx.failedFuture(e); + } + return soFut.map(so -> newSocketConnection(ctx, (NetSocketInternal) so)); + } + + @Override + public Future connect(Context context) { + ContextInternal contextInternal = (ContextInternal) context; + PromiseInternal promise = contextInternal.promise(); + connect(asEventLoopContext(contextInternal)) + .map(conn -> { + QueryTracer tracer = contextInternal.tracer() == null ? null : new QueryTracer(contextInternal.tracer(), options); + ClickhouseBinaryConnectionImpl dbConn = new ClickhouseBinaryConnectionImpl(this, contextInternal, conn, tracer, null); + conn.init(dbConn); + return (SqlConnection)dbConn; + }) + .onComplete(promise); + return promise.future(); + } + + private ClickhouseBinarySocketConnection newSocketConnection(EventLoopContext ctx, NetSocketInternal socket) { + return new ClickhouseBinarySocketConnection(socket, cachePreparedStatements, preparedStatementCacheSize, + preparedStatementCacheSqlFilter, ctx, lz4Factory); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionImpl.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionImpl.java new file mode 100644 index 000000000..584f80994 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionImpl.java @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnection; +import io.vertx.clickhouseclient.binary.spi.ClickhouseBinaryDriver; +import io.vertx.core.Future; +import io.vertx.core.impl.ContextInternal; +import io.vertx.core.spi.metrics.ClientMetrics; +import io.vertx.sqlclient.Transaction; +import io.vertx.sqlclient.impl.Connection; +import io.vertx.sqlclient.impl.SqlConnectionBase; +import io.vertx.sqlclient.impl.tracing.QueryTracer; +import io.vertx.sqlclient.spi.ConnectionFactory; + +public class ClickhouseBinaryConnectionImpl extends SqlConnectionBase implements ClickhouseBinaryConnection { + public static Future connect(ContextInternal ctx, ClickhouseBinaryConnectOptions options) { + ClickhouseBinaryConnectionFactory client; + try { + client = new ClickhouseBinaryConnectionFactory(ctx.owner(), options); + } catch (Exception e) { + return ctx.failedFuture(e); + } + ctx.addCloseHook(client); + return (Future)client.connect(ctx); + } + + ClickhouseBinaryConnectionImpl(ConnectionFactory factory, ContextInternal context, Connection conn, QueryTracer tracer, ClientMetrics metrics) { + super(context, factory, conn, ClickhouseBinaryDriver.INSTANCE, tracer, metrics); + } + + @Override + public Future begin() { + return Future.failedFuture(new UnsupportedOperationException()); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionUriParser.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionUriParser.java new file mode 100644 index 000000000..cfd6c42f6 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryConnectionUriParser.java @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.core.json.JsonObject; + +import java.net.URI; +import java.util.AbstractMap; +import java.util.Arrays; +import java.util.Collections; +import java.util.Map; +import java.util.stream.Collectors; +import java.util.AbstractMap.SimpleImmutableEntry; + +public class ClickhouseBinaryConnectionUriParser { + public static JsonObject parse(String connectionUri) { + return parse(connectionUri, true); + } + + public static JsonObject parse(String connectionUri, boolean exact) { + try { + JsonObject configuration = new JsonObject(); + URI location = URI.create(connectionUri); + String userInfo = location.getUserInfo(); + String user = userInfo; + String password = ""; + if (userInfo.contains(":")) { + String[] tokens = userInfo.split(":"); + user = tokens[0]; + password = tokens[1]; + } + configuration.put("user", user); + configuration.put("password", password); + configuration.put("host", location.getHost()); + int port = location.getPort(); + if (port == -1) { + port = 9000; + } + configuration.put("port", port); + String path = location.getPath(); + int startDbOffset = path.startsWith("/") ? 1 : 0; + int endLocOffset = path.endsWith("/") && path.length() >= 2 ? 1 : 0; + path = path.substring(startDbOffset, path.length() - endLocOffset); + configuration.put("database", path); + + configuration.put("properties", queryAsMap(location.getQuery())); + + return configuration; + } catch (Exception e) { + throw new IllegalArgumentException("Cannot parse invalid connection URI: " + connectionUri, e); + } + } + + public static Map queryAsMap(String query) { + if (query == null || query.isEmpty()) { + return Collections.emptyMap(); + } + return Arrays.stream(query.split("&")) + .map(ClickhouseBinaryConnectionUriParser::asEntry) + .collect(Collectors.toMap(SimpleImmutableEntry::getKey, SimpleImmutableEntry::getValue)); + } + + public static AbstractMap.SimpleImmutableEntry asEntry(String str) { + int idx = str.indexOf("="); + String key = idx > 0 ? str.substring(0, idx) : str; + String value = idx > 0 && str.length() > idx + 1 ? str.substring(idx + 1) : null; + return new AbstractMap.SimpleImmutableEntry<>(key, value); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryDatabaseMetadata.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryDatabaseMetadata.java new file mode 100644 index 000000000..1532210d5 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryDatabaseMetadata.java @@ -0,0 +1,161 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.sqlclient.spi.DatabaseMetadata; + +import java.nio.charset.Charset; +import java.time.Duration; +import java.time.ZoneId; +import java.util.Map; + +public class ClickhouseBinaryDatabaseMetadata implements DatabaseMetadata { + private final String productName; + private final String fullVersion; + private final int major; + private final int minor; + private final int revision; + private final int patchVersion; + private final String displayName; + private final ZoneId serverZoneId; + private final ZoneId defaultZoneId; + private final String fullClientName; + private final Charset stringCharset; + private final Map properties; + private final Duration yearDuration; + private final Duration quarterDuration; + private final Duration monthDuration; + private final boolean saturateExtraNanos; + private final boolean removeTrailingZerosInFixedStrings; + + public ClickhouseBinaryDatabaseMetadata(String productName, String fullVersion, int major, int minor, int revision, + int patchVersion, String displayName, ZoneId serverZoneId, ZoneId defaultZoneId, + String fullClientName, Map properties, Charset stringCharset, + Duration yearDuration, Duration quarterDuration, Duration monthDuration, + boolean saturateExtraNanos, boolean removeTrailingZerosInFixedStrings) { + this.productName = productName; + this.fullVersion = fullVersion; + this.major = major; + this.minor = minor; + this.revision = revision; + this.patchVersion = patchVersion; + this.displayName = displayName; + this.serverZoneId = serverZoneId; + this.defaultZoneId = defaultZoneId; + this.fullClientName = fullClientName; + this.properties = properties; + this.stringCharset = stringCharset; + this.yearDuration = yearDuration; + this.quarterDuration = quarterDuration; + this.monthDuration = monthDuration; + this.saturateExtraNanos = saturateExtraNanos; + this.removeTrailingZerosInFixedStrings = removeTrailingZerosInFixedStrings; + } + + public static Charset charset(Map props) { + String desiredCharset = props.get(ClickhouseConstants.OPTION_STRING_CHARSET); + if (desiredCharset == null || "system_default".equals(desiredCharset)) { + return Charset.defaultCharset(); + } else { + return Charset.forName(desiredCharset); + } + } + + @Override + public String productName() { + return productName; + } + + @Override + public String fullVersion() { + return fullVersion; + } + + @Override + public int majorVersion() { + return major; + } + + @Override + public int minorVersion() { + return minor; + } + + public int getRevision() { + return revision; + } + + public int getPatchVersion() { + return patchVersion; + } + + public String getDisplayName() { + return displayName; + } + + public ZoneId getServerZoneId() { + return serverZoneId; + } + + public ZoneId getDefaultZoneId() { + return defaultZoneId; + } + + public String getFullClientName() { + return fullClientName; + } + + public Map getProperties() { + return properties; + } + + public Charset getStringCharset() { + return stringCharset; + } + + public Duration yearDuration() { + return yearDuration; + } + + public Duration quarterDuration() { + return quarterDuration; + } + + public Duration monthDuration() { + return monthDuration; + } + + public boolean isSaturateExtraNanos() { + return saturateExtraNanos; + } + + public boolean isRemoveTrailingZerosInFixedStrings() { + return removeTrailingZerosInFixedStrings; + } + + @Override + public String toString() { + return "ClickhouseNativeDatabaseMetadata{" + + "productName='" + productName + '\'' + + ", fullVersion='" + fullVersion + '\'' + + ", major=" + major + + ", minor=" + minor + + ", revision=" + revision + + ", patchVersion=" + patchVersion + + ", displayName='" + displayName + '\'' + + ", timezone='" + serverZoneId + '\'' + + '}'; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryPoolImpl.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryPoolImpl.java new file mode 100644 index 000000000..bc2604d11 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryPoolImpl.java @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryPool; +import io.vertx.core.impl.CloseFuture; +import io.vertx.core.impl.VertxInternal; +import io.vertx.sqlclient.Pool; +import io.vertx.sqlclient.impl.PoolBase; + +public class ClickhouseBinaryPoolImpl extends PoolBase implements ClickhouseBinaryPool { + public ClickhouseBinaryPoolImpl(VertxInternal vertx, CloseFuture closeFuture, Pool delegate) { + super(vertx, closeFuture, delegate); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryRowDesc.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryRowDesc.java new file mode 100644 index 000000000..bf07f4d7c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryRowDesc.java @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.impl.RowDesc; + +public class ClickhouseBinaryRowDesc extends RowDesc { + public static final ClickhouseBinaryColumnDescriptor[] EMPTY_DESCRIPTORS = new ClickhouseBinaryColumnDescriptor[0]; + public static final ClickhouseBinaryRowDesc EMPTY = new ClickhouseBinaryRowDesc(EMPTY_DESCRIPTORS); + + public ClickhouseBinaryRowDesc(ClickhouseBinaryColumnDescriptor[] columnDescriptors) { + super(columnDescriptors); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryRowImpl.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryRowImpl.java new file mode 100644 index 000000000..f706083bc --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinaryRowImpl.java @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumnReader; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.NullValue; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +public class ClickhouseBinaryRowImpl implements Row { + private final int rowNo; + private final Charset stringCharset; + private final ClickhouseBinaryRowDesc rowDesc; + private final ColumnOrientedBlock block; + + public ClickhouseBinaryRowImpl(int rowNo, ClickhouseBinaryRowDesc rowDesc, ColumnOrientedBlock block, ClickhouseBinaryDatabaseMetadata md) { + this.rowNo = rowNo; + this.rowDesc = rowDesc; + this.block = block; + this.stringCharset = md.getStringCharset(); + } + + @Override + public String getColumnName(int pos) { + return rowDesc.columnNames().get(pos); + } + + @Override + public int getColumnIndex(String column) { + return rowDesc.columnIndex(column); + } + + @Override + public Object getValue(int columnIndex) { + return getValue(columnIndex, Object.class); + } + + private Object getValue(int columnIndex, Class desired) { + List data = block.getData(); + ClickhouseColumnReader column = data.get(columnIndex); + Object columnData = column.getElement(rowNo, desired); + return columnData; + } + + @Override + public T get(Class type, int position) { + if (type == null) { + throw new IllegalArgumentException("Accessor type can not be null"); + } + Object value = getValue(position, type); + if (value == null) { + return null; + } + if (type.isAssignableFrom(value.getClass())) { + return type.cast(value); + } + throw new ClassCastException("can't cast value " + value + " at position " + position + " of class " + value.getClass().getName() + " to class " + type.getName()); + } + + @Override + public String getString(int pos) { + Object val = getValue(pos); + if (val == null) { + return null; + } else if (val instanceof String) { + return (String) val; + } else if (val instanceof Enum) { + return ((Enum) val).name(); + } else if (val.getClass() == byte[].class) { + return new String((byte[])val, stringCharset); + } else { + throw new ClassCastException("Invalid String value type " + val.getClass()); + } + } + + @Override + public Tuple addValue(Object value) { + throw new IllegalStateException("not implemented"); + } + + @Override + public int size() { + return block.numColumns(); + } + + @Override + public void clear() { + throw new IllegalStateException("not implemented"); + } + + @Override + public List> types() { + int len = size(); + List> types = new ArrayList<>(len); + for (int i = 0; i < len; i++) { + Object param = getValue(i); + if (param instanceof NullValue) { + types.add(((NullValue) param).type()); + } else if (param == null) { + types.add(Object.class); + } else { + types.add(param.getClass()); + } + } + return types; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinarySocketConnection.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinarySocketConnection.java new file mode 100644 index 000000000..d1dc08595 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseBinarySocketConnection.java @@ -0,0 +1,120 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.netty.channel.ChannelPipeline; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryCodec; +import io.vertx.core.Promise; +import io.vertx.core.impl.EventLoopContext; +import io.vertx.core.net.impl.NetSocketInternal; +import io.vertx.sqlclient.impl.Connection; +import io.vertx.sqlclient.impl.SocketConnectionBase; +import io.vertx.sqlclient.impl.command.InitCommand; +import net.jpountz.lz4.LZ4Factory; + +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.function.Predicate; + +public class ClickhouseBinarySocketConnection extends SocketConnectionBase { + private ClickhouseBinaryCodec codec; + private ClickhouseBinaryDatabaseMetadata md; + private UUID psId; + private String ourCursorId; + private final LZ4Factory lz4Factory; + + public ClickhouseBinarySocketConnection(NetSocketInternal socket, + boolean cachePreparedStatements, + int preparedStatementCacheSize, + Predicate preparedStatementCacheSqlFilter, + EventLoopContext context, + LZ4Factory lz4Factory) { + super(socket, cachePreparedStatements, preparedStatementCacheSize, preparedStatementCacheSqlFilter, 1, context); + this.lz4Factory = lz4Factory; + } + + @Override + public void init() { + codec = new ClickhouseBinaryCodec(this); + ChannelPipeline pipeline = socket.channelHandlerContext().pipeline(); + pipeline.addBefore("handler", "codec", codec); + super.init(); + } + + void sendStartupMessage(String username, String password, String database, Map properties, Promise completionHandler) { + InitCommand cmd = new InitCommand(this, username, password, database, properties); + schedule(context, cmd).onComplete(completionHandler); + } + + public void setDatabaseMetadata(ClickhouseBinaryDatabaseMetadata md) { + this.md = md; + } + + public void lockPsOrThrow(UUID newPsId) { + if (psId == null) { + psId = newPsId; + } else { + if (newPsId != null) { + if (!Objects.equals(psId, newPsId)) { + throw new IllegalStateException("attempt to block blocked (" + psId + ") connection by ps" + newPsId); + } + } + } + } + + public void lockCursorOrThrow(UUID psId, String newCursorId) { + lockPsOrThrow(psId); + if (ourCursorId == null) { + ourCursorId = newCursorId; + } else { + if (newCursorId != null) { + if (!Objects.equals(ourCursorId, newCursorId)) { + throw new IllegalStateException("attempt to block blocked (" + ourCursorId + ") connection by cursor " + newCursorId); + } + } + } + } + + public void releaseCursor(UUID psId, String newCursorId) { + if (!Objects.equals(this.ourCursorId, newCursorId)) { + throw new IllegalStateException("can't release: pending cursor = " + ourCursorId + "; provided: " + newCursorId); + } + this.ourCursorId = null; + } + + public void releasePs(UUID newPs) { + if (!Objects.equals(this.psId, newPs)) { + throw new IllegalStateException("can't release: pending cursor = " + psId + "; provided: " + newPs); + } + this.psId = null; + } + + public void throwExceptionIfCursorIsBusy(String callerId) { + if (ourCursorId != null) { + if (!Objects.equals(ourCursorId, callerId)) { + throw new IllegalStateException("connection is busy with " + ourCursorId); + } + } + } + + @Override + public ClickhouseBinaryDatabaseMetadata getDatabaseMetaData() { + return md; + } + + public LZ4Factory lz4Factory() { + return lz4Factory; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseServerException.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseServerException.java new file mode 100644 index 000000000..89474406b --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ClickhouseServerException.java @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +public class ClickhouseServerException extends RuntimeException { + private final int code; + private final String name; + private final String message; + private final String stacktrace; + + private ClickhouseServerException(Integer code, String name, String message, String stacktrace, ClickhouseServerException cause, boolean unused) { + super(message, cause, false, true); + this.code = code; + this.name = name; + this.message = message; + //TODO: maybe log stacktraces with specified EOL (useful for log collectors) + this.stacktrace = stacktrace; + } + + private ClickhouseServerException(Integer code, String name, String message, String stacktrace, ClickhouseServerException cause) { + super(message, cause, false, false); + this.code = code; + this.name = name; + this.message = message; + this.stacktrace = stacktrace; + } + + public static ClickhouseServerException build(Integer code, String name, String message, String stacktrace, ClickhouseServerException cause, boolean first) { + if (first) { + return new ClickhouseServerException(code, name, message, stacktrace, cause, first); + } + return new ClickhouseServerException(code, name, message, stacktrace, cause); + } + + public int getCode() { + return code; + } + + public String getName() { + return name; + } + + @Override + public String getMessage() { + return message; + } + + public String getServerStacktrace() { + return stacktrace; + } + + @Override + public String toString() { + return "ClickhouseServerException{" + + "code=" + code + + ", name='" + name + '\'' + + ", message='" + message + '\'' + + ", stacktrace='" + stacktrace + '\'' + + '}'; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ColumnOrientedBlock.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ColumnOrientedBlock.java new file mode 100644 index 000000000..2bf023f7c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/ColumnOrientedBlock.java @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumnReader; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +public class ColumnOrientedBlock extends BaseBlock { + public ColumnOrientedBlock(Map columnsWithTypes, + List data, BlockInfo blockInfo, ClickhouseBinaryDatabaseMetadata md) { + super(columnsWithTypes, data, blockInfo, md); + } + + public int numColumns() { + Collection dt = getData(); + return dt == null ? 0 : dt.size(); + } + + public int numRows() { + if (numColumns() > 0) { + ClickhouseColumnReader firstColumn = getData().iterator().next(); + return firstColumn.nRows(); + } else { + return 0; + } + } + + public List rows() { + int numRows = numRows(); + List ret = new ArrayList<>(numRows); + for (int i = 0; i < numRows; ++i) { + ret.add(row(i)); + } + return ret; + } + + public ClickhouseBinaryRowImpl row(int rowNo) { + return new ClickhouseBinaryRowImpl(rowNo, rowDesc, this, md); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/RowOrientedBlock.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/RowOrientedBlock.java new file mode 100644 index 000000000..e4790ec37 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/RowOrientedBlock.java @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl; + +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumnWriter; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumns; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.impl.RowDesc; + +import java.util.List; + +public class RowOrientedBlock { + private final RowDesc rowDesc; + private final List data; + private final BlockInfo blockInfo; + private final ClickhouseBinaryDatabaseMetadata md; + private final ClickhouseColumnWriter[] writers; + + public RowOrientedBlock(RowDesc rowDesc, + List data, ClickhouseBinaryDatabaseMetadata md) { + this.rowDesc = rowDesc; + this.data = data; + this.blockInfo = new BlockInfo(); + this.md = md; + this.writers = buildWriters(); + } + + private ClickhouseColumnWriter[] buildWriters() { + ClickhouseColumnWriter[] ret = new ClickhouseColumnWriter[nColumns()]; + for (int columnIndex = 0; columnIndex < nColumns(); ++columnIndex) { + ClickhouseBinaryColumnDescriptor descr = (ClickhouseBinaryColumnDescriptor) rowDesc.columnDescriptor().get(columnIndex); + ClickhouseColumnWriter writer = ClickhouseColumns.columnForSpec(descr, md).writer(data, columnIndex); + ret[columnIndex] = writer; + } + return ret; + } + + public void serializeAsBlock(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + if (md.getRevision() >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_BLOCK_INFO) { + blockInfo.serializeTo(sink); + } + //n_columns + sink.writeULeb128(nColumns()); + //n_rows + int nRows = toRow - fromRow; + sink.writeULeb128(nRows); + //TODO: maybe serialize into tiny sinks/blocks here, then return to caller + for (int columnIndex = 0; columnIndex < nColumns(); ++columnIndex) { + ClickhouseBinaryColumnDescriptor descr = (ClickhouseBinaryColumnDescriptor) rowDesc.columnDescriptor().get(columnIndex); + sink.writePascalString(descr.name()); + sink.writePascalString(descr.getUnparsedNativeType()); + writers[columnIndex].serializeColumn(sink, fromRow, toRow); + } + } + + public int nColumns() { + return rowDesc.columnDescriptor().size(); + } + + public int totalRows() { + return data.size(); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/BlockStreamProfileInfo.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/BlockStreamProfileInfo.java new file mode 100644 index 000000000..f5e3d8e17 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/BlockStreamProfileInfo.java @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +public class BlockStreamProfileInfo { + private final int rows; + private final int blocks; + private final int bytes; + private final boolean appliedLimit; + private final int rowsBeforeLimit; + private final boolean calculatedRowsBeforeLimit; + + public BlockStreamProfileInfo(int rows, int blocks, int bytes, boolean appliedLimit, int rowsBeforeLimit, + boolean calculatedRowsBeforeLimit) { + this.rows = rows; + this.blocks = blocks; + this.bytes = bytes; + this.appliedLimit = appliedLimit; + this.rowsBeforeLimit = rowsBeforeLimit; + this.calculatedRowsBeforeLimit = calculatedRowsBeforeLimit; + } + + public int getRows() { + return rows; + } + + public int getBlocks() { + return blocks; + } + + public int getBytes() { + return bytes; + } + + public boolean getAppliedLimit() { + return appliedLimit; + } + + public int getRowsBeforeLimit() { + return rowsBeforeLimit; + } + + public boolean getCalculatedRowsBeforeLimit() { + return calculatedRowsBeforeLimit; + } + + @Override + public String toString() { + return "BlockStreamProfileInfo{" + + "rows=" + rows + + ", blocks=" + blocks + + ", bytes=" + bytes + + ", appliedLimit=" + appliedLimit + + ", rowsBeforeLimit=" + rowsBeforeLimit + + ", calculatedRowsBeforeLimit=" + calculatedRowsBeforeLimit + + '}'; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/BlockStreamProfileInfoReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/BlockStreamProfileInfoReader.java new file mode 100644 index 000000000..bc56ed327 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/BlockStreamProfileInfoReader.java @@ -0,0 +1,76 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; + +public class BlockStreamProfileInfoReader { + private static final Logger LOG = LoggerFactory.getLogger(BlockStreamProfileInfoReader.class); + + private Integer rows; + private Integer blocks; + private Integer bytes; + private Boolean appliedLimit; + private Integer rowsBeforeLimit; + private Boolean calculatedRowsBeforeLimit; + + public BlockStreamProfileInfo readFrom(ByteBuf in) { + int idxStart = in.readerIndex(); + if (rows == null) { + rows = ByteBufUtils.readULeb128(in); + if (rows == null) { + return null; + } + } + if (blocks == null) { + blocks = ByteBufUtils.readULeb128(in); + if (blocks == null) { + return null; + } + } + if (bytes == null) { + bytes = ByteBufUtils.readULeb128(in); + if (bytes == null) { + return null; + } + } + if (appliedLimit == null) { + if (in.readableBytes() == 0) { + return null; + } + appliedLimit = in.readBoolean(); + } + if (rowsBeforeLimit == null) { + rowsBeforeLimit = ByteBufUtils.readULeb128(in); + if (rowsBeforeLimit == null) { + return null; + } + } + if (calculatedRowsBeforeLimit == null) { + if (in.readableBytes() == 0) { + return null; + } + calculatedRowsBeforeLimit = in.readBoolean(); + } + if (LOG.isDebugEnabled()) { + int idxEnd = in.readerIndex(); + String bufferAsStringConsumed = ByteBufUtil.hexDump(in, idxStart, idxEnd - idxStart); + LOG.debug("bufferAsStringConsumed: " + bufferAsStringConsumed); + } + return new BlockStreamProfileInfo(rows, blocks, bytes, appliedLimit, rowsBeforeLimit, calculatedRowsBeforeLimit); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ByteBufUtils.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ByteBufUtils.java new file mode 100644 index 000000000..6cab2cedb --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ByteBufUtils.java @@ -0,0 +1,81 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +public class ByteBufUtils { + public static void writeULeb128(int value, ByteBuf buf) { + assert (value >= 0); + int remaining = value >>> 7; + while (remaining != 0) { + buf.writeByte((byte) ((value & 0x7f) | 0x80)); + value = remaining; + remaining >>>= 7; + } + buf.writeByte((byte) (value & 0x7f)); + } + + public static Integer readULeb128(ByteBuf buf) { + int value = 0; + int read = 0; + int count = 0; + int readerIndex = buf.readerIndex(); + boolean notEnoughData = false; + do { + if (buf.readableBytes() >= 1) { + read = buf.readByte() & 0xff; + value |= (read & 0x7f) << (count * 7); + count++; + } else { + notEnoughData = true; + break; + } + } while (((read & 0x80) == 0x80) && count < 5); + + if (notEnoughData) { + buf.readerIndex(readerIndex); + return null; + } + if ((read & 0x80) == 0x80) { + buf.readerIndex(readerIndex); + throw new RuntimeException("invalid LEB128 sequence"); + } + return value; + } + + public static String readPascalString(ByteBuf buf, Charset charset) { + int readerIndex = buf.readerIndex(); + Integer length = readULeb128(buf); + if (length == null) { + return null; + } + if (buf.readableBytes() >= length) { + byte[] b = new byte[length]; + buf.readBytes(b); + return new String(b, charset); + } + buf.readerIndex(readerIndex); + return null; + } + + public static void writePascalString(String str, ByteBuf buf) { + byte[] b = str.getBytes(StandardCharsets.UTF_8); + writeULeb128(b.length, buf); + buf.writeBytes(b); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryCodec.java new file mode 100644 index 000000000..782258d08 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryCodec.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.CombinedChannelDuplexHandler; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinarySocketConnection; +import io.vertx.core.impl.NoStackTraceThrowable; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.impl.command.CommandBase; +import io.vertx.sqlclient.impl.command.CommandResponse; + +import java.util.ArrayDeque; +import java.util.Iterator; + +public class ClickhouseBinaryCodec extends CombinedChannelDuplexHandler { + private static final Logger LOG = LoggerFactory.getLogger(ClickhouseBinaryCodec.class); + + private ArrayDeque> inflight; + + public ClickhouseBinaryCodec(ClickhouseBinarySocketConnection conn) { + inflight = new ArrayDeque<>(); + ClickhouseBinaryEncoder encoder = new ClickhouseBinaryEncoder(inflight, conn); + ClickhouseBinaryDecoder decoder = new ClickhouseBinaryDecoder(inflight); + init(decoder, encoder); + } + + @Override + public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { + fail(ctx, cause); + super.exceptionCaught(ctx, cause); + } + + private void fail(ChannelHandlerContext ctx, Throwable cause) { + for (Iterator> it = inflight.iterator(); it.hasNext();) { + ClickhouseBinaryCommandCodec codec = it.next(); + it.remove(); + CommandResponse failure = CommandResponse.failure(cause); + failure.cmd = (CommandBase) codec.cmd; + ctx.fireChannelRead(failure); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + fail(ctx, new NoStackTraceThrowable("Fail to read any response from the server, the underlying connection might get lost unexpectedly.")); + super.channelInactive(ctx); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryColumnDescriptor.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryColumnDescriptor.java new file mode 100644 index 000000000..27f417f9e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryColumnDescriptor.java @@ -0,0 +1,189 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.vertx.sqlclient.desc.ColumnDescriptor; + +import java.math.BigInteger; +import java.sql.JDBCType; + +public class ClickhouseBinaryColumnDescriptor implements ColumnDescriptor { + public static final int NOSIZE = -1; + + private final String name; + private final String unparsedNativeType; + private final String nestedType; + private final JDBCType jdbcType; + private final int elementSize; + private final boolean isArray; + private final boolean nullable; + private final boolean unsigned; + private final boolean lowCardinality; + private final BigInteger minValue; + private final BigInteger maxValue; + + private final Integer precision; + private final Integer scale; + + private final int arrayDimensionsCount; + private final ClickhouseBinaryColumnDescriptor nested; + + public ClickhouseBinaryColumnDescriptor(String name, String unparsedNativeType, String nestedType, + boolean isArray, int elementSize, JDBCType jdbcType, + boolean nullable, boolean unsigned, + boolean lowCardinality, Number minValue, Number maxValue) { + this(name, unparsedNativeType, nestedType, isArray, elementSize, jdbcType, nullable, unsigned, lowCardinality, + minValue, maxValue, null, null, -1, null); + } + + public ClickhouseBinaryColumnDescriptor(String name, String unparsedNativeType, String nestedType, + boolean isArray, int elementSize, JDBCType jdbcType, + boolean nullable, boolean unsigned, + boolean lowCardinality, Number minValue, Number maxValue, + int arrayDimensionsCount, ClickhouseBinaryColumnDescriptor nested) { + this(name, unparsedNativeType, nestedType, isArray, elementSize, jdbcType, nullable, unsigned, lowCardinality, + minValue, maxValue, null, null, arrayDimensionsCount, nested); + } + + public ClickhouseBinaryColumnDescriptor(String name, String unparsedNativeType, String nestedType, + boolean isArray, int elementSize, JDBCType jdbcType, + boolean nullable, boolean unsigned, + boolean lowCardinality, Number minValue, Number maxValue, + Integer precision, Integer scale) { + this(name, unparsedNativeType, nestedType, isArray, elementSize, jdbcType, nullable, unsigned, lowCardinality, + minValue, maxValue, precision, scale, -1, null); + } + + public ClickhouseBinaryColumnDescriptor(String name, String unparsedNativeType, String nestedType, + boolean isArray, int elementSize, JDBCType jdbcType, + boolean nullable, boolean unsigned, + boolean lowCardinality, Number minValue, Number maxValue, + Integer precision, Integer scale, + int arrayDimensionsCount, ClickhouseBinaryColumnDescriptor nested) { + this.name = name; + this.unparsedNativeType = unparsedNativeType; + this.nestedType = nestedType; + this.isArray = isArray; + this.elementSize = elementSize; + this.jdbcType = jdbcType; + this.nullable = nullable; + this.unsigned = unsigned; + this.lowCardinality = lowCardinality; + this.minValue = bi(minValue); + this.maxValue = bi(maxValue); + this.precision = precision; + this.scale = scale; + this.arrayDimensionsCount = arrayDimensionsCount; + this.nested = nested; + } + + private BigInteger bi(Number src) { + if (src instanceof Byte || src instanceof Integer || src instanceof Long) { + return BigInteger.valueOf(src.longValue()); + } + return (BigInteger) src; + } + + @Override + public String name() { + return name; + } + + @Override + public boolean isArray() { + return isArray; + } + + public int arrayDimensionsCount() { + return arrayDimensionsCount; + } + + @Override + public JDBCType jdbcType() { + return jdbcType; + } + + @Override + public String typeName() { + return unparsedNativeType; + } + + //TODO: remove? + @Deprecated + public String getUnparsedNativeType() { + return unparsedNativeType; + } + + public int getElementSize() { + return elementSize; + } + + public boolean isNullable() { + return nullable; + } + + public boolean isUnsigned() { + return unsigned; + } + + public boolean isLowCardinality() { + return lowCardinality; + } + + public BigInteger getMinValue() { + return minValue; + } + + public BigInteger getMaxValue() { + return maxValue; + } + + public String getNestedType() { + return nestedType; + } + + public ClickhouseBinaryColumnDescriptor getNestedDescr() { + return nested; + } + + public Integer getPrecision() { + return precision; + } + + public Integer getScale() { + return scale; + } + + public ClickhouseBinaryColumnDescriptor copyWithModifiers(boolean newArray, boolean newLowCardinality, boolean newNullable) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedNativeType, nestedType, newArray, elementSize, jdbcType, + newNullable, unsigned, newLowCardinality, minValue, maxValue, precision, scale, arrayDimensionsCount, nested); + } + + public ClickhouseBinaryColumnDescriptor copyWithModifiers(boolean newLowCardinality, boolean newNullable) { + return copyWithModifiers(isArray, newLowCardinality, newNullable); + } + + @Override + public String toString() { + return "ClickhouseNativeColumnDescriptor{" + + "name='" + name + '\'' + + ", unparsedNativeType='" + unparsedNativeType + '\'' + + ", nativeType='" + nestedType + '\'' + + ", isArray=" + isArray + + ", jdbcType=" + jdbcType + + ", elementSize=" + elementSize + + ", nullable=" + nullable + + '}'; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryCommandCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryCommandCodec.java new file mode 100644 index 000000000..0341c7723 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryCommandCodec.java @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.core.Handler; +import io.vertx.sqlclient.impl.command.CommandBase; +import io.vertx.sqlclient.impl.command.CommandResponse; + +abstract class ClickhouseBinaryCommandCodec> { + protected ClickhouseBinaryEncoder encoder; + protected Handler> completionHandler; + protected final C cmd; + + protected ClickhouseBinaryCommandCodec(C cmd) { + this.cmd = cmd; + } + + void encode(ClickhouseBinaryEncoder encoder) { + this.encoder = encoder; + } + + abstract void decode(ChannelHandlerContext ctx, ByteBuf in); + + ByteBuf allocateBuffer() { + return encoder.chctx().alloc().ioBuffer(); + } + + ByteBuf allocateBuffer(int capacity) { + return encoder.chctx().alloc().ioBuffer(capacity); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryDecoder.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryDecoder.java new file mode 100644 index 000000000..eddd9e08b --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryDecoder.java @@ -0,0 +1,35 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.ByteToMessageDecoder; + +import java.util.ArrayDeque; +import java.util.List; + +public class ClickhouseBinaryDecoder extends ByteToMessageDecoder { + private final ArrayDeque> inflight; + + public ClickhouseBinaryDecoder(ArrayDeque> inflight) { + this.inflight = inflight; + } + + @Override + protected void decode(ChannelHandlerContext ctx, ByteBuf in, List out) throws Exception { + ClickhouseBinaryCommandCodec codec = inflight.peek(); + codec.decode(ctx, in); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryEncoder.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryEncoder.java new file mode 100644 index 000000000..1f6afe07c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryEncoder.java @@ -0,0 +1,154 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.ChannelOutboundHandlerAdapter; +import io.netty.channel.ChannelPromise; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinarySocketConnection; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.impl.QueryResultHandler; +import io.vertx.sqlclient.impl.command.*; + +import java.util.ArrayDeque; + +public class ClickhouseBinaryEncoder extends ChannelOutboundHandlerAdapter { + private static final Logger LOG = LoggerFactory.getLogger(ClickhouseBinaryEncoder.class); + + private final ArrayDeque> inflight; + private final ClickhouseBinarySocketConnection conn; + + private InitCommand initCommand; + private DbSwitchState dbSwitchState; + + private ChannelHandlerContext chctx; + + public ClickhouseBinaryEncoder(ArrayDeque> inflight, ClickhouseBinarySocketConnection conn) { + this.inflight = inflight; + this.conn = conn; + } + + ClickhouseBinarySocketConnection getConn() { + return conn; + } + + @Override + public void handlerAdded(ChannelHandlerContext ctx) { + chctx = ctx; + } + + ChannelHandlerContext chctx() { + return chctx; + } + + @Override + public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception { + CommandBase cmd = null; + try { + if (msg instanceof CommandBase) { + cmd = (CommandBase) msg; + write(cmd); + } else { + super.write(ctx, msg, promise); + } + } catch (Throwable t) { + deliverError(cmd, t); + throw t; + } + } + + void write(CommandBase cmd) { + if (LOG.isDebugEnabled()) { + LOG.debug("got command: " + cmd.getClass()); + } + ClickhouseBinaryCommandCodec codec = wrap(cmd); + codec.completionHandler = resp -> { + ClickhouseBinaryCommandCodec c = inflight.poll(); + resp.cmd = (CommandBase) c.cmd; + boolean initCodecCommand = c instanceof InitCommandCodec; + InitCommandCodec initCommandCodec = initCodecCommand ? (InitCommandCodec) c : null; + if (initCodecCommand) { + this.initCommand = initCommandCodec.cmd; + String dbName = initCommand.database(); + dbSwitchState = (dbName == null || dbName.isEmpty()) ? null : DbSwitchState.NeedDbSwitch; + } + if (dbSwitchState == DbSwitchState.NeedDbSwitch && initCodecCommand) { + String query = "USE " + initCommandCodec.cmd.database() + ";"; + LOG.info("sending '" + query + "' command"); + + write(new SimpleQueryCommand(query, false, false, QueryCommandBase.NULL_COLLECTOR, QueryResultHandler.NOOP_HANDLER)); + dbSwitchState = DbSwitchState.SentSwitchCommand; + } else { + if (dbSwitchState == DbSwitchState.SentSwitchCommand) { + resp.cmd = (CommandBase)initCommand; + dbSwitchState = DbSwitchState.SwitchedDb; + } + chctx.fireChannelRead(resp); + } + }; + inflight.add(codec); + codec.encode(this); + } + + private ClickhouseBinaryCommandCodec wrap(CommandBase cmd) { + if (cmd instanceof InitCommand) { + return new InitCommandCodec((InitCommand) cmd); + } else if (cmd instanceof SimpleQueryCommand) { + return new SimpleQueryCommandCodec<>((SimpleQueryCommand) cmd, conn); + } else if (cmd instanceof CloseConnectionCommand) { + return new CloseConnectionCommandCodec((CloseConnectionCommand)cmd); + } else if (cmd instanceof PrepareStatementCommand) { + PrepareStatementCommand ps = (PrepareStatementCommand) cmd; + QueryInfo queryInfo = QueryInfo.parse(ps.sql()); + return new PrepareStatementCodec(ps, queryInfo); + } else if (cmd instanceof ExtendedQueryCommand) { + ExtendedQueryCommand ecmd = (ExtendedQueryCommand) cmd; + QueryInfo queryInfo; + if (ecmd.preparedStatement() != null) { + queryInfo = ((ClickhouseBinaryPreparedStatement) ecmd.preparedStatement()).queryInfo(); + } else { + queryInfo = QueryInfo.parse(ecmd.sql()); + } + if (queryInfo != null && !queryInfo.isInsert() && ecmd.isBatch() && ecmd.paramsList() != null && ecmd.paramsList().size() > 1) { + RuntimeException ex = new UnsupportedOperationException("batch queries are supported for INSERTs only"); + deliverError(cmd, ex); + } + return new ExtendedQueryCommandCodec<>(queryInfo, ecmd, conn); + } else if (cmd instanceof CloseCursorCommand) { + return new CloseCursorCommandCodec((CloseCursorCommand)cmd, conn); + } else if (cmd instanceof CloseStatementCommand) { + return new CloseStatementCommandCodec((CloseStatementCommand) cmd, conn); + } + RuntimeException ex = new UnsupportedOperationException(cmd.getClass().getName()); + deliverError(cmd, ex); + throw ex; + } + + private void deliverError(CommandBase cmd, Throwable ex) { + if (cmd instanceof QueryCommandBase) { + QueryCommandBase ecmd = (QueryCommandBase)cmd; + ecmd.resultHandler().handleResult(0, 0, null, null, ex); + } + CommandResponse resp = CommandResponse.failure(ex); + resp.cmd = cmd; + chctx.fireChannelRead(resp); + } + + private enum DbSwitchState { + NeedDbSwitch, + SentSwitchCommand, + SwitchedDb + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryParamDesc.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryParamDesc.java new file mode 100644 index 000000000..cfc3903fd --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryParamDesc.java @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.vertx.sqlclient.impl.ParamDesc; + +import java.util.List; + +public class ClickhouseBinaryParamDesc extends ParamDesc { + private final List paramDescr; + + public ClickhouseBinaryParamDesc(List paramDescr) { + this.paramDescr = paramDescr; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryPreparedStatement.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryPreparedStatement.java new file mode 100644 index 000000000..cf0001565 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryPreparedStatement.java @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryRowDesc; +import io.vertx.sqlclient.impl.ParamDesc; +import io.vertx.sqlclient.impl.PreparedStatement; +import io.vertx.sqlclient.impl.RowDesc; +import io.vertx.sqlclient.impl.TupleInternal; + +import java.util.UUID; + +public class ClickhouseBinaryPreparedStatement implements PreparedStatement { + private final String sql; + private final ClickhouseBinaryParamDesc paramDesc; + private final ClickhouseBinaryRowDesc rowDesc; + private final QueryInfo queryInfo; + private final boolean sentQuery; + private final UUID psId; + + public ClickhouseBinaryPreparedStatement(String sql, ClickhouseBinaryParamDesc paramDesc, ClickhouseBinaryRowDesc rowDesc, + QueryInfo queryInfo, boolean sentQuery, UUID psId) { + this.sql = sql; + this.paramDesc = paramDesc; + this.rowDesc = rowDesc; + this.queryInfo = queryInfo; + this.sentQuery = sentQuery; + this.psId = psId; + } + + @Override + public ParamDesc paramDesc() { + return paramDesc; + } + + @Override + public RowDesc rowDesc() { + return rowDesc; + } + + @Override + public String sql() { + return sql; + } + + @Override + public String prepare(TupleInternal values) { + return null; + } + + public QueryInfo queryInfo() { + return queryInfo; + } + + public boolean isSentQuery() { + return sentQuery; + } + + public UUID getPsId() { + return psId; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryQueryCommandBaseCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryQueryCommandBaseCodec.java new file mode 100644 index 000000000..76a6de4ef --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseBinaryQueryCommandBaseCodec.java @@ -0,0 +1,22 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.vertx.sqlclient.impl.command.QueryCommandBase; + +abstract class ClickhouseBinaryQueryCommandBaseCodec> extends ClickhouseBinaryCommandCodec { + protected ClickhouseBinaryQueryCommandBaseCodec(C cmd) { + super(cmd); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseExceptionReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseExceptionReader.java new file mode 100644 index 000000000..c75954952 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseExceptionReader.java @@ -0,0 +1,111 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.vertx.clickhouseclient.binary.impl.ClickhouseServerException; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +public class ClickhouseExceptionReader { + private final List exceptionBlocks = new ArrayList<>(); + + private final Charset charset; + private Integer code; + private String name; + private String message; + private String stacktrace; + private Boolean hasNested; + + public ClickhouseExceptionReader(Charset charset) { + this.charset = charset; + } + + + public ClickhouseServerException readFrom(ByteBuf in) { + boolean hadNested; + do { + if (code == null) { + if (in.readableBytes() >= 4) { + code = in.readIntLE(); + } else { + return null; + } + } + if (name == null) { + name = ByteBufUtils.readPascalString(in, charset); + if (name == null) { + return null; + } + } + if (message == null) { + message = ByteBufUtils.readPascalString(in, charset); + if (message == null) { + return null; + } + } + if (stacktrace == null) { + stacktrace = ByteBufUtils.readPascalString(in, charset); + if (stacktrace == null) { + return null; + } + } + if (hasNested == null) { + if (in.readableBytes() >= 1) { + hasNested = in.readBoolean(); + } else { + return null; + } + } + hadNested = hasNested; + ExceptionBlock tmp = new ExceptionBlock(code, name, message, stacktrace, hasNested); + code = null; + name = null; + message = null; + stacktrace = null; + hasNested = null; + exceptionBlocks.add(tmp); + } while (hadNested); + + boolean isFirst = exceptionBlocks.size() == 1; + ClickhouseServerException prevException = exceptionBlocks.get(exceptionBlocks.size() - 1).toException(null, isFirst); + if (!isFirst) { + for (int idx = exceptionBlocks.size() - 2; idx >= 0; --idx) { + isFirst = idx == 0; + prevException = exceptionBlocks.get(idx).toException(prevException, isFirst); + } + } + return prevException; + } + + private static class ExceptionBlock { + private final Integer code; + private final String name; + private final String message; + private final String stacktrace; + + private ExceptionBlock(Integer code, String name, String message, String stacktrace, Boolean hasNested) { + this.code = code; + this.name = name; + this.message = message; + this.stacktrace = stacktrace; + } + + public ClickhouseServerException toException(ClickhouseServerException cause, boolean first) { + return ClickhouseServerException.build(code, name, message, stacktrace, cause, first); + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseStreamDataSink.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseStreamDataSink.java new file mode 100644 index 000000000..17fe21f11 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseStreamDataSink.java @@ -0,0 +1,33 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +public interface ClickhouseStreamDataSink { + void writeULeb128(int value); + void writeByte(int value); + void writeShortLE(int value); + void writeIntLE(int value); + void writeLongLE(long value); + void writeFloatLE(float value); + void writeDoubleLE(double value); + void writeBytes(byte[] value); + void writeBytes(byte[] value, int index, int length); + void writeBoolean(boolean value); + void writeZero(int length); + void writePascalString(String value); + void ensureWritable(int size); + + default void finish() { + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseStreamDataSource.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseStreamDataSource.java new file mode 100644 index 000000000..1a4dca7cb --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClickhouseStreamDataSource.java @@ -0,0 +1,44 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; + +public interface ClickhouseStreamDataSource { + Logger LOG = LoggerFactory.getLogger(ClickhouseStreamDataSource.class); + + void moreData(ByteBuf buf, ByteBufAllocator ctx); + int readerIndex(); + int readableBytes(); + void skipBytes(int length); + String readPascalString(); + Integer readULeb128(); + boolean readBoolean(); + int readIntLE(); + long readLongLE(); + short readShortLE(); + float readFloatLE(); + double readDoubleLE(); + ByteBuf readSlice(int nBytes); + void readBytes(byte[] dst); + byte readByte(); + String hexDump(int fromIndex, int len); + + String hexDump(); + + void finish(); +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClientInfo.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClientInfo.java new file mode 100644 index 000000000..62b06cddd --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClientInfo.java @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; + +import java.util.Map; + +public class ClientInfo { + public static final int NO_QUERY = 0; + public static final int INITIAL_QUERY = 1; + + private final ClickhouseBinaryDatabaseMetadata meta; + + public ClientInfo(ClickhouseBinaryDatabaseMetadata meta) { + this.meta = meta; + } + + public void serializeTo(ByteBuf buf) { + int serverRevision = meta.getRevision(); + if (serverRevision < ClickhouseConstants.DBMS_MIN_REVISION_WITH_CLIENT_INFO) { + throw new IllegalStateException(String.format("server revision %d < DBMS_MIN_REVISION_WITH_CLIENT_INFO(%d)", + serverRevision, ClickhouseConstants.DBMS_MIN_REVISION_WITH_CLIENT_INFO)); + } + buf.writeByte(INITIAL_QUERY); + Map properties = meta.getProperties(); + + //initial_user + ByteBufUtils.writePascalString(properties.getOrDefault(ClickhouseConstants.OPTION_INITIAL_USER, ""), buf); + //initial_query_id + ByteBufUtils.writePascalString(properties.getOrDefault(ClickhouseConstants.OPTION_INITIAL_QUERY_ID, ""), buf); + //initial_address + ByteBufUtils.writePascalString(properties.getOrDefault(ClickhouseConstants.OPTION_INITIAL_ADDRESS, "0.0.0.0:0"), buf); + //interface: TCP + buf.writeByte(1); + ByteBufUtils.writePascalString(properties.getOrDefault(ClickhouseConstants.OPTION_INITIAL_USER, System.getProperty("user.name")), buf); + ByteBufUtils.writePascalString(properties.getOrDefault(ClickhouseConstants.OPTION_INITIAL_HOSTNAME, "unknown-hostname"), buf); + ByteBufUtils.writePascalString(meta.getFullClientName(), buf); + ByteBufUtils.writeULeb128(ClickhouseConstants.CLIENT_VERSION_MAJOR, buf); + ByteBufUtils.writeULeb128(ClickhouseConstants.CLIENT_VERSION_MINOR, buf); + ByteBufUtils.writeULeb128(ClickhouseConstants.CLIENT_REVISION, buf); + if (serverRevision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_QUOTA_KEY_IN_CLIENT_INFO) { + //quota_key + ByteBufUtils.writePascalString("", buf); + } + if (serverRevision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_VERSION_PATCH) { + ByteBufUtils.writeULeb128(ClickhouseConstants.CLIENT_VERSION_PATCH, buf); + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClientPacketTypes.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClientPacketTypes.java new file mode 100644 index 000000000..e10aae225 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ClientPacketTypes.java @@ -0,0 +1,20 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +public class ClientPacketTypes { + public static final int HELLO = 0; + public static final int QUERY = 1; + public static final int DATA = 2; +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseConnectionCommandCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseConnectionCommandCodec.java new file mode 100644 index 000000000..e3aae1203 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseConnectionCommandCodec.java @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.channel.ChannelHandlerContext; +import io.netty.channel.socket.SocketChannel; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.impl.command.CloseConnectionCommand; + +public class CloseConnectionCommandCodec extends ClickhouseBinaryCommandCodec { + private static final Logger LOG = LoggerFactory.getLogger(CloseConnectionCommandCodec.class); + + protected CloseConnectionCommandCodec(CloseConnectionCommand cmd) { + super(cmd); + } + + @Override + void decode(ChannelHandlerContext ctx, ByteBuf in) { + } + + @Override + public void encode(ClickhouseBinaryEncoder encoder) { + super.encode(encoder); + if (LOG.isDebugEnabled()) { + LOG.debug("closing channel"); + } + ChannelHandlerContext ctx = encoder.chctx(); + SocketChannel channel = (SocketChannel) ctx.channel(); + ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(v -> channel.shutdownOutput()); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseCursorCommandCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseCursorCommandCodec.java new file mode 100644 index 000000000..63713edd4 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseCursorCommandCodec.java @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinarySocketConnection; +import io.vertx.sqlclient.impl.command.CloseCursorCommand; +import io.vertx.sqlclient.impl.command.CommandResponse; + +public class CloseCursorCommandCodec extends ClickhouseBinaryCommandCodec { + private final ClickhouseBinarySocketConnection conn; + + protected CloseCursorCommandCodec(CloseCursorCommand cmd, ClickhouseBinarySocketConnection conn) { + super(cmd); + this.conn = conn; + } + + void encode(ClickhouseBinaryEncoder encoder) { + conn.releaseCursor(((ClickhouseBinaryPreparedStatement)cmd.statement()).getPsId(), cmd.id()); + super.encode(encoder); + completionHandler.handle(CommandResponse.success(null)); + } + + @Override + void decode(ChannelHandlerContext ctx, ByteBuf in) { + } +} + diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseStatementCommandCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseStatementCommandCodec.java new file mode 100644 index 000000000..4812f375f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/CloseStatementCommandCodec.java @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinarySocketConnection; +import io.vertx.sqlclient.impl.command.CloseStatementCommand; +import io.vertx.sqlclient.impl.command.CommandResponse; + +public class CloseStatementCommandCodec extends ClickhouseBinaryCommandCodec { + public CloseStatementCommandCodec(CloseStatementCommand cmd, ClickhouseBinarySocketConnection conn) { + super(cmd); + } + + void encode(ClickhouseBinaryEncoder encoder) { + super.encode(encoder); + ClickhouseBinaryPreparedStatement stmt = (ClickhouseBinaryPreparedStatement) cmd.statement(); + if (stmt.isSentQuery()) { + encoder.getConn().releasePs(stmt.getPsId()); + } + completionHandler.handle(CommandResponse.success(null)); + } + + + @Override + void decode(ChannelHandlerContext ctx, ByteBuf in) { + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ColumnOrientedBlockReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ColumnOrientedBlockReader.java new file mode 100644 index 000000000..7c59bba89 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ColumnOrientedBlockReader.java @@ -0,0 +1,136 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumns; +import io.vertx.clickhouseclient.binary.impl.BlockInfo; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.ColumnOrientedBlock; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumnReader; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +public class ColumnOrientedBlockReader { + private static final Logger LOG = LoggerFactory.getLogger(ColumnOrientedBlockReader.class); + + private final int serverRevision; + private final ClickhouseBinaryDatabaseMetadata md; + + private String tempTableInfo; + private BlockInfo blockInfo; + private Integer nColumns; + private Integer nRows; + private Map colWithTypes; + private List columnsData; + + private String colName; + private String colType; + private ClickhouseColumnReader columnData; + private ClickhouseBinaryColumnDescriptor columnDescriptor; + + public ColumnOrientedBlockReader(ClickhouseBinaryDatabaseMetadata md) { + assert(md != null); + this.md = md; + this.serverRevision = md.getRevision(); + } + + public ColumnOrientedBlock readFrom(ClickhouseStreamDataSource in) { + if (LOG.isDebugEnabled()) { + LOG.debug("readFrom: " + in.hexDump()); + } + //BlockInputStream.read + if (blockInfo == null) { + blockInfo = new BlockInfo(); + } + if (serverRevision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_BLOCK_INFO) { + if (blockInfo.isPartial()) { + blockInfo.readFrom(in); + if (blockInfo.isPartial()) { + return null; + } + } + } + if (nColumns == null) { + nColumns = in.readULeb128(); + if (nColumns == null) { + return null; + } + colWithTypes = new LinkedHashMap<>(); + } + if (nRows == null) { + nRows = in.readULeb128(); + if (nRows == null) { + return null; + } + } + + while (colWithTypes.size() < nColumns) { + if (colName == null) { + colName = in.readPascalString(); + if (colName == null) { + return null; + } + } + if (colType == null) { + colType = in.readPascalString(); + if (colType == null) { + return null; + } + } + if (columnDescriptor == null) { + columnDescriptor = ClickhouseColumns.columnDescriptorForSpec(colType, colName); + } + if (nRows > 0) { + if (columnsData == null) { + columnsData = new ArrayList<>(nColumns); + } + if (columnData == null) { + columnData = ClickhouseColumns.columnForSpec(columnDescriptor, md).reader(nRows); + } + if (columnData.isPartial()) { + if (LOG.isDebugEnabled()) { + LOG.debug("reading(first or continuation) column " + colName + "[" + nRows + "] of type " + colType); + } + columnData.readColumn(in); + if (columnData.isPartial()) { + if (LOG.isDebugEnabled()) { + LOG.debug("partial read of " + colName + "; buffer consumed: " + columnData.bufferAsStringConsumed()); + } + return null; + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("fully read " + colName + "; buffer consumed: " + columnData.bufferAsStringConsumed()); + } + columnsData.add(columnData); + columnData = null; + } + } + } + colWithTypes.put(colName, columnDescriptor); + columnDescriptor = null; + colName = null; + colType = null; + } + if (colWithTypes.size() == nColumns) { + return new ColumnOrientedBlock(colWithTypes, columnsData, blockInfo, md); + } + return null; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Compression.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Compression.java new file mode 100644 index 000000000..6260df9d0 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Compression.java @@ -0,0 +1,19 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +public class Compression { + public static final int DISABLED = 0; + public static final int ENABLED = 1; +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/DatabaseMetadataReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/DatabaseMetadataReader.java new file mode 100644 index 000000000..daa059178 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/DatabaseMetadataReader.java @@ -0,0 +1,117 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.time.Duration; +import java.time.ZoneId; +import java.util.Map; + +public class DatabaseMetadataReader { + private final String fullClientName; + private final Map properties; + + private String productName; + private Integer major; + private Integer minor; + private Integer revision; + private String serverZoneIdName; + private String displayName; + private Integer patchVersion; + + public DatabaseMetadataReader(String fullClientName, Map properties) { + assert(fullClientName != null); + assert(properties != null); + this.fullClientName = fullClientName; + this.properties = properties; + } + + public ClickhouseBinaryDatabaseMetadata readFrom(ByteBuf in) { + if (productName == null) { + productName = ByteBufUtils.readPascalString(in, StandardCharsets.UTF_8); + if (productName == null) { + return null; + } + } + if (major == null) { + major = ByteBufUtils.readULeb128(in); + if (major == null) { + return null; + } + } + if (minor == null) { + minor = ByteBufUtils.readULeb128(in); + if (minor == null) { + return null; + } + } + if (revision == null) { + revision = ByteBufUtils.readULeb128(in); + if (revision == null) { + return null; + } + } + if (serverZoneIdName == null && revision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_SERVER_TIMEZONE) { + serverZoneIdName = ByteBufUtils.readPascalString(in, StandardCharsets.UTF_8); + if (serverZoneIdName == null) { + return null; + } + } + if (displayName == null && revision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_SERVER_DISPLAY_NAME ) { + displayName = ByteBufUtils.readPascalString(in, StandardCharsets.UTF_8); + if (displayName == null) { + return null; + } + } + + if (revision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_VERSION_PATCH) { + if (patchVersion == null) { + patchVersion = ByteBufUtils.readULeb128(in); + if (patchVersion == null) { + return null; + } + } + } else { + patchVersion = revision; + } + int daysInYear = Integer.parseInt(properties.getOrDefault(ClickhouseConstants.OPTION_YEAR_DURATION, "365")); + int daysInQuarter = Integer.parseInt(properties.getOrDefault(ClickhouseConstants.OPTION_QUARTER_DURATION, "120")); + int daysInMonth = Integer.parseInt(properties.getOrDefault(ClickhouseConstants.OPTION_MONTH_DURATION, "30")); + ZoneId serverZoneId = serverZoneIdName == null ? null : ZoneId.of(serverZoneIdName); + ZoneId defaultZoneId = getDefaultZoneId(serverZoneId); + String extraNanos = properties.getOrDefault(ClickhouseConstants.OPTION_DATETIME64_EXTRA_NANOS_MODE, "throw"); + boolean saturateExtraNanos = "saturate".equals(extraNanos); + boolean removeTrailingZerosInFixedStringsStr = Boolean.parseBoolean(properties.getOrDefault(ClickhouseConstants.OPTION_REMOVE_TRAILING_ZEROS_WHEN_ENCODE_FIXED_STRINGS, "true")); + return new ClickhouseBinaryDatabaseMetadata(productName, + String.format("%d.%d.%d", major, minor, revision), + major, minor, revision, patchVersion, displayName, serverZoneId, defaultZoneId, fullClientName, properties, ClickhouseBinaryDatabaseMetadata.charset(properties), + Duration.ofDays(daysInYear), Duration.ofDays(daysInQuarter), Duration.ofDays(daysInMonth), saturateExtraNanos, removeTrailingZerosInFixedStringsStr); + } + + private ZoneId getDefaultZoneId(ZoneId serverZoneId) { + String defaultZoneId = properties.get(ClickhouseConstants.OPTION_DEFAULT_ZONE_ID); + if (defaultZoneId == null || "from_server".equals(defaultZoneId)) { + return serverZoneId; + } else if ("system_default".equals(defaultZoneId)) { + return ZoneId.systemDefault(); + } else { + return ZoneId.of(defaultZoneId); + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ExtendedQueryCommandCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ExtendedQueryCommandCodec.java new file mode 100644 index 000000000..5d5b94588 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ExtendedQueryCommandCodec.java @@ -0,0 +1,115 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryRowDesc; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinarySocketConnection; +import io.vertx.clickhouseclient.binary.impl.RowOrientedBlock; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.impl.PreparedStatement; +import io.vertx.sqlclient.impl.command.ExtendedQueryCommand; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class ExtendedQueryCommandCodec extends SimpleQueryCommandCodec { + private static final Logger LOG = LoggerFactory.getLogger(SimpleQueryCommandCodec.class); + + public ExtendedQueryCommandCodec(QueryInfo queryInfo, ExtendedQueryCommand cmd, ClickhouseBinarySocketConnection conn) { + super(queryInfo, cmd.paramsList() == null ? 0 : cmd.paramsList().size(), cmd, conn, cmd.fetch() > 0); + } + + @Override + protected String sql() { + ExtendedQueryCommand ecmd = ecmd(); + if ((queryInfo != null && !queryInfo.isInsert()) || !ecmd.isBatch()) { + return QueryParsers.insertParamValuesIntoQuery(ecmd.sql(), ecmd.params() == null ? ecmd.paramsList().get(0) : ecmd.params()); + } + return ecmd.sql(); + } + + @Override + void encode(ClickhouseBinaryEncoder encoder) { + ExtendedQueryCommand ecmd = ecmd(); + String ourCursorId = ecmd.cursorId(); + if (ourCursorId != null) { + conn.lockCursorOrThrow(((ClickhouseBinaryPreparedStatement)ecmd.preparedStatement()).getPsId(), ourCursorId); + } + PreparedStatement ps = ecmd.preparedStatement(); + if (ps != null && ((ClickhouseBinaryPreparedStatement)ps).isSentQuery()) { + this.encoder = encoder; + ByteBuf buf = allocateBuffer(); + try { + ChannelHandlerContext chctx = encoder.chctx(); + PacketForge forge = new PacketForge(encoder.getConn(), chctx); + ClickhouseBinaryDatabaseMetadata md = encoder.getConn().getDatabaseMetaData(); + List paramsList = ecmd.paramsList(); + if (paramsList != null && !paramsList.isEmpty()) { + RowOrientedBlock block = new RowOrientedBlock(ps.rowDesc(), (List) paramsList, md); + forge.sendColumns(block, buf, null); + } + forge.sendData(buf, new RowOrientedBlock(ClickhouseBinaryRowDesc.EMPTY, Collections.emptyList(), md),""); + chctx.writeAndFlush(buf, chctx.voidPromise()); + if (LOG.isDebugEnabled()) { + LOG.debug("sent columns"); + } + } catch (Throwable t) { + buf.release(); + throw t; + } + } else { + super.encode(encoder); + } + } + + @Override + protected Map settings() { + String fetchSize = Integer.toString(ecmd().fetch()); + Map defaultSettings = super.settings(); + String defaultFetchSize = defaultSettings.get(ClickhouseConstants.OPTION_MAX_BLOCK_SIZE); + if (!"0".equals(fetchSize)) { + if (!Objects.equals(defaultFetchSize, fetchSize)) { + if (LOG.isWarnEnabled() && defaultFetchSize != null) { + LOG.warn("overriding " + ClickhouseConstants.OPTION_MAX_BLOCK_SIZE + " option with new value " + fetchSize + ", was " + defaultSettings.get(ClickhouseConstants.OPTION_MAX_BLOCK_SIZE)); + } + defaultSettings = new HashMap<>(defaultSettings); + defaultSettings.put(ClickhouseConstants.OPTION_MAX_BLOCK_SIZE, fetchSize); + } + } + return defaultSettings; + } + + @Override + protected void checkIfBusy() { + conn.throwExceptionIfCursorIsBusy(ecmd().cursorId()); + } + + @Override + protected boolean isSuspended() { + return ecmd().isSuspended(); + } + + private ExtendedQueryCommand ecmd() { + return (ExtendedQueryCommand)cmd; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/InitCommandCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/InitCommandCodec.java new file mode 100644 index 000000000..67500c595 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/InitCommandCodec.java @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.ClickhouseServerException; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.impl.Connection; +import io.vertx.sqlclient.impl.command.CommandResponse; +import io.vertx.sqlclient.impl.command.InitCommand; + +public class InitCommandCodec extends ClickhouseBinaryCommandCodec { + private static final Logger LOG = LoggerFactory.getLogger(InitCommandCodec.class); + + private PacketReader packetReader; + private String fullClientName; + + InitCommandCodec(InitCommand cmd) { + super(cmd); + } + + @Override + void encode(ClickhouseBinaryEncoder encoder) { + super.encode(encoder); + + ByteBuf buf = allocateBuffer(); + ByteBufUtils.writeULeb128(ClientPacketTypes.HELLO, buf); + fullClientName = "ClickHouse " + cmd.properties() + .getOrDefault(ClickhouseConstants.OPTION_APPLICATION_NAME, "vertx-sql"); + ByteBufUtils.writePascalString(fullClientName, buf); + ByteBufUtils.writeULeb128(ClickhouseConstants.CLIENT_VERSION_MAJOR, buf); + ByteBufUtils.writeULeb128(ClickhouseConstants.CLIENT_VERSION_MINOR, buf); + ByteBufUtils.writeULeb128(ClickhouseConstants.CLIENT_REVISION, buf); + //Do not send db-name explicitly: it is almost impossible to catch exception-after-hello packet in newer versions (e.g. database does not exist). + //Instead, send explicit 'USE db-name' after hello packet if db-name is non-empty. + //Old versions answer with Exception-only (no HELLO/metadata packet) + ByteBufUtils.writePascalString("", buf); + ByteBufUtils.writePascalString(cmd.username(), buf); + ByteBufUtils.writePascalString(cmd.password(), buf); + encoder.chctx().writeAndFlush(buf, encoder.chctx().voidPromise()); + if (LOG.isDebugEnabled()) { + LOG.debug("sent hello packet "); + } + } + + @Override + void decode(ChannelHandlerContext ctx, ByteBuf in) { + if (packetReader == null) { + packetReader = new PacketReader(encoder.getConn().getDatabaseMetaData(), fullClientName, cmd.properties(), encoder.getConn().lz4Factory()); + } + Object packet = packetReader.receivePacket(ctx.alloc(), in); + if (packet != null) { + if (packet.getClass() == ClickhouseBinaryDatabaseMetadata.class) { + ClickhouseBinaryDatabaseMetadata md = (ClickhouseBinaryDatabaseMetadata)packet; + encoder.getConn().setDatabaseMetadata(md); + if (LOG.isDebugEnabled()) { + LOG.debug("connected to server: " + md + "; readableBytes: " + in.readableBytes()); + } + completionHandler.handle(CommandResponse.success(null)); + } else if (packet.getClass() == ClickhouseServerException.class) { + ClickhouseServerException exc = (ClickhouseServerException)packet; + completionHandler.handle(CommandResponse.failure(exc)); + } else { + String msg = "unknown packet type: " + packet.getClass(); + LOG.error(msg); + completionHandler.handle(CommandResponse.failure(new RuntimeException(msg))); + } + packetReader = null; + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Lz4ClickhouseStreamDataSink.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Lz4ClickhouseStreamDataSink.java new file mode 100644 index 000000000..1b30a9514 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Lz4ClickhouseStreamDataSink.java @@ -0,0 +1,138 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import net.jpountz.lz4.LZ4Compressor; +import net.jpountz.lz4.LZ4Factory; +import ru.yandex.clickhouse.util.ClickHouseCityHash; + +class Lz4ClickhouseStreamDataSink implements ClickhouseStreamDataSink { + private static final Logger LOG = LoggerFactory.getLogger(Lz4ClickhouseStreamDataSink.class); + + public static final int HEADER_SIZE = 1 + 4 + 4; + + private final ByteBuf sink; + private final LZ4Factory lz4Factory; + private final ByteBuf tmpStorage; + private final ChannelHandlerContext ctx; + + Lz4ClickhouseStreamDataSink(ByteBuf sink, LZ4Factory lz4Factory, ChannelHandlerContext ctx) { + this.sink = sink; + this.tmpStorage = ctx.alloc().heapBuffer(); + this.lz4Factory = lz4Factory; + this.ctx = ctx; + } + + @Override + public void writeULeb128(int value) { + ByteBufUtils.writeULeb128(value, tmpStorage); + } + + @Override + public void writeByte(int value) { + tmpStorage.writeByte(value); + } + + @Override + public void writeShortLE(int value) { + tmpStorage.writeShortLE(value); + } + + @Override + public void writeLongLE(long value) { + tmpStorage.writeLongLE(value); + } + + @Override + public void writeFloatLE(float value) { + tmpStorage.writeFloatLE(value); + } + + @Override + public void writeDoubleLE(double value) { + tmpStorage.writeDoubleLE(value); + } + + @Override + public void writeIntLE(int value) { + tmpStorage.writeIntLE(value); + } + + @Override + public void writeBytes(byte[] value) { + tmpStorage.writeBytes(value); + } + + @Override + public void writeBytes(byte[] value, int index, int length) { + tmpStorage.writeBytes(value, index, length); + } + + @Override + public void writeBoolean(boolean value) { + tmpStorage.writeBoolean(value); + } + + @Override + public void writeZero(int length) { + tmpStorage.writeZero(length); + } + + @Override + public void writePascalString(String str) { + ByteBufUtils.writePascalString(str, tmpStorage); + } + + @Override + public void ensureWritable(int size) { + tmpStorage.ensureWritable(size); + } + + @Override + public void finish() { + ByteBuf compressed = null; + try { + compressed = getCompressedBuffer(tmpStorage); + byte[] compressedBytes = compressed.array(); + long[] cityHash = ClickHouseCityHash.cityHash128(compressedBytes, 0, compressed.readableBytes()); + sink.writeLongLE(cityHash[0]); + sink.writeLongLE(cityHash[1]); + sink.writeBytes(compressed); + } finally { + tmpStorage.release(); + if (compressed != null) { + compressed.release(); + } + } + } + + private ByteBuf getCompressedBuffer(ByteBuf from) { + LZ4Compressor compressor = lz4Factory.fastCompressor(); + int uncompressedLen = from.readableBytes(); + int maxCompressedLen = compressor.maxCompressedLength(uncompressedLen); + ByteBuf tmp = ctx.alloc().heapBuffer(maxCompressedLen + HEADER_SIZE); + tmp.writeByte(ClickhouseConstants.COMPRESSION_METHOD_LZ4); + int compressedLen = compressor.compress(from.array(), 0, uncompressedLen, tmp.array(), HEADER_SIZE); + int compressedBlockLen = HEADER_SIZE + compressedLen; + tmp.writeIntLE(compressedBlockLen); + tmp.writeIntLE(uncompressedLen); + tmp.writerIndex(compressedBlockLen); + return tmp; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Lz4ClickhouseStreamDataSource.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Lz4ClickhouseStreamDataSource.java new file mode 100644 index 000000000..b88acc4dc --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/Lz4ClickhouseStreamDataSource.java @@ -0,0 +1,234 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import net.jpountz.lz4.LZ4Factory; +import net.jpountz.lz4.LZ4FastDecompressor; +import ru.yandex.clickhouse.util.ClickHouseCityHash; + +import java.nio.charset.Charset; +import java.util.Arrays; + +public class Lz4ClickhouseStreamDataSource implements ClickhouseStreamDataSource { + private static final Logger LOG = LoggerFactory.getLogger(Lz4ClickhouseStreamDataSource.class); + + //compression method byte + sizeWithHeader + decompressed size + public static final int CHECKSUMED_HEADER_LENGTH = 1 + 4 + 4; + //cityhash size + compression method byte + sizeWithHeader + decompressed size + public static final int HEADER_LENGTH = 16 + CHECKSUMED_HEADER_LENGTH; + + private final Charset charset; + private final LZ4Factory lz4Factory; + private final ByteBuf decompressedData; + private long[] serverCityHash; + private Long sizeWithHeader; + private Long uncompressedSize; + private ByteBuf arrayBb; + + public Lz4ClickhouseStreamDataSource(LZ4Factory lz4Factory, Charset charset, ByteBufAllocator alloc) { + this.lz4Factory = lz4Factory; + this.decompressedData = alloc.heapBuffer(); + this.charset = charset; + } + + @Override + public void moreData(ByteBuf buf, ByteBufAllocator alloc) { + if (serverCityHash == null) { + if (buf.readableBytes() >= HEADER_LENGTH) { + serverCityHash = new long[2]; + if (LOG.isDebugEnabled()) { + dumpHeader(buf); + LOG.debug(this.hashCode() + ": lz4 header dump: " + ByteBufUtil.hexDump(buf, buf.readerIndex(), HEADER_LENGTH) + + "; buf hash: " + buf.hashCode() + "; identityHash:" + System.identityHashCode(buf) + + "; readerIndex: " + buf.readerIndex() + "; writerIndex: " + buf.writerIndex() + "; readableBytes: " + buf.readableBytes()); + LOG.debug("full dump: " + ByteBufUtil.hexDump(buf)); + } + serverCityHash[0] = buf.readLongLE(); + serverCityHash[1] = buf.readLongLE(); + int checkSummedReaderIndex = buf.readerIndex(); + int compressionMethod = buf.readUnsignedByte(); + if (compressionMethod != ClickhouseConstants.COMPRESSION_METHOD_LZ4) { + decompressedData.release(); + String msg = String.format("unexpected compression method type 0x%X; expects 0x%X", + compressionMethod, ClickhouseConstants.COMPRESSION_METHOD_LZ4); + throw new IllegalStateException(msg); + } + sizeWithHeader = buf.readUnsignedIntLE(); + if (sizeWithHeader > Integer.MAX_VALUE) { + throw new IllegalStateException("block is too big: " + sizeWithHeader + "; limit " + Integer.MAX_VALUE); + } + long compressedAndSizeSize = sizeWithHeader - 1 - 4; + uncompressedSize = buf.readUnsignedIntLE(); + if (uncompressedSize > Integer.MAX_VALUE) { + throw new IllegalStateException("uncompressedSize is too big: " + uncompressedSize + "; limit " + Integer.MAX_VALUE); + } + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("compressed size: %d(0x%X), sizeWithHeader: %d(0x%X), uncompressed size: %d(0x%X)", + compressedAndSizeSize, compressedAndSizeSize, sizeWithHeader, sizeWithHeader, uncompressedSize, uncompressedSize)); + } + arrayBb = alloc.buffer(sizeWithHeader.intValue()); + buf.readerIndex(checkSummedReaderIndex); + buf.readBytes(arrayBb, CHECKSUMED_HEADER_LENGTH); + } + } + if (uncompressedSize == null) { + return; + } + + int compressedDataSize = sizeWithHeader.intValue() - CHECKSUMED_HEADER_LENGTH; + if (buf.readableBytes() < compressedDataSize) { + //NB: fragmented read + return; + } + //TODO: maybe skip arrayBb allocation if buf.hasArray() == true and not fragmented read^^^^ + buf.readBytes(arrayBb); + long[] oursCityHash = ClickHouseCityHash.cityHash128(arrayBb.array(), arrayBb.arrayOffset(), sizeWithHeader.intValue()); + //reposition at the beginning of the compressed data, need to skip compression method byte, sizeWithHeader and uncompressed size + arrayBb.readerIndex(CHECKSUMED_HEADER_LENGTH); + + if (!Arrays.equals(serverCityHash, oursCityHash)) { + LOG.error("cityhash mismatch"); + LOG.error("all available data: " + ByteBufUtil.hexDump(buf, 0, buf.readerIndex() + buf.readableBytes())); + LOG.error("data from reader index(" + buf.readerIndex() + "): " + ByteBufUtil.hexDump(buf)); + LOG.error("compressed block bytes w/header: " + ByteBufUtil.hexDump(arrayBb, arrayBb.readerIndex() - CHECKSUMED_HEADER_LENGTH, sizeWithHeader.intValue())); + LOG.error("readableBytes: " + arrayBb.readableBytes() + "; comprDataLen: " + compressedDataSize); + throw new IllegalStateException("CityHash mismatch; server's: " + + Arrays.toString(hex(serverCityHash)) + "; ours: " + + Arrays.toString(hex(oursCityHash))); + } + byte[] uncompressedBytes = new byte[uncompressedSize.intValue()]; + LZ4FastDecompressor decompressor = lz4Factory.fastDecompressor(); + //LOG.info("compressed bytes: " + ByteBufUtil.hexDump(arrayBb)); + decompressor.decompress(arrayBb.array(), arrayBb.arrayOffset() + arrayBb.readerIndex(), uncompressedBytes, 0, uncompressedBytes.length); + if (LOG.isDebugEnabled()) { + LOG.debug("decompressed " + uncompressedBytes.length + " bytes of data"); + } + //LOG.info("decompressed data: " + ByteBufUtil.hexDump(uncompressedBytes) + "; asStr: " + new String(uncompressedBytes, StandardCharsets.UTF_8)); + decompressedData.writeBytes(uncompressedBytes); + arrayBb.release(); + serverCityHash = null; + sizeWithHeader = null; + uncompressedSize = null; + } + + private void dumpHeader(ByteBuf buf) { + String h1 = ByteBufUtil.hexDump(buf, buf.readerIndex(), 8); + String h2 = ByteBufUtil.hexDump(buf, buf.readerIndex() + 8, 8); + String method = ByteBufUtil.hexDump(buf, buf.readerIndex() + 16, 1); + String sizeWithHeader = ByteBufUtil.hexDump(buf, buf.readerIndex() + 17, 4); + String uncompressedSize = ByteBufUtil.hexDump(buf, buf.readerIndex() + 21, 4); + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("header: [%s:%s]:%s:%s:%s", h1, h2, method, sizeWithHeader, uncompressedSize)); + } + } + + @Override + public int readerIndex() { + return decompressedData.readerIndex(); + } + + @Override + public int readableBytes() { + return decompressedData.readableBytes(); + } + + @Override + public void skipBytes(int length) { + decompressedData.skipBytes(length); + } + + @Override + public String readPascalString() { + return ByteBufUtils.readPascalString(decompressedData, charset); + } + + @Override + public Integer readULeb128() { + return ByteBufUtils.readULeb128(decompressedData); + } + + @Override + public boolean readBoolean() { + return decompressedData.readBoolean(); + } + + @Override + public int readIntLE() { + return decompressedData.readIntLE(); + } + + @Override + public ByteBuf readSlice(int nBytes) { + return decompressedData.readSlice(nBytes); + } + + @Override + public void readBytes(byte[] dst) { + decompressedData.readBytes(dst); + } + + @Override + public byte readByte() { + return decompressedData.readByte(); + } + + @Override + public long readLongLE() { + return decompressedData.readLongLE(); + } + + @Override + public short readShortLE() { + return decompressedData.readShortLE(); + } + + @Override + public float readFloatLE() { + return decompressedData.readFloatLE(); + } + + @Override + public double readDoubleLE() { + return decompressedData.readDoubleLE(); + } + + @Override + public String hexDump(int fromIndex, int len) { + return ByteBufUtil.hexDump(decompressedData, fromIndex, len); + } + + @Override + public String hexDump() { + return ByteBufUtil.hexDump(decompressedData); + } + + @Override + public void finish() { + decompressedData.release(); + } + + private static String[] hex(long[] src) { + String[] result = new String[src.length]; + for (int i = 0; i < src.length; ++i) { + result[i] = "0x" + Long.toHexString(src[i]); + } + return result; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/MultistringMessageReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/MultistringMessageReader.java new file mode 100644 index 000000000..9ffff81b2 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/MultistringMessageReader.java @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +public class MultistringMessageReader { + private final List strings; + private final Charset charset; + private Integer stringsExpected; + + public MultistringMessageReader(Charset charset) { + this.charset = charset; + strings = new ArrayList<>(); + } + + public List readFrom(ByteBuf in, ServerPacketType packetType) { + if (stringsExpected == null) { + stringsExpected = stringsInMessage(packetType); + } + String ln; + while (strings.size() < stringsExpected && (ln = ByteBufUtils.readPascalString(in, charset)) != null) { + strings.add(ln); + } + if (strings.size() == stringsExpected) { + return strings; + } + return null; + } + + private int stringsInMessage(ServerPacketType type) { + if (type == ServerPacketType.TABLE_COLUMNS) { + return 2; + } + return 0; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PacketForge.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PacketForge.java new file mode 100644 index 000000000..e9629d0c7 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PacketForge.java @@ -0,0 +1,131 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryRowDesc; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinarySocketConnection; +import io.vertx.clickhouseclient.binary.impl.RowOrientedBlock; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.Map; + +public class PacketForge { + private static final Logger LOG = LoggerFactory.getLogger(PacketForge.class); + private final ClickhouseBinarySocketConnection conn; + private final ChannelHandlerContext chctx; + + public PacketForge(ClickhouseBinarySocketConnection conn, ChannelHandlerContext chctx) { + this.conn = conn; + this.chctx = chctx; + } + + public void sendQuery(String query, ByteBuf buf) { + if (LOG.isDebugEnabled()) { + LOG.debug("running query: " + query); + } + ByteBufUtils.writeULeb128(ClientPacketTypes.QUERY, buf); + //query id + ByteBufUtils.writePascalString("", buf); + ClickhouseBinaryDatabaseMetadata meta = conn.getDatabaseMetaData(); + int serverRevision = meta.getRevision(); + if (serverRevision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_CLIENT_INFO) { + ClientInfo clInfo = new ClientInfo(meta); + clInfo.serializeTo(buf); + } + boolean settingsAsStrings = serverRevision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_SETTINGS_SERIALIZED_AS_STRINGS; + writeSettings(settings(), settingsAsStrings, true, buf); + if (serverRevision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_INTERSERVER_SECRET) { + ByteBufUtils.writePascalString("", buf); + } + ByteBufUtils.writeULeb128(QueryProcessingStage.COMPLETE, buf); + int compressionEnabled = conn.lz4Factory() == null ? Compression.DISABLED : Compression.ENABLED; + ByteBufUtils.writeULeb128(compressionEnabled, buf); + ByteBufUtils.writePascalString(query, buf); + } + + public void writeSettings(Map settings, boolean settingsAsStrings, boolean settingsAreImportant, ByteBuf buf) { + if (settingsAsStrings) { + for (Map.Entry entry : settings.entrySet()) { + if (!ClickhouseConstants.NON_QUERY_OPTIONS.contains(entry.getKey())) { + if (LOG.isDebugEnabled()) { + LOG.debug("writing query setting: " + entry); + } + ByteBufUtils.writePascalString(entry.getKey(), buf); + buf.writeBoolean(settingsAreImportant); + ByteBufUtils.writePascalString(entry.getValue(), buf); + } + } + } else { + //TODO: implement (required for old clickhouse versions) + throw new IllegalArgumentException("not implemented for settingsAsStrings=false"); + } + //end of settings + ByteBufUtils.writePascalString("", buf); + } + + public void sendExternalTables(ByteBuf buf, Collection blocks) { + ClickhouseBinaryDatabaseMetadata md = conn.getDatabaseMetaData(); + for (RowOrientedBlock block : blocks) { + //TODO implement external tables support + sendData(buf, block, null); + } + sendData(buf, new RowOrientedBlock(ClickhouseBinaryRowDesc.EMPTY, Collections.emptyList(), md), ""); + } + + public void sendData(ByteBuf buf, RowOrientedBlock block, String tableName) { + sendData(buf, block, tableName, 0, block.totalRows()); + } + + public void sendData(ByteBuf buf, RowOrientedBlock block, String tableName, int fromRow, int toRow) { + ByteBufUtils.writeULeb128(ClientPacketTypes.DATA, buf); + if (conn.getDatabaseMetaData().getRevision() >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES) { + ByteBufUtils.writePascalString(tableName, buf); + } + ClickhouseStreamDataSink sink = null; + try { + sink = dataSink(buf); + block.serializeAsBlock(sink, fromRow, toRow); + } finally { + if (sink != null) { + sink.finish(); + } + } + } + + private ClickhouseStreamDataSink dataSink(ByteBuf buf) { + return conn.lz4Factory() == null ? new RawClickhouseStreamDataSink(buf) : new Lz4ClickhouseStreamDataSink(buf, conn.lz4Factory(), chctx); + } + + protected Map settings() { + return conn.getDatabaseMetaData().getProperties(); + } + + public void sendColumns(RowOrientedBlock block, ByteBuf buf, Integer maxInsertBlockSize) { + int nRows = block.totalRows(); + int blockSize = maxInsertBlockSize == null ? nRows : maxInsertBlockSize; + int fromRow = 0; + while (fromRow < nRows) { + int toRow = Math.min(nRows, fromRow + blockSize); + sendData(buf, block, "", fromRow, toRow); + fromRow = toRow; + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PacketReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PacketReader.java new file mode 100644 index 000000000..78989609a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PacketReader.java @@ -0,0 +1,298 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryRowImpl; +import io.vertx.clickhouseclient.binary.impl.ClickhouseServerException; +import io.vertx.clickhouseclient.binary.impl.ColumnOrientedBlock; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.impl.RowDesc; +import net.jpountz.lz4.LZ4Factory; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.sql.JDBCType; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +public class PacketReader { + private static final Logger LOG = LoggerFactory.getLogger(PacketReader.class); + + private final ClickhouseBinaryDatabaseMetadata md; + private final String fullClientName; + private final Map properties; + private final LZ4Factory lz4Factory; + + private ClickhouseStreamDataSource ds; + private ServerPacketType packetType; + private DatabaseMetadataReader metadataReader; + private ClickhouseExceptionReader exceptionReader; + + private String tempTableInfo; + private ColumnOrientedBlockReader columnBlockReader; + + private BlockStreamProfileInfoReader blockStreamProfileReader; + private QueryProgressInfoReader queryProgressInfoReader; + private MultistringMessageReader multistringReader; + private List multistringMessage; + private PacketReader tableColumnsPacketReader; + + private boolean endOfStream; + + public PacketReader(ClickhouseBinaryDatabaseMetadata md, String fullClientName, Map properties, LZ4Factory lz4Factory) { + this.md = md; + this.fullClientName = fullClientName; + this.properties = properties; + this.lz4Factory = lz4Factory; + } + + public static Boolean hasException(ByteBuf in) { + int pos = in.readerIndex(); + Integer packetTypeCode = ByteBufUtils.readULeb128(in); + in.readerIndex(pos); + if (packetTypeCode == null) { + return null; + } else { + ServerPacketType pkt = ServerPacketType.fromCode(packetTypeCode); + return pkt == ServerPacketType.EXCEPTION; + } + } + + public Object receivePacket(ByteBufAllocator alloc, ByteBuf in) { + if (packetType == null) { + Integer packetTypeCode = ByteBufUtils.readULeb128(in); + if (packetTypeCode == null) { + return null; + } + try { + packetType = ServerPacketType.fromCode(packetTypeCode); + if (LOG.isDebugEnabled()) { + LOG.debug("packet type: " + packetType); + } + } catch (IllegalArgumentException ex) { + LOG.error("unknown packet type, dump: " + ByteBufUtil.hexDump(in)); + LOG.error("unknown packet type", ex); + throw ex; + } + } + + if (packetType == ServerPacketType.HELLO) { + return readServerHelloBlock(in); + } else if (packetType == ServerPacketType.DATA) { + return readDataBlock(alloc, in); + } else if (packetType == ServerPacketType.EXCEPTION) { + return readExceptionBlock(in); + } else if (packetType == ServerPacketType.PROGRESS) { + return readProgressBlock(in); + } else if (packetType == ServerPacketType.END_OF_STREAM) { + if (LOG.isDebugEnabled()) { + LOG.debug("decoded: END_OF_STREAM"); + } + packetType = null; + endOfStream = true; + } else if (packetType == ServerPacketType.PROFILE_INFO) { + //TODO: find a way to expose profile block to the calling app + return readProfileInfoBlock(in); + } else if (packetType == ServerPacketType.LOG) { + ColumnOrientedBlock block = readDataBlock(alloc, in, false); + if (block != null) { + traceServerLogs(block); + } + return null; + } else if (packetType == ServerPacketType.TABLE_COLUMNS) { + return receiveTableColumns(alloc, in, packetType); + } else { + throw new IllegalStateException("unknown packet type: " + packetType); + } + return null; + } + + private void traceServerLogs(ColumnOrientedBlock block) { + //TODO: find a way to expose logs to the calling app + if (LOG.isDebugEnabled()) { + LOG.debug("server log: [" + block.numColumns() + "; " + block.numRows() + "]"); + List rows = block.rows(); + LOG.debug("rows: "); + StringBuilder bldr = new StringBuilder(); + for (ClickhouseBinaryRowImpl row : rows) { + bldr.append(rowAsString(row, block.rowDesc())).append("\n"); + } + LOG.debug(bldr); + } + } + + private String rowAsString(Row row, RowDesc rowDesc) { + String[] vals = new String[row.size()]; + for (int i = 0; i < vals.length; ++i) { + Object value = row.getValue(i); + if (rowDesc.columnDescriptor().get(i).jdbcType() == JDBCType.VARCHAR) { + value = "'" + value + "'"; + } + vals[i] = Objects.toString(value); + } + return String.join(", ", vals); + } + + private TableColumns receiveTableColumns(ByteBufAllocator alloc, ByteBuf in, ServerPacketType type) { + if (multistringMessage == null) { + if (multistringReader == null) { + multistringReader = new MultistringMessageReader(md.getStringCharset()); + } + multistringMessage = multistringReader.readFrom(in, type); + } + if (multistringMessage == null) { + return null; + } + if (tableColumnsPacketReader == null) { + tableColumnsPacketReader = new PacketReader(md, fullClientName, properties, lz4Factory); + } + ColumnOrientedBlock block = tableColumnsPacketReader.readDataBlock(alloc, in, true); + TableColumns ret = null; + if (block != null) { + ret = new TableColumns(multistringMessage, block); + if (LOG.isDebugEnabled()) { + LOG.debug("decoded: MultistringMessage: " + multistringMessage + "; block: [" + block.numColumns() + "; " + block.numRows() + "]"); + } + multistringReader = null; + packetType = null; + tableColumnsPacketReader = null; + multistringMessage = null; + } + return ret; + } + + private ClickhouseBinaryDatabaseMetadata readServerHelloBlock(ByteBuf in) { + if (metadataReader == null) { + metadataReader = new DatabaseMetadataReader(fullClientName, properties); + } + ClickhouseBinaryDatabaseMetadata md = metadataReader.readFrom(in); + if (md != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("decoded: HELLO/ClickhouseBinaryDatabaseMetadata"); + } + metadataReader = null; + packetType = null; + } + return md; + } + + private BlockStreamProfileInfo readProfileInfoBlock(ByteBuf in) { + if (blockStreamProfileReader == null) { + blockStreamProfileReader = new BlockStreamProfileInfoReader(); + } + int startIdx = in.readerIndex(); + BlockStreamProfileInfo profileInfo = blockStreamProfileReader.readFrom(in); + if (profileInfo != null) { + if (LOG.isDebugEnabled()) { + int endIndex = in.readerIndex(); + LOG.debug("decoded: PROFILE_INFO/BlockStreamProfileInfo " + profileInfo + ": " + ByteBufUtil.hexDump(in, startIdx, endIndex - startIdx)); + } + blockStreamProfileReader = null; + packetType = null; + } + return profileInfo; + } + + private QueryProgressInfo readProgressBlock(ByteBuf in) { + if (queryProgressInfoReader == null) { + queryProgressInfoReader = new QueryProgressInfoReader(md); + } + QueryProgressInfo queryProgressInfo = queryProgressInfoReader.readFrom(in); + if (queryProgressInfo != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("decoded: PROGRESS/QueryProgressInfo: " + queryProgressInfo); + } + queryProgressInfoReader = null; + packetType = null; + } + return queryProgressInfo; + } + + private ClickhouseServerException readExceptionBlock(ByteBuf in) { + if (exceptionReader == null) { + //metadata may be null for a login exception + Charset charset = md == null ? ClickhouseBinaryDatabaseMetadata.charset(properties) : md.getStringCharset(); + exceptionReader = new ClickhouseExceptionReader(charset); + } + ClickhouseServerException exc = exceptionReader.readFrom(in); + if (exc != null) { + if (LOG.isDebugEnabled()) { + LOG.debug("decoded: EXCEPTION/ClickhouseServerException"); + } + exceptionReader = null; + packetType = null; + } + return exc; + } + + private ColumnOrientedBlock readDataBlock(ByteBufAllocator alloc, ByteBuf in) { + return readDataBlock(alloc, in, true); + } + + private ColumnOrientedBlock readDataBlock(ByteBufAllocator alloc, ByteBuf in, boolean preferCompressionIfEnabled) { + if (md.getRevision() >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_TEMPORARY_TABLES) { + if (tempTableInfo == null) { + tempTableInfo = ByteBufUtils.readPascalString(in, md.getStringCharset()); + if (tempTableInfo == null) { + return null; + } + } + } + if (columnBlockReader == null) { + ds = dataSource(alloc, preferCompressionIfEnabled); + columnBlockReader = new ColumnOrientedBlockReader(md); + } + ds.moreData(in, alloc); + ColumnOrientedBlock block = columnBlockReader.readFrom(ds); + if (block != null) { + List colNames = new ArrayList<>(block.getColumnsWithTypes().keySet()); + if (LOG.isDebugEnabled()) { + LOG.debug("decoded: DATA/ColumnOrientedBlock [" + block.numColumns() + "; " + block.numRows() + "][" + colNames + "]"); + } + columnBlockReader = null; + packetType = null; + ds.finish(); + ds = null; + tempTableInfo = null; + } + return block; + } + + private ClickhouseStreamDataSource dataSource(ByteBufAllocator alloc, boolean preferCompressionIfEnabled) { + if (lz4Factory == null || !preferCompressionIfEnabled) { + LOG.debug("dataSource: raw"); + return new RawClickhouseStreamDataSource(md.getStringCharset()); + } else { + LOG.debug("dataSource: lz4"); + return new Lz4ClickhouseStreamDataSource(lz4Factory, md.getStringCharset(), alloc); + } + } + + public ServerPacketType packetType() { + return packetType; + } + + public boolean isEndOfStream() { + return endOfStream; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PrepareStatementCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PrepareStatementCodec.java new file mode 100644 index 000000000..e2646359d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/PrepareStatementCodec.java @@ -0,0 +1,86 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryRowDesc; +import io.vertx.sqlclient.desc.ColumnDescriptor; +import io.vertx.sqlclient.impl.PreparedStatement; +import io.vertx.sqlclient.impl.command.CommandResponse; +import io.vertx.sqlclient.impl.command.PrepareStatementCommand; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class PrepareStatementCodec extends ClickhouseBinaryCommandCodec { + private final QueryInfo queryInfo; + private final UUID psId; + private PacketReader packetReader; + + protected PrepareStatementCodec(PrepareStatementCommand cmd, QueryInfo queryInfo) { + super(cmd); + this.queryInfo = queryInfo; + this.psId = UUID.randomUUID(); + } + + @Override + void encode(ClickhouseBinaryEncoder encoder) { + super.encode(encoder); + String sql = cmd.sql(); + boolean realInsertBatch = queryInfo.isInsert() && queryInfo.hasValues(); + if (realInsertBatch) { + encoder.getConn().lockPsOrThrow(psId); + String truncatedSql = queryInfo.queryEndingWithValues(); + ByteBuf buf = allocateBuffer(); + try { + PacketForge forge = new PacketForge(encoder.getConn(), encoder.chctx()); + forge.sendQuery(truncatedSql, buf); + forge.sendExternalTables(buf, Collections.emptyList()); + encoder.chctx().writeAndFlush(buf, encoder.chctx().voidPromise()); + } catch (Throwable t) { + buf.release(); + throw t; + } + } else { + completionHandler.handle(CommandResponse.success(new ClickhouseBinaryPreparedStatement(sql, new ClickhouseBinaryParamDesc(Collections.emptyList()), + ClickhouseBinaryRowDesc.EMPTY, queryInfo, false, psId))); + } + } + + @Override + void decode(ChannelHandlerContext ctx, ByteBuf in) { + if (packetReader == null) { + packetReader = new PacketReader(encoder.getConn().getDatabaseMetaData(), null, null, encoder.getConn().lz4Factory()); + } + Object packet = packetReader.receivePacket(ctx.alloc(), in); + if (packet != null) { + packetReader = null; + if (packet.getClass() == TableColumns.class) { + TableColumns columns = (TableColumns)packet; + Map data = columns.columnDefinition().getColumnsWithTypes(); + + ClickhouseBinaryColumnDescriptor[] columnTypes = data.values().toArray(ClickhouseBinaryRowDesc.EMPTY_DESCRIPTORS); + ClickhouseBinaryRowDesc rowDesc = new ClickhouseBinaryRowDesc(columnTypes); + completionHandler.handle(CommandResponse.success(new ClickhouseBinaryPreparedStatement(cmd.sql(), + new ClickhouseBinaryParamDesc(Collections.emptyList()), rowDesc, queryInfo, true, psId))); + } else if (packet instanceof Throwable) { + cmd.fail((Throwable) packet); + } + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryInfo.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryInfo.java new file mode 100644 index 000000000..5338d4e48 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryInfo.java @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import java.util.Map; + +public class QueryInfo { + public static final int VALUES_LENGTH = "values".length(); + + private final String typeKeyword; + private final Integer typeKeywordPos; + private final boolean isInsert; + private final String queryEndingWithValues; + + QueryInfo(String sql, String typeKeyword, Integer typeKeywordPos) { + this.typeKeyword = typeKeyword; + this.typeKeywordPos = typeKeywordPos; + this.isInsert = "insert".equalsIgnoreCase(typeKeyword); + this.queryEndingWithValues = isInsert ? findValuesAndTruncate(sql, typeKeywordPos) : null; + } + + public String typeKeyword() { + return typeKeyword; + } + + public Integer typeKeywordPos() { + return typeKeywordPos; + } + + public boolean isInsert() { + return isInsert; + } + + public boolean hasValues() { + return queryEndingWithValues != null; + } + + public String queryEndingWithValues() { + return queryEndingWithValues; + } + + private String findValuesAndTruncate(String sql, int typeKeywordPos) { + String loCaseSql = sql.toLowerCase(); + boolean endsWithVals = loCaseSql.endsWith("values"); + if (endsWithVals) { + return sql; + } else { + //TODO: make sure there are placeholders only, maybe count placeholders amount + int valuesIndex = QueryParsers.valuesPosForLoCaseSql(loCaseSql, typeKeywordPos); + if (valuesIndex != -1) { + return sql.substring(0, valuesIndex + VALUES_LENGTH); + } else { + return null; + } + } + } + + public static QueryInfo parse(String query) { + Map.Entry qInfo = QueryParsers.findKeyWord(query, QueryParsers.SELECT_AND_MUTATE_KEYWORDS); + return new QueryInfo(query, qInfo == null ? null : qInfo.getKey(), qInfo == null ? null : qInfo.getValue()); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryParsers.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryParsers.java new file mode 100644 index 000000000..ba7da9ff9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryParsers.java @@ -0,0 +1,199 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.vertx.sqlclient.Tuple; + +import java.time.temporal.Temporal; +import java.util.*; + +//TODO: maybe switch to antlr4 or JavaCC + .jj file (see ClickHouseSqlParser.jj in regular ClickHouse jdbc driver) +public class QueryParsers { + private static final String INSERT_KEYWORD = "INSERT"; + private static final String UPDATE_KEYWORD = "UPDATE"; + + public static final Set SELECT_KEYWORDS = + Collections.unmodifiableSet(new HashSet<>(Arrays.asList("SELECT", "WITH", "SHOW", "DESC", "EXISTS", "EXPLAIN"))); + public static final Set SELECT_AND_MUTATE_KEYWORDS = + Collections.unmodifiableSet(new HashSet<>(Arrays.asList("SELECT", "WITH", "SHOW", "DESC", "EXISTS", "EXPLAIN", + INSERT_KEYWORD, UPDATE_KEYWORD))); + + + public static String insertParamValuesIntoQuery(String parametrizedSql, Tuple paramsList) { + int prevIdx = 0; + int newIdx; + StringBuilder bldr = new StringBuilder(); + Set usedArgs = new HashSet<>(); + while(prevIdx < parametrizedSql.length() && (newIdx = parametrizedSql.indexOf('$', prevIdx)) != -1) { + if (newIdx == 0 || parametrizedSql.charAt(newIdx - 1) != '\\') { + int paramIdxStartPos = newIdx + 1; + int paramIdxEndPos = paramIdxStartPos; + while (paramIdxEndPos < parametrizedSql.length() && Character.isDigit(parametrizedSql.charAt(paramIdxEndPos))) { + ++paramIdxEndPos; + } + if (paramIdxStartPos == paramIdxEndPos) { + throw new IllegalArgumentException("$ without digit at pos " + paramIdxStartPos + " in query " + parametrizedSql); + } + int paramIndex = Integer.parseInt(parametrizedSql.substring(paramIdxStartPos, paramIdxEndPos)) - 1; + if (paramsList == null || paramIndex >= paramsList.size()) { + throw new IllegalArgumentException("paramList is null or too small(" + (paramsList == null ? null : paramsList.size()) + + ") for arg with index " + paramIndex); + } + Object paramValue = paramsList.getValue(paramIndex); + bldr.append(parametrizedSql, prevIdx, newIdx); + Class paramClass = paramValue == null ? null : paramValue.getClass(); + if (paramClass != null) { + if (CharSequence.class.isAssignableFrom(paramClass) || paramClass == Character.class || Temporal.class.isAssignableFrom(paramClass)) { + bldr.append('\'').append(paramValue).append('\''); + } else if (paramClass == Double.class) { + //DB parser gets mad at 4.9e-322 or smaller. Using cast to cure + bldr.append(String.format("CAST('%s', 'Float64')", paramValue.toString())); + } else if (paramClass == Float.class) { + bldr.append(String.format("CAST('%s', 'Float32')", paramValue.toString())); + } else { + bldr.append(paramValue); + } + } else { + bldr.append(paramValue); + } + usedArgs.add(paramIndex); + newIdx = paramIdxEndPos; + } + prevIdx = newIdx; + } + if (usedArgs.size() != paramsList.size()) { + String msg = String.format("The number of parameters to execute should be consistent with the expected number of parameters = [%d] but the actual number is [%d].", + usedArgs.size(), paramsList.size()); + throw new IllegalArgumentException(msg); + } + bldr.append(parametrizedSql, prevIdx, parametrizedSql.length()); + return bldr.toString(); + } + + public static boolean isSelect(String sql) { + Map.Entry tmp = findKeyWord(sql, 0, SELECT_KEYWORDS); + return tmp != null; + } + + public static Map.Entry findKeyWord(String sql, Collection keywords) { + return findKeyWord(sql, 0, keywords); + } + + public static Map.Entry findKeyWord(String sql, int startPos, Collection keywords) { + Character requiredChar = null; + //special case to find special chars, e.g. argument index $ + if (keywords.size() == 1) { + String str = keywords.iterator().next(); + if (str.length() == 1) { + requiredChar = str.charAt(0); + } + } + for (int i = startPos; i < sql.length(); i++) { + char ch = sql.charAt(i); + String nextTwo = sql.substring(i, Math.min(i + 2, sql.length())); + if ("--".equals(nextTwo)) { + i = Math.max(i, sql.indexOf("\n", i)); + } else if ("/*".equals(nextTwo)) { + i = Math.max(i, sql.indexOf("*/", i)); + } else if (ch == '\'' && (i == 0 || sql.charAt(i - 1) != '\\')) { + while (i < sql.length() && !(sql.charAt(i) == '\'' && (i == 0 || sql.charAt(i - 1) != '\\'))) { + ++i; + } + } else { + if (requiredChar == null) { + if (Character.isLetter(ch)) { + String trimmed = sql.substring(i, Math.min(sql.length(), Math.max(i, sql.indexOf(" ", i)))); + for (String keyword : keywords) { + if (trimmed.regionMatches(true, 0, keyword, 0, keyword.length())) { + return new AbstractMap.SimpleEntry<>(keyword, i); + } + } + } + } else { + if (requiredChar == ch) { + return new AbstractMap.SimpleEntry<>(keywords.iterator().next(), i); + } + } + } + } + return null; + } + + public static Map parseEnumValues(String nativeType) { + final boolean isByte = nativeType.startsWith("Enum8("); + int openBracketPos = nativeType.indexOf('('); + Map result = new LinkedHashMap<>(); + int lastQuotePos = -1; + boolean gotEq = false; + String enumElementName = null; + int startEnumValPos = -1; + int signum = 1; + for (int i = openBracketPos; i < nativeType.length(); ++i) { + char ch = nativeType.charAt(i); + if (ch == '\'') { + if (lastQuotePos == -1) { + lastQuotePos = i; + } else { + enumElementName = nativeType.substring(lastQuotePos + 1, i); + lastQuotePos = -1; + } + } else if (ch == '=') { + gotEq = true; + } else if (gotEq) { + if (ch == '-') { + signum = -1; + } if (Character.isDigit(ch)) { + if (startEnumValPos == -1) { + startEnumValPos = i; + } else if (!Character.isDigit(nativeType.charAt(i + 1))) { + int enumValue = Integer.parseInt(nativeType.substring(startEnumValPos, i + 1)) * signum; + Number key = byteOrShort(enumValue, isByte); + result.put(key, enumElementName); + signum = 1; + startEnumValPos = -1; + enumElementName = null; + gotEq = false; + } + } else if (startEnumValPos != -1) { + int enumValue = Integer.parseInt(nativeType.substring(startEnumValPos, i)) * signum; + Number key = byteOrShort(enumValue, isByte); + result.put(key, enumElementName); + signum = 1; + startEnumValPos = -1; + enumElementName = null; + gotEq = false; + } + } + } + return result; + } + + private static Number byteOrShort(int number, boolean isByte) { + if (isByte) { + return (byte) number; + } + return (short) number; + } + + static int valuesPosForLoCaseSql(String sqlLoCase, int fromPos) { + if (sqlLoCase.endsWith("values")) { + return sqlLoCase.length() - "values".length(); + } + Map.Entry pos = findKeyWord(sqlLoCase, fromPos, Collections.singleton("$")); + if (pos == null) { + return -1; + } + return sqlLoCase.lastIndexOf("values", pos.getValue()); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProcessingStage.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProcessingStage.java new file mode 100644 index 000000000..7f599aa37 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProcessingStage.java @@ -0,0 +1,20 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +public class QueryProcessingStage { + public static final int FETCH_COLUMNS = 0; + public static final int WITH_MERGEABLE_STATE = 1; + public static final int COMPLETE = 2; +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProgressInfo.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProgressInfo.java new file mode 100644 index 000000000..bf4c0fb57 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProgressInfo.java @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +public class QueryProgressInfo { + private final int rows; + private final int bytes; + private final int totalRows; + private final int writtenRows; + private final int writtenBytes; + + public QueryProgressInfo(int rows, int bytes, int totalRows, int writtenRows, int writtenBytes) { + this.rows = rows; + this.bytes = bytes; + this.totalRows = totalRows; + + this.writtenRows = writtenRows; + this.writtenBytes = writtenBytes; + } + + public int getRows() { + return rows; + } + + public int getBytes() { + return bytes; + } + + public int getTotalRows() { + return totalRows; + } + + public int getWrittenRows() { + return writtenRows; + } + + public int getWrittenBytes() { + return writtenBytes; + } + + @Override + public String toString() { + return "QueryProgressInfo{" + + "rows=" + rows + + ", bytes=" + bytes + + ", totalRows=" + totalRows + + ", writtenRows=" + writtenRows + + ", writtenBytes=" + writtenBytes + + '}'; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProgressInfoReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProgressInfoReader.java new file mode 100644 index 000000000..5bde877e7 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/QueryProgressInfoReader.java @@ -0,0 +1,84 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; + +public class QueryProgressInfoReader { + private static final Logger LOG = LoggerFactory.getLogger(QueryProgressInfoReader.class); + + private final int serverRevision; + + private Integer rows; + private Integer bytes; + private Integer totalRows; + private Integer writtenRows; + private Integer writtenBytes; + + public QueryProgressInfoReader(ClickhouseBinaryDatabaseMetadata md) { + this.serverRevision = md.getRevision(); + } + + public QueryProgressInfo readFrom(ByteBuf in) { + int idxStart = in.readerIndex(); + if (rows == null) { + rows = ByteBufUtils.readULeb128(in); + if (rows == null) { + return null; + } + } + + if (bytes == null) { + bytes = ByteBufUtils.readULeb128(in); + if (bytes == null) { + return null; + } + } + + if (serverRevision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_TOTAL_ROWS_IN_PROGRESS) { + if (totalRows == null) { + totalRows = ByteBufUtils.readULeb128(in); + } + if (totalRows == null) { + return null; + } + } + + if (serverRevision >= ClickhouseConstants.DBMS_MIN_REVISION_WITH_CLIENT_WRITE_INFO) { + if (writtenRows == null) { + writtenRows = ByteBufUtils.readULeb128(in); + } + if (writtenRows == null) { + return null; + } + if (writtenBytes == null) { + writtenBytes = ByteBufUtils.readULeb128(in); + if (writtenBytes == null) { + return null; + } + } + } + int idxEnd = in.readerIndex(); + String bufferAsStringConsumed = ByteBufUtil.hexDump(in, idxStart, idxEnd - idxStart); + if (LOG.isDebugEnabled()) { + LOG.debug("bufferAsStringConsumed: " + bufferAsStringConsumed); + } + return new QueryProgressInfo(rows, bytes, totalRows, writtenRows, writtenBytes); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RawClickhouseStreamDataSink.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RawClickhouseStreamDataSink.java new file mode 100644 index 000000000..2a42ab570 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RawClickhouseStreamDataSink.java @@ -0,0 +1,89 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; + +public class RawClickhouseStreamDataSink implements ClickhouseStreamDataSink { + private final ByteBuf sink; + + public RawClickhouseStreamDataSink(ByteBuf sink) { + this.sink = sink; + } + + @Override + public void writeULeb128(int value) { + ByteBufUtils.writeULeb128(value, sink); + } + + @Override + public void writeByte(int value) { + sink.writeByte(value); + } + + @Override + public void writeShortLE(int value) { + sink.writeShortLE(value); + } + + @Override + public void writeLongLE(long value) { + sink.writeLongLE(value); + } + + @Override + public void writeFloatLE(float value) { + sink.writeFloatLE(value); + } + + @Override + public void writeDoubleLE(double value) { + sink.writeDoubleLE(value); + } + + @Override + public void writeIntLE(int value) { + sink.writeIntLE(value); + } + + @Override + public void writeBytes(byte[] value) { + sink.writeBytes(value); + } + + @Override + public void writeBytes(byte[] value, int index, int length) { + sink.writeBytes(value, index, length); + } + + @Override + public void writeBoolean(boolean value) { + sink.writeBoolean(value); + } + + @Override + public void writeZero(int length) { + sink.writeZero(length); + } + + @Override + public void writePascalString(String str) { + ByteBufUtils.writePascalString(str, sink); + } + + @Override + public void ensureWritable(int size) { + sink.ensureWritable(size); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RawClickhouseStreamDataSource.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RawClickhouseStreamDataSource.java new file mode 100644 index 000000000..197473aeb --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RawClickhouseStreamDataSource.java @@ -0,0 +1,122 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufUtil; + +import java.nio.charset.Charset; + +public class RawClickhouseStreamDataSource implements ClickhouseStreamDataSource { + private final Charset charset; + private ByteBuf source; + + public RawClickhouseStreamDataSource(Charset charset) { + this.charset = charset; + } + + @Override + public void moreData(ByteBuf source, ByteBufAllocator alloc) { + this.source = source; + } + + @Override + public int readerIndex() { + return source.readerIndex(); + } + + @Override + public int readableBytes() { + return source.readableBytes(); + } + + @Override + public void skipBytes(int length) { + source.skipBytes(length); + } + + @Override + public String readPascalString() { + return ByteBufUtils.readPascalString(source, charset); + } + + @Override + public Integer readULeb128() { + return ByteBufUtils.readULeb128(source); + } + + @Override + public boolean readBoolean() { + return source.readBoolean(); + } + + @Override + public int readIntLE() { + return source.readIntLE(); + } + + @Override + public ByteBuf readSlice(int nBytes) { + return source.readSlice(nBytes); + } + + @Override + public void readBytes(byte[] dst) { + source.readBytes(dst); + } + + @Override + public byte readByte() { + return source.readByte(); + } + + @Override + public long readLongLE() { + return source.readLongLE(); + } + + @Override + public short readShortLE() { + return source.readShortLE(); + } + + @Override + public float readFloatLE() { + return source.readFloatLE(); + } + + @Override + public double readDoubleLE() { + return source.readDoubleLE(); + } + + @Override + public void finish() { + } + + @Override + public String hexDump() { + return source != null + ? ByteBufUtil.hexDump(source) + : null; + } + + @Override + public String hexDump(int fromIndex, int len) { + return source != null + ? ByteBufUtil.hexDump(source, fromIndex, len) + : null; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RowResultDecoder.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RowResultDecoder.java new file mode 100644 index 000000000..0ace9003a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/RowResultDecoder.java @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryRowImpl; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryRowDesc; +import io.vertx.clickhouseclient.binary.impl.ColumnOrientedBlock; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.impl.RowDecoder; + +import java.util.stream.Collector; + +class RowResultDecoder extends RowDecoder { + private static final Logger LOG = LoggerFactory.getLogger(RowResultDecoder.class); + + private final ClickhouseBinaryRowDesc rowDesc; + private final ClickhouseBinaryDatabaseMetadata md; + private ColumnOrientedBlock block; + private int rowNo; + + protected RowResultDecoder(Collector collector, ClickhouseBinaryRowDesc rowDesc, ClickhouseBinaryDatabaseMetadata md) { + super(collector); + this.rowDesc = rowDesc; + this.md = md; + } + + @Override + protected Row decodeRow(int len, ByteBuf in) { + ClickhouseBinaryRowImpl row = block.row(rowNo); + ++rowNo; + return row; + } + + public void generateRows(ColumnOrientedBlock block) { + this.block = block; + this.rowNo = 0; + for (int i = 0; i < block.numRows(); ++i) { + this.handleRow(-1, null); + } + this.block = null; + this.rowNo = 0; + } + + public ClickhouseBinaryRowDesc getRowDesc() { + return rowDesc; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ServerPacketType.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ServerPacketType.java new file mode 100644 index 000000000..89a2307b2 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/ServerPacketType.java @@ -0,0 +1,87 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import java.util.HashMap; +import java.util.Map; + +public enum ServerPacketType { + //Name, version, revision. + HELLO(0), + + //A block of data (compressed or not). + DATA(1), + + //The exception during query execution. + EXCEPTION(2), + + //Query execution progress: rows read, bytes read. + PROGRESS( 3), + + //Ping response + PONG(4), + + //All packets were transmitted + END_OF_STREAM(5), + + //Packet with profiling info. + PROFILE_INFO(6), + + //A block with totals (compressed or not). + TOTALS(7), + + //A block with minimums and maximums (compressed or not). + EXTREMES(8), + + //A response to TablesStatus request. + TABLES_STATUS_RESPONSE(9), + + //System logs of the query execution + LOG(10), + + //Columns' description for default values calculation + TABLE_COLUMNS(11); + + private static final Map CODE_INDEX = buildCodeIndex(); + + private final int code; + ServerPacketType(int code) { + this.code = code; + } + + public int code() { + return code; + } + + @Override + public String toString() { + return this.name() + "(" + this.code + ")"; + } + + public static ServerPacketType fromCode(int code) { + ServerPacketType ret = CODE_INDEX.get(code); + if (ret == null) { + throw new IllegalArgumentException("unknown code: " + code + "(0x" + Integer.toHexString(code) + ")"); + } + return ret; + } + + private static Map buildCodeIndex() { + Map ret = new HashMap<>(); + for (ServerPacketType pType : ServerPacketType.values()) { + ret.put(pType.code(), pType); + } + return ret; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/SimpleQueryCommandCodec.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/SimpleQueryCommandCodec.java new file mode 100644 index 000000000..ce3d8bda4 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/SimpleQueryCommandCodec.java @@ -0,0 +1,165 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryRowDesc; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinarySocketConnection; +import io.vertx.clickhouseclient.binary.impl.ColumnOrientedBlock; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.impl.command.CommandResponse; +import io.vertx.sqlclient.impl.command.QueryCommandBase; + +import java.util.Collections; +import java.util.Map; + +public class SimpleQueryCommandCodec extends ClickhouseBinaryQueryCommandBaseCodec> { + private static final Logger LOG = LoggerFactory.getLogger(SimpleQueryCommandCodec.class); + private final boolean commandRequiresUpdatesDelivery; + protected final QueryInfo queryInfo; + protected final int batchSize; + + private RowResultDecoder rowResultDecoder; + private PacketReader packetReader; + private int dataPacketNo; + protected final ClickhouseBinarySocketConnection conn; + + protected SimpleQueryCommandCodec(QueryCommandBase cmd, ClickhouseBinarySocketConnection conn) { + this(null, 0, cmd, conn, false); + } + protected SimpleQueryCommandCodec(QueryInfo queryInfo, int batchSize, QueryCommandBase cmd, ClickhouseBinarySocketConnection conn, boolean requireUpdatesDelivery) { + super(cmd); + this.queryInfo = queryInfo; + this.batchSize = batchSize; + this.conn = conn; + this.commandRequiresUpdatesDelivery = requireUpdatesDelivery; + } + + @Override + void encode(ClickhouseBinaryEncoder encoder) { + checkIfBusy(); + super.encode(encoder); + if (!isSuspended()) { + ByteBuf buf = allocateBuffer(); + try { + PacketForge forge = new PacketForge(conn, encoder.chctx()); + forge.sendQuery(sql(), buf); + forge.sendExternalTables(buf, Collections.emptyList()); + encoder.chctx().writeAndFlush(buf, encoder.chctx().voidPromise()); + } catch (Throwable t) { + buf.release(); + throw t; + } + } + } + + protected String sql() { + return cmd.sql(); + } + + protected Map settings() { + return conn.getDatabaseMetaData().getProperties(); + } + + protected boolean isSuspended() { + return false; + } + + protected void checkIfBusy() { + conn.throwExceptionIfCursorIsBusy(null); + } + + @Override + void decode(ChannelHandlerContext ctx, ByteBuf in) { + if (LOG.isDebugEnabled()) { + LOG.debug("decode, readable bytes: " + in.readableBytes()); + } + if (packetReader == null) { + packetReader = new PacketReader(encoder.getConn().getDatabaseMetaData(), null, null, encoder.getConn().lz4Factory()); + } + Object packet = packetReader.receivePacket(ctx.alloc(), in); + if (packet != null) { + if (packet.getClass() == ColumnOrientedBlock.class) { + ColumnOrientedBlock block = (ColumnOrientedBlock)packet; + if (LOG.isDebugEnabled()) { + LOG.debug("decoded packet " + dataPacketNo + ": " + block + " row count " + block.numRows()); + } + if (dataPacketNo == 0) { + ClickhouseBinaryRowDesc rowDesc = block.rowDesc(); + rowResultDecoder = new RowResultDecoder<>(cmd.collector(), rowDesc, conn.getDatabaseMetaData()); + } + packetReader = null; + rowResultDecoder.generateRows(block); + if (commandRequiresUpdatesDelivery && block.numRows() > 0) { + notifyOperationUpdate(true, null); + } + ++dataPacketNo; + } else { + if (LOG.isDebugEnabled()) { + LOG.error("non-data packet type: " + packet.getClass()); + } + if (packet instanceof Throwable) { + Throwable t = (Throwable) packet; + LOG.debug("unknown packet type or server exception", t); + notifyOperationUpdate(false, t); + } + } + } else if (packetReader.isEndOfStream()) { + notifyOperationUpdate(false, null); + packetReader = null; + } + } + + private void notifyOperationUpdate(boolean hasMoreResults, Throwable t) { + notifyOperationUpdate(0, hasMoreResults, t); + } + + private void notifyOperationUpdate(int updateCount, boolean hasMoreResults, Throwable t) { + Throwable failure = null; + if (rowResultDecoder != null) { + failure = rowResultDecoder.complete(); + T result = rowResultDecoder.result(); + int size = rowResultDecoder.size(); + rowResultDecoder.reset(); + if (LOG.isDebugEnabled()) { + LOG.debug("notifying operation update; has more result = " + hasMoreResults + "; size: " + size); + } + cmd.resultHandler().handleResult(updateCount, size, rowResultDecoder.getRowDesc(), result, failure); + } else { + if (queryInfo != null && queryInfo.isInsert()) { + rowResultDecoder = new RowResultDecoder<>(cmd.collector(), ClickhouseBinaryRowDesc.EMPTY, conn.getDatabaseMetaData()); + failure = rowResultDecoder.complete(); + cmd.resultHandler().handleResult(batchSize, 0, ClickhouseBinaryRowDesc.EMPTY, rowResultDecoder.result(), failure); + } + } + if (t != null) { + if (failure == null) { + failure = t; + } else { + failure = new RuntimeException(failure); + failure.addSuppressed(t); + } + } + + CommandResponse response; + if (failure == null) { + response = CommandResponse.success(hasMoreResults); + } else { + response = CommandResponse.failure(failure); + } + completionHandler.handle(response); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/TableColumns.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/TableColumns.java new file mode 100644 index 000000000..d4a368919 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/TableColumns.java @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec; + +import io.vertx.clickhouseclient.binary.impl.ColumnOrientedBlock; + +import java.util.List; + +public class TableColumns { + private final List msg; + private final ColumnOrientedBlock columnDefinition; + + public TableColumns(List msg, ColumnOrientedBlock columnDefinition) { + this.msg = msg; + this.columnDefinition = columnDefinition; + } + + public List msg() { + return msg; + } + + public ColumnOrientedBlock columnDefinition() { + return columnDefinition; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumn.java new file mode 100644 index 000000000..f8a0f6944 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumn.java @@ -0,0 +1,49 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class ArrayColumn extends ClickhouseColumn { + private final ClickhouseBinaryDatabaseMetadata md; + + public ArrayColumn(ClickhouseBinaryColumnDescriptor descriptor, ClickhouseBinaryDatabaseMetadata md) { + super(descriptor); + this.md = md; + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new ArrayColumnReader(nRows, descriptor, md); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new ArrayColumnWriter(data, descriptor, md, columnIndex); + } + + @Override + public Object nullValue() { + throw new IllegalArgumentException("arrays are not nullable"); + } + + @Override + public Object[] emptyArray() { + throw new IllegalArgumentException("not implemented"); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumnReader.java new file mode 100644 index 000000000..adbde9371 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumnReader.java @@ -0,0 +1,213 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; + +import java.util.Arrays; + +public class ArrayColumnReader extends ClickhouseColumnReader { + private static final Logger LOG = LoggerFactory.getLogger(ArrayColumnReader.class); + + private final ClickhouseBinaryDatabaseMetadata md; + private final ClickhouseBinaryColumnDescriptor elementTypeDescr; + + private int[][][] perRowsSlice; + + private Integer curDimension; + private ClickhouseColumnReader nestedColumnReader; + private ClickhouseColumn nestedColumn; + private Class elementClass; + private Integer nItems; + private Object statePrefix; + + private Integer curLevelSliceSize; + + public ArrayColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descr, ClickhouseBinaryDatabaseMetadata md) { + super(nRows, descr); + this.md = md; + this.elementTypeDescr = descr.getNestedDescr(); + } + + @Override + protected Object readStatePrefix(ClickhouseStreamDataSource in) { + ClickhouseColumnReader statePrefixColumn = ClickhouseColumns.columnForSpec(elementTypeDescr, md).reader(0); + if (statePrefix == null) { + statePrefix = statePrefixColumn.readStatePrefix(in); + } + return statePrefix; + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (nItems == null) { + curDimension = 0; + nItems = 0; + } + if (statePrefix == null) { + return null; + } + if (curDimension < columnDescriptor.arrayDimensionsCount()) { + LOG.debug("reading array slices"); + readAsPerRowSlices(in); + if (curDimension < columnDescriptor.arrayDimensionsCount()) { + LOG.debug("partial read arr1"); + return null; + } + } + if (nestedColumnReader == null) { + nestedColumn = ClickhouseColumns.columnForSpec(elementTypeDescr, md); + nestedColumnReader = nestedColumn.reader(nItems); + elementClass = nestedColumn.nullValue().getClass(); + } + if (elementTypeDescr.isNullable()) { + if (nestedColumnReader.nullsMap == null) { + nestedColumnReader.nullsMap = nestedColumnReader.readNullsMap(in); + if (LOG.isDebugEnabled()) { + LOG.debug("nestedColumnReader.nullsMap: " + nestedColumnReader.nullsMap); + } + } + } + if (nItems > 0) { + assert nItems == nestedColumnReader.nRows; + if (nestedColumnReader.getClass() == LowCardinalityColumnReader.class) { + ((LowCardinalityColumnReader) nestedColumnReader).keysSerializationVersion = (Long) statePrefix; + } + if (nestedColumnReader.isPartial()) { + nestedColumnReader.itemsArray = nestedColumnReader.readItems(in); + if (nestedColumnReader.isPartial()) { + LOG.debug("partial read arr2"); + return null; + } + } + return nestedColumnReader.itemsArray; + } + return nestedColumn.emptyArray(); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + desired = maybeUnwrapArrayElementType(desired); + return resliceIntoArray(nestedColumnReader, perRowsSlice[rowIdx], desired); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + throw new IllegalArgumentException("not implemented"); + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + throw new IllegalArgumentException("not implemented"); + } + + private Class maybeUnwrapArrayElementType(Class desired) { + if (desired != null) { + while (desired.isArray() && desired != byte[].class) { + desired = desired.getComponentType(); + } + } + return desired; + } + + + private Object resliceIntoArray(ClickhouseColumnReader reader, int[][] sliceToUse, Class elementClass) { + int i = sliceToUse.length - 1; + int[] slices = sliceToUse[i]; + Object[] intermData = reader.slices(slices, elementClass); //resliceArray(dataAccessor, slices, java.lang.reflect.Array.newInstance(elementClass, 0).getClass()); + + for (i = sliceToUse.length - 2; i >= 0; --i) { + slices = sliceToUse[i]; + intermData = resliceArray(intermData, slices, intermData.getClass()); + } + return intermData[0]; + } + + private Object[] resliceArray(Object[] dataElements, int[] slices, Class upperClass) { + IntPairIterator paired = PairedIterator.of(slices); + Object[] newDataList = (Object[]) java.lang.reflect.Array.newInstance(upperClass, slices.length - 1); + int tmpSliceIdx = 0; + while (paired.hasNext()) { + paired.next(); + int newSliceSz = paired.getValue() - paired.getKey(); + Object[] reslicedArray = (Object[]) java.lang.reflect.Array.newInstance(upperClass.getComponentType(), newSliceSz); + System.arraycopy(dataElements, paired.getKey(), reslicedArray, 0, newSliceSz); + newDataList[tmpSliceIdx] = reslicedArray; + ++tmpSliceIdx; + } + return newDataList; + } + + private void readAsPerRowSlices(ClickhouseStreamDataSource in) { + if (nRows == 0) { + perRowsSlice = new int[0][][]; + curDimension = columnDescriptor.arrayDimensionsCount(); + return; + } + + if (perRowsSlice == null) { + perRowsSlice = new int[nRows][][]; + for (int i = 0; i < nRows; ++i) { + perRowsSlice[i] = new int[columnDescriptor.arrayDimensionsCount()][]; + } + curLevelSliceSize = nRows; + } + + while (curDimension < columnDescriptor.arrayDimensionsCount()) { + int readableBytes = in.readableBytes(); + if (readableBytes < curLevelSliceSize * Long.BYTES) { + if (LOG.isDebugEnabled()) { + LOG.debug("ArrayColumnReader: not enough bytes; have + " + readableBytes + "; need " + curLevelSliceSize * Long.SIZE); + } + return; + } + long prevSliceElement = 0; + for (int rowIdx = 0; rowIdx < nRows; ++rowIdx) { + int rowSliceElementsToReadAtDimension; + if (curDimension == 0) { + rowSliceElementsToReadAtDimension = 1; + } else { + int[] rowSliceAtPrevDimension = perRowsSlice[rowIdx][curDimension - 1]; + rowSliceElementsToReadAtDimension = rowSliceAtPrevDimension[rowSliceAtPrevDimension.length - 1] - rowSliceAtPrevDimension[0]; + } + int[] rowSliceAtDimension = new int[rowSliceElementsToReadAtDimension + 1]; + //offsets at last dimension are absolute + boolean lastDimension = curDimension == columnDescriptor.arrayDimensionsCount() - 1; + int firstElementInSlice = (int) prevSliceElement; + rowSliceAtDimension[0] = (firstElementInSlice - (int)(lastDimension ? 0L : firstElementInSlice)); + for (int i = 0; i < rowSliceElementsToReadAtDimension; ++i) { + prevSliceElement = in.readLongLE(); + if (prevSliceElement > Integer.MAX_VALUE) { + throw new IllegalStateException("nested size is too big (" + prevSliceElement + "), max " + Integer.MAX_VALUE); + } + rowSliceAtDimension[i + 1] = ((int)(prevSliceElement - (lastDimension ? 0L : firstElementInSlice))); + } + perRowsSlice[rowIdx][curDimension] = (rowSliceAtDimension); + if (LOG.isDebugEnabled()) { + LOG.debug("rowSliceAtDimension[" + rowIdx + "]:" + Arrays.toString(rowSliceAtDimension)); + } + } + ++curDimension; + curLevelSliceSize = (int)prevSliceElement; + if (LOG.isDebugEnabled()) { + LOG.debug("curDimension: " + curDimension + "; columnDescriptor.arrayDimensionsCount(): " + columnDescriptor.arrayDimensionsCount()); + } + } + nItems = curLevelSliceSize; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumnWriter.java new file mode 100644 index 000000000..5d70e9369 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayColumnWriter.java @@ -0,0 +1,154 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class ArrayColumnWriter extends ClickhouseColumnWriter { + private final ClickhouseBinaryDatabaseMetadata md; + private final ClickhouseBinaryColumnDescriptor elementTypeDescr; + private final ClickhouseColumn elementTypeColumn; + + public ArrayColumnWriter(List data, ClickhouseBinaryColumnDescriptor descriptor, ClickhouseBinaryDatabaseMetadata md, int columnIndex) { + super(data, descriptor, columnIndex); + this.md = md; + this.elementTypeDescr = descriptor.getNestedDescr(); + this.elementTypeColumn = ClickhouseColumns.columnForSpec(elementTypeDescr, md); + } + + @Override + protected void serializeDataInternal(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + writeSizes(sink, false, fromRow, toRow); + writeNullsInfo(sink, 0, columnDescriptor, data, fromRow, toRow, columnIndex); + writeElementData(sink, 0, columnDescriptor, data, fromRow, toRow, columnIndex); + } + + private void writeElementData(ClickhouseStreamDataSink sink, int localDepth, ClickhouseBinaryColumnDescriptor descr, List localData, int fromRow, int toRow, int colIndex) { + if (localDepth != 0 && descr.isArray() && elementTypeDescr.isNullable() && localData == null) { + localData = Collections.emptyList(); + } + + while (localDepth < descr.arrayDimensionsCount()) { + localData = flattenArrays(localData, fromRow, toRow, colIndex); + colIndex = 0; + fromRow = 0; + toRow = localData.size(); + localDepth += 1; + } + ClickhouseColumn localNestedColumn = ClickhouseColumns.columnForSpec(elementTypeDescr, md); + ClickhouseColumnWriter localWriter = localNestedColumn.writer(localData, colIndex); + localWriter.serializeDataInternal(sink, fromRow, toRow); + } + + private void writeNullsInfo(ClickhouseStreamDataSink sink, int localDepth, ClickhouseBinaryColumnDescriptor descr, List localData, int fromRow, int toRow, int colIndex) { + if (localDepth != 0 && descr.isArray() && elementTypeDescr.isNullable() && localData == null) { + localData = Collections.emptyList(); + } + + while (localDepth < descr.arrayDimensionsCount()) { + localData = flattenArrays(localData, fromRow, toRow, colIndex); + colIndex = 0; + fromRow = 0; + toRow = localData.size(); + localDepth += 1; + } + if (elementTypeDescr.isNullable()) { + elementTypeColumn.writer(localData, colIndex).serializeNullsMap(sink, fromRow, toRow); + } + } + + private static List flattenArrays(List data, int fromRow, int toRow, int colIndex) { + List result = new ArrayList<>(); + for (int i = fromRow; i < toRow; ++i) { + Tuple row = data.get(i); + Object element = row.getValue(colIndex); + Class cls = element.getClass(); + if (cls.isArray() && cls != byte[].class) { + Object[] arr = (Object[])element; + List tuples = Arrays.stream(arr).map(Tuple::of).collect(Collectors.toList()); + result.addAll(tuples); + } else { + result.add(Tuple.of(element)); + } + } + return result; + } + + private void writeSizes(ClickhouseStreamDataSink sink, boolean writeTotalSize, int fromRow, int toRow) { + int nRows = toRow - fromRow; + List sizes = new ArrayList<>(); + if (writeTotalSize) { + sizes.add(nRows); + } + + List values = data; + int localColumnIndex = columnIndex; + int localDepth = 0; + while (localDepth < columnDescriptor.arrayDimensionsCount()) { + int offset = 0; + List newValue = new ArrayList<>(); + for (int i = fromRow; i < toRow; ++i) { + Object valObj = values.get(i); + Object tmp = maybeUnwrapTuple(valObj, localColumnIndex); + Object[] val = (Object[]) tmp; + offset += val.length; + sizes.add(offset); + List newTuples = Arrays.asList(val); + newValue.addAll(newTuples); + } + values = newValue; + ++localDepth; + localColumnIndex = 0; + fromRow = 0; + toRow = newValue.size(); + } + sink.ensureWritable(sizes.size() * Long.BYTES); + for (Integer size : sizes) { + sink.writeLongLE(size); + } + } + + protected void serializeStatePrefix(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + elementTypeColumn.writer(data, 0).serializeStatePrefix(sink, fromRow, toRow); + } + + private static Object maybeUnwrapTuple(Object val, int columnIndex) { + return val instanceof Tuple ? ((Tuple)val).getValue(columnIndex) : val; + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + } + + @Override + protected void serializeNullsMap(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + } + + @Override + protected void ensureCapacity(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayIntPairIterator.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayIntPairIterator.java new file mode 100644 index 000000000..4baa75622 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ArrayIntPairIterator.java @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +public class ArrayIntPairIterator implements IntPairIterator { + private final int[] src; + private int pos; + + public ArrayIntPairIterator(int[] src) { + this.src = src; + this.pos = -1; + } + + + @Override + public boolean hasNext() { + return pos < src.length - 2; + } + + @Override + public void next() { + ++pos; + } + + @Override + public int getKey() { + return src[pos]; + } + + @Override + public int getValue() { + return src[pos + 1]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumn.java new file mode 100644 index 000000000..f325a637c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumn.java @@ -0,0 +1,33 @@ +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class BooleanColumn extends ClickhouseColumn { + public static final Boolean[] EMPTY_BOOLEAN_ARRAY = new Boolean[0]; + public BooleanColumn(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new BooleanColumnReaderAsBitSet(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new BooleanColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return Boolean.FALSE; + } + + @Override + public Object[] emptyArray() { + return EMPTY_BOOLEAN_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnReaderAsArray.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnReaderAsArray.java new file mode 100644 index 000000000..56115864f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnReaderAsArray.java @@ -0,0 +1,42 @@ +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +public class BooleanColumnReaderAsArray extends ClickhouseColumnReader { + public static final int ELEMENT_SIZE = 1; + protected BooleanColumnReaderAsArray(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= ELEMENT_SIZE * nRows) { + boolean[] data = new boolean[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + data[i] = in.readBoolean(); + } else { + in.skipBytes(ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == boolean.class) { + return new boolean[dim1][dim2]; + } + return new Boolean[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == boolean.class) { + return new boolean[length]; + } + return new Boolean[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnReaderAsBitSet.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnReaderAsBitSet.java new file mode 100644 index 000000000..0dcb28f2f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnReaderAsBitSet.java @@ -0,0 +1,49 @@ +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.util.BitSet; + +public class BooleanColumnReaderAsBitSet extends ClickhouseColumnReader { + protected BooleanColumnReaderAsBitSet(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return ((BitSet)itemsArray).get(rowIdx); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= BooleanColumnReaderAsArray.ELEMENT_SIZE * nRows) { + BitSet data = new BitSet(nRows); + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + data.set(i, in.readBoolean()); + } else { + in.skipBytes(BooleanColumnReaderAsArray.ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == boolean.class) { + return new boolean[dim1][dim2]; + } + return new Boolean[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == boolean.class) { + return new boolean[length]; + } + return new Boolean[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnWriter.java new file mode 100644 index 000000000..d0a0317c9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/BooleanColumnWriter.java @@ -0,0 +1,23 @@ +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class BooleanColumnWriter extends ClickhouseColumnWriter { + public BooleanColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + sink.writeBoolean((Boolean) val); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(BooleanColumnReaderAsArray.ELEMENT_SIZE); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumn.java new file mode 100644 index 000000000..bc9402c2b --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumn.java @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public abstract class ClickhouseColumn { + protected ClickhouseBinaryColumnDescriptor descriptor; + + public ClickhouseColumn(ClickhouseBinaryColumnDescriptor descriptor) { + this.descriptor = descriptor; + } + + public abstract ClickhouseColumnReader reader(int nRows); + + public abstract ClickhouseColumnWriter writer(List data, int columnIndex); + + public abstract Object nullValue(); + public abstract Object[] emptyArray(); +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnReader.java new file mode 100644 index 000000000..07d33f890 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnReader.java @@ -0,0 +1,180 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; + +import java.util.BitSet; + +public abstract class ClickhouseColumnReader { + private static final Logger LOG = LoggerFactory.getLogger(ClickhouseColumnReader.class); + + private static final Object NOP_STATE = new Object(); + + protected final int nRows; + protected final ClickhouseBinaryColumnDescriptor columnDescriptor; + protected BitSet nullsMap; + //TODO: parametrize class with type of itemsArray? + protected Object itemsArray; + + private long bytesConsumed; + private String bufferAsStringConsumed = ""; + + protected ClickhouseColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + this.columnDescriptor = columnDescriptor; + this.nRows = nRows; + } + + public ClickhouseBinaryColumnDescriptor columnDescriptor() { + return columnDescriptor; + } + + public void readColumn(ClickhouseStreamDataSource in){ + int idxStart = in.readerIndex(); + readStatePrefix(in); + readData(in); + int idxEnd = in.readerIndex(); + int bytesRead = idxEnd - idxStart; + bytesConsumed += bytesRead; + bufferAsStringConsumed += in.hexDump(idxStart, bytesRead); + } + + public long bytesConsumed() { + return bytesConsumed; + } + + public String bufferAsStringConsumed() { + return bufferAsStringConsumed; + } + + public int nRows() { + return nRows; + } + + protected Object readStatePrefix(ClickhouseStreamDataSource in) { + return NOP_STATE; + } + + protected void readData(ClickhouseStreamDataSource in) { + if (columnDescriptor.isNullable() && nullsMap == null) { + nullsMap = readNullsMap(in); + if (nullsMap == null) { + return; + } + } + readDataInternal(in); + } + + protected void readDataInternal(ClickhouseStreamDataSource in) { + if (itemsArray == null) { + itemsArray = readItems(in); + if (itemsArray == null) { + return; + } + } + afterReadItems(in); + } + + protected Object[] asObjectsArrayWithGetElement(int startIncluding, int endExcluding, Class desired) { + Object[] ret = (Object[]) allocateOneDimArray(desired, endExcluding - startIncluding); + int arrayIdx = 0; + for (int i = startIncluding; i < endExcluding; ++i) { + ret[arrayIdx] = getElement(i, desired); + ++arrayIdx; + } + return ret; + } + + protected Object[] asObjectsArrayWithGetElement(Class desired) { + return asObjectsArrayWithGetElement(0, nRows, desired); + } + + protected abstract Object readItems(ClickhouseStreamDataSource in); + protected void afterReadItems(ClickhouseStreamDataSource in) { + } + + protected BitSet readNullsMap(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= nRows) { + LOG.debug("readNullsMap"); + BitSet bSet = new BitSet(nRows); + for (int i = 0; i < nRows; ++i) { + byte b = in.readByte(); + if (b != 0) { + bSet.set(i); + } + } + return bSet; + } else { + if (LOG.isDebugEnabled()) { + LOG.debug("readNullsMap skipped: has " + in.readableBytes() + "; need" + nRows); + } + } + return null; + } + + public boolean isPartial() { + boolean ret = itemsArray == null || (columnDescriptor.isNullable() && nullsMap == null); + if (LOG.isDebugEnabled()) { + LOG.debug("isPartial: " + ret + "; itemsArray == null: " + (itemsArray == null) + "; columnDescriptor.isNullable(): " + + columnDescriptor.isNullable() + "; nullsMap == null: " + (nullsMap == null)); + } + return ret; + } + + public Object getElement(int rowIdx, Class desired) { + if (nullsMap != null && nullsMap.get(rowIdx)) { + return null; + } + return getElementInternal(rowIdx, desired); + } + + protected Object getElementInternal(int rowIdx, Class desired) { + return java.lang.reflect.Array.get(itemsArray, rowIdx); + } + + protected Object getObjectsArrayElement(int rowIdx) { + Object[] data = (Object[]) itemsArray; + return data[rowIdx]; + } + + public Object[] slices(int[] slices, Class desired) { + IntPairIterator slice = PairedIterator.of(slices); + int sliceCount = slices.length - 1; + Object[] ret = allocateTwoDimArray(desired, sliceCount, 0); + if (desired.isPrimitive()) { + if (columnDescriptor.isNullable()) { + throw new IllegalArgumentException("primitive arrays are not supported for nullable columns"); + } + for (int sliceIdx = 0; sliceIdx < sliceCount; ++sliceIdx) { + slice.next(); + int len = slice.getValue() - slice.getKey(); + Object tmp = allocateOneDimArray(desired, len); + System.arraycopy(itemsArray, slice.getKey(), tmp, 0, len); + ret[sliceIdx] = tmp; + } + } else { + for (int sliceIdx = 0; sliceIdx < sliceCount; ++sliceIdx) { + slice.next(); + ret[sliceIdx] = asObjectsArrayWithGetElement(slice.getKey(), slice.getValue(), ret.getClass().getComponentType().getComponentType()); + } + } + return ret; + } + + protected abstract Object[] allocateTwoDimArray(Class desired, int dim1, int dim2); + protected abstract Object allocateOneDimArray(Class desired, int length); +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnWriter.java new file mode 100644 index 000000000..2408d8c26 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnWriter.java @@ -0,0 +1,96 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public abstract class ClickhouseColumnWriter { + protected final List data; + protected final ClickhouseBinaryColumnDescriptor columnDescriptor; + protected final int columnIndex; + + public ClickhouseColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + this.data = data; + this.columnDescriptor = columnDescriptor; + this.columnIndex = columnIndex; + } + + public void serializeColumn(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + serializeStatePrefix(sink, fromRow, toRow); + serializeData(sink, fromRow, toRow); + } + + protected void serializeStatePrefix(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + } + + protected void serializeData(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + ensureCapacity(sink, fromRow, toRow); + if (columnDescriptor.isNullable()) { + serializeNullsMap(sink, fromRow, toRow); + } + serializeDataInternal(sink, fromRow, toRow); + } + + protected int nullsMapSize(int nRows) { + if (columnDescriptor.isNullable() && !columnDescriptor.isLowCardinality()) { + return nRows; + } + return 0; + } + + protected int elementsSize(int fromRow, int toRow) { + if (columnDescriptor.getElementSize() > 0) { + return (toRow - fromRow) * columnDescriptor.getElementSize(); + } + return 0; + } + + protected void ensureCapacity(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + int requiredSize = 0; + requiredSize += nullsMapSize(toRow - fromRow); + requiredSize += elementsSize(fromRow, toRow); + sink.ensureWritable(requiredSize); + } + + protected void serializeNullsMap(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + for (int rowNo = fromRow; rowNo < toRow; ++rowNo) { + Object val = data.get(rowNo).getValue(columnIndex); + sink.writeBoolean(val == null); + } + } + + protected void serializeDataInternal(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + for (int rowNo = fromRow; rowNo < toRow; ++rowNo) { + Object val = data.get(rowNo).getValue(columnIndex); + if (val == null) { + if (columnDescriptor.isNullable()) { + serializeDataNull(sink); + } else { + throw new IllegalArgumentException("can't serialize null for non-nullable column " + columnDescriptor.name() + " at row " + rowNo); + } + } else { + serializeDataElement(sink, val); + } + } + } + + protected abstract void serializeDataElement(ClickhouseStreamDataSink sink, Object val); + + //TODO: maybe skip bytes instead (perform ByteBuf.writerIndex(writerIndex() + elemSize)) (is allocated memory zero-filled ?) + protected abstract void serializeDataNull(ClickhouseStreamDataSink sink); +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumns.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumns.java new file mode 100644 index 000000000..3c6b4b8f1 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumns.java @@ -0,0 +1,311 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.QueryParsers; + +import java.math.BigInteger; +import java.sql.JDBCType; +import java.time.Duration; +import java.time.ZoneId; +import java.util.AbstractMap; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class ClickhouseColumns { + public static final String NULLABLE_PREFIX = "Nullable("; + public static final int NULLABLE_PREFIX_LENGTH = NULLABLE_PREFIX.length(); + + public static final String ARRAY_PREFIX = "Array("; + public static final int ARRAY_PREFIX_LENGTH = ARRAY_PREFIX.length(); + + public static final String LOW_CARDINALITY_PREFIX = "LowCardinality("; + public static final int LOW_CARDINALITY_PREFIX_LENGTH = LOW_CARDINALITY_PREFIX.length(); + + public static final String FIXED_STRING_PREFIX = "FixedString("; + public static final int FIXED_STRING_PREFIX_LENGTH = FIXED_STRING_PREFIX.length(); + + public static final String DECIMAL_PREFIX = "Decimal("; + public static final int DECIMAL_PREFIX_LENGTH = DECIMAL_PREFIX.length(); + + public static final String ENUM_PREFIX = "Enum"; + public static final int ENUM_PREFIX_LENGTH = ENUM_PREFIX.length(); + + public static final String INTERVAL_PREFIX = "Interval"; + + private static final Map CONST_DURATION_MULTIPLIERS = Collections.unmodifiableMap(buildConstDurationMultipliers()); + + private static Map buildConstDurationMultipliers() { + HashMap result = new HashMap<>(); + result.put("Second", Duration.ofSeconds(1)); + result.put("Day", Duration.ofDays(1)); + result.put("Hour", Duration.ofHours(1)); + result.put("Minute", Duration.ofMinutes(1)); + result.put("Week", Duration.ofDays(7)); + return result; + } + + + public static ClickhouseBinaryColumnDescriptor columnDescriptorForSpec(String unparsedSpec, String name) { + String spec = unparsedSpec; + Map.Entry arrayDimensionsInfo = maybeUnwrapArrayDimensions(spec); + if (arrayDimensionsInfo.getKey() > 0) { + ClickhouseBinaryColumnDescriptor nested = columnDescriptorForSpec(arrayDimensionsInfo.getValue(), name); + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, true, ClickhouseBinaryColumnDescriptor.NOSIZE, + JDBCType.ARRAY, false, false, false, null, null, arrayDimensionsInfo.getKey(), nested); + } + boolean isLowCardinality = false; + if (spec.startsWith(LOW_CARDINALITY_PREFIX)) { + spec = spec.substring(LOW_CARDINALITY_PREFIX_LENGTH, spec.length() - 1); + isLowCardinality = true; + } + boolean nullable = false; + if (spec.startsWith(NULLABLE_PREFIX)) { + spec = spec.substring(NULLABLE_PREFIX_LENGTH, spec.length() - 1); + nullable = true; + } + return columnDescriptorForSpec(unparsedSpec, spec, name, nullable, false, isLowCardinality); + } + + private static Map.Entry maybeUnwrapArrayDimensions(String spec) { + int arrayDepth = 0; + while (spec.startsWith(ARRAY_PREFIX)) { + spec = spec.substring(ARRAY_PREFIX_LENGTH, spec.length() - 1); + ++arrayDepth; + } + return new AbstractMap.SimpleEntry<>(arrayDepth, spec); + } + + public static ClickhouseBinaryColumnDescriptor columnDescriptorForSpec(String unparsedSpec, String spec, String name, + boolean nullable, boolean isArray, + boolean isLowCardinality) { + boolean unsigned = spec.startsWith("U"); + //older versions (at least yandex/clickhouse-server:20.10.2) return Int8 for bool types + //newer versions (at least clickhouse/clickhouse-server:22.9.3.18) return Bool, + if (spec.equals("UInt8") || spec.equals("Int8")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, SignedInt8ColumnReader.ELEMENT_SIZE, JDBCType.TINYINT, nullable, unsigned, isLowCardinality, + unsigned ? 0 : -128, unsigned ? 255 : 127); + } else if (spec.equals("Bool") || spec.equals("Boolean")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, SignedInt8ColumnReader.ELEMENT_SIZE, JDBCType.BOOLEAN, nullable, unsigned, isLowCardinality, + 0, 1); + } else if (spec.equals("UInt16") || spec.equals("Int16")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, SignedInt16ColumnReader.ELEMENT_SIZE, JDBCType.SMALLINT, nullable, unsigned, isLowCardinality, + unsigned ? 0 : -32768, unsigned ? 65535 : 32767); + } if (spec.equals("UInt32") || spec.equals("Int32")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, SignedInt32ColumnReader.ELEMENT_SIZE, JDBCType.INTEGER, nullable, unsigned, isLowCardinality, + unsigned ? 0 : -2147483648L, unsigned ? 4294967295L : 2147483647L); + } if (spec.equals("UInt64") || spec.equals("Int64")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, SignedInt64ColumnReader.ELEMENT_SIZE, JDBCType.BIGINT, nullable, unsigned, isLowCardinality, + unsigned ? BigInteger.ZERO : new BigInteger("-9223372036854775808"), + unsigned ? new BigInteger("18446744073709551615") : new BigInteger("9223372036854775807")); + } if (spec.equals("Int128")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, Int128Column.ELEMENT_SIZE, JDBCType.BIGINT, nullable, false, isLowCardinality, + Int128Column.INT128_MIN_VALUE, Int128Column.INT128_MAX_VALUE); + } else if (spec.equals("String")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, ClickhouseBinaryColumnDescriptor.NOSIZE, JDBCType.VARCHAR, + nullable, false, isLowCardinality, null, null); + } else if (spec.startsWith(FIXED_STRING_PREFIX)) { + String lengthStr = spec.substring(FIXED_STRING_PREFIX_LENGTH, spec.length() - 1); + int bytesLength = Integer.parseInt(lengthStr); + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, bytesLength, JDBCType.VARCHAR, + nullable, false, isLowCardinality, null, null); + } else if (spec.startsWith("DateTime64")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, DateTime64Column.ELEMENT_SIZE, + spec.endsWith(")") ? JDBCType.TIMESTAMP_WITH_TIMEZONE : JDBCType.TIMESTAMP, nullable, false, isLowCardinality, null, null); + } else if (spec.startsWith("DateTime")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, DateTimeColumnReader.ELEMENT_SIZE, + spec.endsWith(")") ? JDBCType.TIMESTAMP_WITH_TIMEZONE : JDBCType.TIMESTAMP, nullable, false, isLowCardinality, null, null); + } else if (spec.equals("UUID")) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, UUIDColumn.ELEMENT_SIZE, + JDBCType.OTHER, nullable, false, isLowCardinality, null, null); + } else if (spec.startsWith(DECIMAL_PREFIX)) { + String decimalModifiers = spec.substring(DECIMAL_PREFIX_LENGTH, spec.length() - 1); + String[] modifiersTokens = decimalModifiers.split(","); + int precision = Integer.parseInt(modifiersTokens[0].trim()); + int scale = Integer.parseInt(modifiersTokens[1].trim()); + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, decimalSize(precision), + JDBCType.DECIMAL, nullable, false, isLowCardinality, null, null, precision, scale); + } else if (spec.startsWith(ENUM_PREFIX)) { + int openBracketPos = spec.indexOf('(', ENUM_PREFIX_LENGTH); + int enumBitsSize = Integer.parseInt(spec.substring(ENUM_PREFIX_LENGTH, openBracketPos)); + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, enumBitsSize / 8, + JDBCType.OTHER, nullable, false, isLowCardinality, null, null, null, null); + } else if ("Nothing".equals(spec)) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, SignedInt8ColumnReader.ELEMENT_SIZE, + JDBCType.NULL, nullable, false, isLowCardinality, null, null, null, null); + } else if ("Float32".equals(spec)) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, Float32ColumnReader.ELEMENT_SIZE, + JDBCType.REAL, nullable, false, isLowCardinality, null, null, null, null); + } else if ("Float64".equals(spec)) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, Float64ColumnReader.ELEMENT_SIZE, + JDBCType.DOUBLE, nullable, false, isLowCardinality, null, null, null, null); + } else if ("Date".equals(spec)) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, SignedInt16ColumnReader.ELEMENT_SIZE, + JDBCType.DATE, nullable, true, isLowCardinality, 0, 65535, null, null); + } else if (spec.startsWith(INTERVAL_PREFIX)) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, SignedInt64ColumnReader.ELEMENT_SIZE, + JDBCType.OTHER, nullable, false, isLowCardinality, null, null, null, null); + } else if ("IPv4".equals(spec)) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, IPv4Column.ELEMENT_SIZE, + JDBCType.OTHER, nullable, true, isLowCardinality, null, null, null, null); + } else if ("IPv6".equals(spec)) { + return new ClickhouseBinaryColumnDescriptor(name, unparsedSpec, spec, isArray, IPv6Column.ELEMENT_SIZE, + JDBCType.OTHER, nullable, true, isLowCardinality, null, null, null, null); + } + throw new IllegalArgumentException("unknown column spec: '" + spec + "'"); + } + + private static int decimalSize(int precision) { + if (precision <= Decimal32Column.MAX_PRECISION) { + return Decimal32Column.ELEMENT_SIZE; + } else if (precision <= Decimal64Column.MAX_PRECISION) { + return Decimal64Column.ELEMENT_SIZE; + } else if (precision <= Decimal128Column.MAX_PRECISION) { + return Decimal128Column.ELEMENT_SIZE; + } else if (precision <= Decimal256Column.MAX_PRECISION ){ + return Decimal256Column.ELEMENT_SIZE; + } else { + throw new IllegalArgumentException("precision is too large: " + precision); + } + } + + public static ClickhouseColumn columnForSpec(String spec, String name, ClickhouseBinaryDatabaseMetadata md) { + return columnForSpec(spec, name, md, false); + } + + public static ClickhouseColumn columnForSpec(String spec, String name, ClickhouseBinaryDatabaseMetadata md, boolean enableStringCache) { + ClickhouseBinaryColumnDescriptor descr = ClickhouseColumns.columnDescriptorForSpec(spec, name); + return columnForSpec(descr, md, enableStringCache); + } + + public static ClickhouseColumn columnForSpec(ClickhouseBinaryColumnDescriptor descr, ClickhouseBinaryDatabaseMetadata md) { + return columnForSpec(descr, md, false); + } + + public static ClickhouseColumn columnForSpec(ClickhouseBinaryColumnDescriptor descr, ClickhouseBinaryDatabaseMetadata md, boolean enableStringCache) { + if (descr.isArray()) { + return new ArrayColumn(descr, md); + } + if (descr.isLowCardinality()) { + return new LowCardinalityColumn(descr, md); + } + JDBCType jdbcType = descr.jdbcType(); + if (jdbcType == JDBCType.TINYINT || jdbcType == JDBCType.NULL) { + return new UInt8Column(descr); + } else if (jdbcType == JDBCType.BOOLEAN) { + return new BooleanColumn(descr); + } else if (jdbcType == JDBCType.SMALLINT) { + return new UInt16Column(descr); + } else if (jdbcType == JDBCType.INTEGER) { + return new UInt32Column(descr); + } else if (jdbcType == JDBCType.BIGINT) { + if (descr.getElementSize() == SignedInt64ColumnReader.ELEMENT_SIZE) { + return new UInt64Column(descr); + } else if (descr.getElementSize() == Int128Column.ELEMENT_SIZE) { + return new Int128Column(descr); + } + } else if (jdbcType == JDBCType.VARCHAR) { + if (descr.getElementSize() == ClickhouseBinaryColumnDescriptor.NOSIZE) { + return new StringColumn(descr, md, enableStringCache); + } else { + return new FixedStringColumn(descr, md, enableStringCache); + } + } else if (jdbcType == JDBCType.TIMESTAMP || jdbcType == JDBCType.TIMESTAMP_WITH_TIMEZONE) { + ZoneId zoneId; + Integer precision = null; + String nativeType = descr.getNestedType(); + if (nativeType.endsWith(")")) { + int openBracePos = nativeType.indexOf("("); + String dateModifiers = nativeType.substring(openBracePos + 1, nativeType.length() - 1); + if (descr.getElementSize() == DateTime64Column.ELEMENT_SIZE) { + String[] modifiers = dateModifiers.split(","); + precision = Integer.parseInt(modifiers[0].trim()); + if (modifiers.length == 2) { + String id = modifiers[1].trim(); + id = id.substring(1, id.length() - 1); + zoneId = ZoneId.of(id); + } else { + zoneId = md.getDefaultZoneId(); + } + } else { + zoneId = ZoneId.of(dateModifiers); + } + } else { + zoneId = md.getDefaultZoneId(); + } + return precision == null ? new DateTimeColumn(descr, zoneId) : new DateTime64Column(descr, precision, md.isSaturateExtraNanos(), zoneId); + } else if (jdbcType == JDBCType.DECIMAL) { + if (descr.getElementSize() == Decimal32Column.ELEMENT_SIZE) { + return new Decimal32Column(descr); + } else if (descr.getElementSize() == Decimal64Column.ELEMENT_SIZE) { + return new Decimal64Column(descr); + } else if (descr.getElementSize() == Decimal128Column.ELEMENT_SIZE) { + return new Decimal128Column(descr); + } else if (descr.getElementSize() == Decimal256Column.ELEMENT_SIZE) { + return new Decimal256Column(descr); + } + } else if (jdbcType == JDBCType.REAL) { + return new Float32Column(descr); + } else if (jdbcType == JDBCType.DOUBLE) { + return new Float64Column(descr); + } else if (jdbcType == JDBCType.DATE) { + return new DateColumn(descr); + } else if (jdbcType == JDBCType.OTHER) { + String nativeType = descr.getNestedType(); + if (nativeType.equals("UUID")) { + return new UUIDColumn(descr); + } else if (nativeType.startsWith(ENUM_PREFIX)) { + Map enumVals = QueryParsers.parseEnumValues(nativeType); + String enumResolutionStr = md.getProperties().get(ClickhouseConstants.OPTION_ENUM_RESOLUTION); + EnumResolutionMethod resolutionMethod = enumResolutionStr == null ? EnumResolutionMethod.ORDINAL : EnumResolutionMethod.forOpt(enumResolutionStr); + if (descr.getElementSize() == Enum8ColumnReader.ELEMENT_SIZE) { + return new Enum8Column(descr, enumVals, resolutionMethod); + } else if (descr.getElementSize() == Enum16ColumnReader.ELEMENT_SIZE) { + return new Enum16Column(descr, enumVals, resolutionMethod); + } + } else if (nativeType.startsWith(INTERVAL_PREFIX)) { + Duration multiplier = getDurationMultiplier(descr, md); + if (multiplier == null) { + throw new IllegalArgumentException("unknown duration specifier in spec: " + descr.getUnparsedNativeType()); + } + return new IntervalColumn(descr, multiplier); + } else if (nativeType.equals("IPv4")) { + return new IPv4Column(descr); + } else if (nativeType.equals("IPv6")) { + return new IPv6Column(descr, md); + } + } + throw new IllegalArgumentException("no column type for jdbc type " + jdbcType + " (raw type: '" + descr.getUnparsedNativeType() + "')"); + } + + private static Duration getDurationMultiplier(ClickhouseBinaryColumnDescriptor descr, ClickhouseBinaryDatabaseMetadata md) { + String durationStr = descr.getNestedType().substring(INTERVAL_PREFIX.length()); + Duration multiplier = CONST_DURATION_MULTIPLIERS.get(durationStr); + if (multiplier == null) { + switch (durationStr) { + case "Year": + return md.yearDuration(); + case "Quarter": + return md.quarterDuration(); + case "Month": + return md.monthDuration(); + } + } + return multiplier; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ColumnUtils.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ColumnUtils.java new file mode 100644 index 000000000..67d575e79 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ColumnUtils.java @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +import java.math.BigDecimal; + +public class ColumnUtils { + public static byte[] reverse(byte[] src) { + for (int i = 0, j = src.length - 1; i < j; ++i, --j) { + byte tmp = src[i]; + src[i] = src[j]; + src[j] = tmp; + } + return src; + } + + public static int getLastNonZeroPos(byte[] bytes) { + int lastNonZeroPos = bytes.length - 1; + for (; lastNonZeroPos >= 0 && bytes[lastNonZeroPos] == 0; --lastNonZeroPos) { + } + return lastNonZeroPos; + } + + //TODO: maybe rework checks + public static void bigDecimalFitsOrThrow(BigDecimal bd, ClickhouseBinaryColumnDescriptor columnDescriptor) { + if (columnDescriptor.getScale() < bd.scale()) { + throw new IllegalArgumentException("possible loss of scale: max " + columnDescriptor.getScale() + ", got " + bd.scale()); + } + if (columnDescriptor.getPrecision() < bd.precision()) { + throw new IllegalArgumentException("possible loss of precision: max " + columnDescriptor.getPrecision() + ", got " + bd.precision()); + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumn.java new file mode 100644 index 000000000..0339a202d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumn.java @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class DateColumn extends UInt16Column { + public DateColumn(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new DateColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new DateColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return DateColumnReader.MIN_VALUE; + } + + @Override + public Object[] emptyArray() { + return DateColumnReader.EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumnReader.java new file mode 100644 index 000000000..f2841df23 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumnReader.java @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +import java.time.LocalDate; + +public class DateColumnReader extends UnsignedInt16ColumnReader { + public static final LocalDate[] EMPTY_ARRAY = new LocalDate[0]; + + public static final LocalDate MIN_VALUE = LocalDate.of(1970, 1, 1); + public static final LocalDate MAX_VALUE = MIN_VALUE.plusDays(65535); + + public DateColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + Integer offset = (Integer) super.getElementInternal(rowIdx, desired); + return MIN_VALUE.plusDays(offset); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new LocalDate[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new LocalDate[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumnWriter.java new file mode 100644 index 000000000..ae8217d54 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateColumnWriter.java @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; +import java.util.List; + +public class DateColumnWriter extends UInt16ColumnWriter { + public static final long MAX_VALUE = 65535; + + public DateColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + LocalDate dateVal = (LocalDate) val; + long daysDelta = ChronoUnit.DAYS.between(DateColumnReader.MIN_VALUE, dateVal); + if (daysDelta < 0) { + throw new IllegalArgumentException("date " + dateVal + " is too small; smallest possible date: " + DateColumnReader.MIN_VALUE); + } + if (daysDelta > MAX_VALUE) { + throw new IllegalArgumentException("date " + dateVal + " is too big; largest possible date: " + DateColumnReader.MAX_VALUE); + } + super.serializeDataElement(sink, daysDelta); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64Column.java new file mode 100644 index 000000000..91976da59 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64Column.java @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.time.Instant; +import java.time.ZoneId; +import java.util.List; + +public class DateTime64Column extends ClickhouseColumn { + public static final int ELEMENT_SIZE = 8; + public static final Instant ZERO_INSTANT = Instant.EPOCH; + public static final Instant[] EMPTY_ARRAY = new Instant[0]; + + private final Integer precision; + private final ZoneId zoneId; + private boolean saturateExtraNanos; + + public DateTime64Column(ClickhouseBinaryColumnDescriptor descriptor, Integer precision, boolean saturateExtraNanos, ZoneId zoneId) { + super(descriptor); + this.precision = precision; + this.zoneId = zoneId; + this.saturateExtraNanos = saturateExtraNanos; + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new DateTime64ColumnReader(nRows, descriptor, precision, zoneId); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new DateTime64ColumnWriter(data, descriptor, precision, zoneId, saturateExtraNanos, columnIndex); + } + + @Override + public Object nullValue() { + return ZERO_INSTANT.atZone(zoneId).toOffsetDateTime(); + } + + @Override + public Object[] emptyArray() { + return EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64ColumnReader.java new file mode 100644 index 000000000..aea993573 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64ColumnReader.java @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.math.BigInteger; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; + +public class DateTime64ColumnReader extends ClickhouseColumnReader { + + private final ZoneId zoneId; + private final BigInteger invTickSize; + + public DateTime64ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descr, Integer precision, ZoneId zoneId) { + super(nRows, descr); + this.zoneId = zoneId; + this.invTickSize = BigInteger.TEN.pow(precision); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= DateTime64Column.ELEMENT_SIZE * nRows) { + OffsetDateTime[] data = new OffsetDateTime[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + BigInteger bi = SignedInt64ColumnReader.unsignedBi(in.readLongLE()); + long seconds = bi.divide(invTickSize).longValueExact(); + long nanos = bi.remainder(invTickSize).longValueExact(); + OffsetDateTime dt = Instant.ofEpochSecond(seconds, nanos).atZone(zoneId).toOffsetDateTime(); + data[i] = dt; + } else { + in.skipBytes(DateTime64Column.ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new OffsetDateTime[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new OffsetDateTime[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64ColumnWriter.java new file mode 100644 index 000000000..339548c36 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTime64ColumnWriter.java @@ -0,0 +1,61 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.math.BigInteger; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.List; + +public class DateTime64ColumnWriter extends ClickhouseColumnWriter { + private final BigInteger invTickSize; + private final long invTickLong; + private final ZoneId zoneId; + private final boolean saturateExtraNanos; + + public DateTime64ColumnWriter(List data, ClickhouseBinaryColumnDescriptor descr, Integer precision, ZoneId zoneId, boolean saturateExtraNanos, int columnIndex) { + super(data, descr, columnIndex); + this.zoneId = zoneId; + this.invTickSize = BigInteger.TEN.pow(precision); + this.invTickLong = invTickSize.longValueExact(); + this.saturateExtraNanos = saturateExtraNanos; + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + OffsetDateTime dt = (OffsetDateTime) val; + //TODO: maybe check zone offset + long tickCount = invTickSize.multiply(BigInteger.valueOf(dt.toEpochSecond())).longValue(); + long nanos = dt.getNano(); + if (nanos < invTickLong) { + tickCount += nanos; + } else { + if (saturateExtraNanos) { + tickCount += invTickLong - 1; + } else { + throw new IllegalArgumentException("nano adjustment " + nanos + " is too big, max " + invTickLong); + } + } + sink.writeLongLE(tickCount); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(DateTime64Column.ELEMENT_SIZE); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumn.java new file mode 100644 index 000000000..a94179175 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumn.java @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.List; + +public class DateTimeColumn extends ClickhouseColumn { + public static final OffsetDateTime[] EMPTY_ARRAY = new OffsetDateTime[0]; + + private final ZoneId zoneId; + private final OffsetDateTime nullValue; + + public DateTimeColumn(ClickhouseBinaryColumnDescriptor descriptor, ZoneId zoneId) { + super(descriptor); + this.zoneId = zoneId; + this.nullValue = Instant.EPOCH.atZone(zoneId).toOffsetDateTime(); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new DateTimeColumnReader(nRows, descriptor, zoneId); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new DateTimeColumnWriter(data, descriptor, zoneId, columnIndex); + } + + @Override + public Object nullValue() { + return nullValue; + } + + @Override + public Object[] emptyArray() { + return EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumnReader.java new file mode 100644 index 000000000..8521c5b0a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumnReader.java @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; + +public class DateTimeColumnReader extends ClickhouseColumnReader { + public static final long MAX_EPOCH_SECOND = 4294967295L; + + public static final int ELEMENT_SIZE = 4; + + private final ZoneId zoneId; + + public DateTimeColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descr, ZoneId zoneId) { + super(nRows, descr); + this.zoneId = zoneId; + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= ELEMENT_SIZE * nRows) { + OffsetDateTime[] data = new OffsetDateTime[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + long unixSeconds = Integer.toUnsignedLong(in.readIntLE()); + OffsetDateTime dt = Instant.ofEpochSecond(unixSeconds).atZone(zoneId).toOffsetDateTime(); + data[i] = dt; + } else { + in.skipBytes(ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new OffsetDateTime[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new OffsetDateTime[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumnWriter.java new file mode 100644 index 000000000..f315db02e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/DateTimeColumnWriter.java @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.List; + +public class DateTimeColumnWriter extends ClickhouseColumnWriter { + public final OffsetDateTime maxValue; + + public DateTimeColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, ZoneId zoneId, int columnIndex) { + super(data, columnDescriptor, columnIndex); + this.maxValue = Instant.ofEpochSecond(DateTimeColumnReader.MAX_EPOCH_SECOND).atZone(zoneId).toOffsetDateTime(); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + OffsetDateTime dateTime = (OffsetDateTime) val; + long epochSecond = dateTime.toInstant().getEpochSecond(); + if (epochSecond > DateTimeColumnReader.MAX_EPOCH_SECOND) { + throw new IllegalArgumentException("value " + dateTime + " is too big; max epoch seconds: " + maxValue); + } + sink.writeIntLE((int) epochSecond); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeIntLE(0); + } + +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal128Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal128Column.java new file mode 100644 index 000000000..108f8a4c7 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal128Column.java @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.List; + +public class Decimal128Column extends ClickhouseColumn { + public static final Numeric[] EMPTY_ARRAY = new Numeric[0]; + + public static final int ELEMENT_SIZE = 16; + public static final int MAX_PRECISION = 38; + public static final MathContext MATH_CONTEXT = new MathContext(MAX_PRECISION, RoundingMode.HALF_EVEN); + private final Numeric zeroValue; + + public Decimal128Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + zeroValue = Numeric.create(new BigDecimal(BigInteger.ZERO, descriptor.getPrecision(), MATH_CONTEXT)); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new GenericDecimalColumnReader(nRows, descriptor, MATH_CONTEXT); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new GenericDecimalColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return zeroValue; + } + + @Override + public Object[] emptyArray() { + return EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal256Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal256Column.java new file mode 100644 index 000000000..fa5886efb --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal256Column.java @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.List; + +//Looks like support is experimental at the moment +public class Decimal256Column extends ClickhouseColumn { + public static final int ELEMENT_SIZE = 32; + public static final int MAX_PRECISION = 76; + public static final MathContext MATH_CONTEXT = new MathContext(MAX_PRECISION, RoundingMode.HALF_EVEN); + + private final Numeric zeroValue; + + public Decimal256Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + zeroValue = Numeric.create(new BigDecimal(BigInteger.ZERO, descriptor.getPrecision(), MATH_CONTEXT)); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new GenericDecimalColumnReader(nRows, descriptor, MATH_CONTEXT); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new GenericDecimalColumnWriter(data, descriptor, columnIndex); + } + + public Object nullValue() { + return zeroValue; + } + + @Override + public Object[] emptyArray() { + return Decimal128Column.EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32Column.java new file mode 100644 index 000000000..8d87167c6 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32Column.java @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.List; + +public class Decimal32Column extends ClickhouseColumn { + public static final int ELEMENT_SIZE = 4; + public static final int MAX_PRECISION = 9; + public final static MathContext MATH_CONTEXT = new MathContext(MAX_PRECISION, RoundingMode.HALF_EVEN); + + private final Numeric zeroValue; + + public Decimal32Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + zeroValue = Numeric.create(new BigDecimal(BigInteger.ZERO, descriptor.getPrecision(), MATH_CONTEXT)); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new Decimal32ColumnReader(nRows, descriptor, MATH_CONTEXT); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new Decimal32ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return zeroValue; + } + + @Override + public Object[] emptyArray() { + return Decimal128Column.EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32ColumnReader.java new file mode 100644 index 000000000..20d805e61 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32ColumnReader.java @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; + +public class Decimal32ColumnReader extends ClickhouseColumnReader { + private final MathContext mc; + + protected Decimal32ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor, MathContext mc) { + super(nRows, columnDescriptor); + this.mc = mc; + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= Decimal32Column.ELEMENT_SIZE * nRows) { + Numeric[] data = new Numeric[nRows]; + int scale = columnDescriptor.getScale(); + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + int item = in.readIntLE(); + data[i] = Numeric.create(new BigDecimal(BigInteger.valueOf(item), scale, mc)); + } else { + in.skipBytes(Decimal32Column.ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new Numeric[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new Numeric[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32ColumnWriter.java new file mode 100644 index 000000000..c17dc2d29 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal32ColumnWriter.java @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; + +public class Decimal32ColumnWriter extends ClickhouseColumnWriter { + public Decimal32ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + BigDecimal bd = ((Numeric) val).bigDecimalValue(); + if (bd == null) { + serializeDataNull(sink); + return; + } + ColumnUtils.bigDecimalFitsOrThrow(bd, columnDescriptor); + BigInteger bi = bd.unscaledValue(); + sink.writeIntLE(bi.intValueExact()); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(Decimal32Column.ELEMENT_SIZE); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64Column.java new file mode 100644 index 000000000..3d9e54cb3 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64Column.java @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.List; + +public class Decimal64Column extends ClickhouseColumn { + public static final int ELEMENT_SIZE = 8; + public static final int MAX_PRECISION = 18; + public static final MathContext MATH_CONTEXT = new MathContext(MAX_PRECISION, RoundingMode.HALF_EVEN); + private final Numeric zeroValue; + + public Decimal64Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + zeroValue = Numeric.create(new BigDecimal(BigInteger.ZERO, descriptor.getPrecision(), MATH_CONTEXT)); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new Decimal64ColumnReader(nRows, descriptor, MATH_CONTEXT); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new Decimal64ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return zeroValue; + } + + @Override + public Object[] emptyArray() { + return Decimal128Column.EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64ColumnReader.java new file mode 100644 index 000000000..7c346b4c3 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64ColumnReader.java @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; + +public class Decimal64ColumnReader extends ClickhouseColumnReader { + private final MathContext mc; + + protected Decimal64ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor, MathContext mathContext) { + super(nRows, columnDescriptor); + this.mc = mathContext; + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= Decimal64Column.ELEMENT_SIZE * nRows) { + Numeric[] data = new Numeric[nRows]; + int scale = columnDescriptor.getScale(); + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + long item = in.readLongLE(); + data[i] = Numeric.create(new BigDecimal(BigInteger.valueOf(item), scale, mc)); + } else { + in.skipBytes(Decimal64Column.ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new Numeric[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new Numeric[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64ColumnWriter.java new file mode 100644 index 000000000..dcd317708 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Decimal64ColumnWriter.java @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; + +public class Decimal64ColumnWriter extends ClickhouseColumnWriter { + public Decimal64ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + BigDecimal bd = ((Numeric) val).bigDecimalValue(); + if (bd == null) { + serializeDataNull(sink); + return; + } + ColumnUtils.bigDecimalFitsOrThrow(bd, columnDescriptor); + BigInteger bi = bd.unscaledValue(); + sink.writeLongLE(bi.longValueExact()); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(Decimal64Column.ELEMENT_SIZE); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16Column.java new file mode 100644 index 000000000..41e4a33c6 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16Column.java @@ -0,0 +1,41 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; +import java.util.Map; + +public class Enum16Column extends UInt16Column { + private final Map enumVals; + private final EnumResolutionMethod resolutionMethod; + + public Enum16Column(ClickhouseBinaryColumnDescriptor descriptor, Map enumVals, EnumResolutionMethod resolutionMethod) { + super(descriptor); + this.enumVals = enumVals; + this.resolutionMethod = resolutionMethod; + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new Enum16ColumnReader(nRows, descriptor, enumVals, resolutionMethod); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new Enum16ColumnWriter(data, descriptor, columnIndex, enumVals, resolutionMethod); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16ColumnReader.java new file mode 100644 index 000000000..b31b0e40d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16ColumnReader.java @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +import java.util.Map; + +public class Enum16ColumnReader extends SignedInt16ColumnReader implements EnumColumnReader { + public static final int ELEMENT_SIZE = 2; + private final EnumColumnDecoder columnRecoder; + + public Enum16ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descr, Map enumVals, EnumResolutionMethod resolutionMethod) { + super(nRows, descr); + this.columnRecoder = new EnumColumnDecoder(enumVals, resolutionMethod); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + Short key = (Short) super.getElementInternal(rowIdx, desired); + return columnRecoder.recodeElement(key, desired); + } + + @Override + public Object[] recodeValues(Object[] src, Class desired) { + return columnRecoder.recodeValues(src, desired); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired != null && desired.isEnum()) { + return (Object[]) java.lang.reflect.Array.newInstance(desired, dim1, dim2); + } + return super.allocateTwoDimArray(desired, dim1, dim2); + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired != null && desired.isEnum()) { + return java.lang.reflect.Array.newInstance(desired, length); + } + return super.allocateOneDimArray(desired, length); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16ColumnWriter.java new file mode 100644 index 000000000..89e802584 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum16ColumnWriter.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; +import java.util.Map; + +public class Enum16ColumnWriter extends UInt16ColumnWriter { + private final EnumColumnEncoder columnEncoder; + + public Enum16ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex, + Map enumVals, EnumResolutionMethod resolutionMethod) { + super(data, columnDescriptor, columnIndex); + this.columnEncoder = new EnumColumnEncoder(enumVals, resolutionMethod); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + Number idx = columnEncoder.encode(val); + super.serializeDataElement(sink, idx); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8Column.java new file mode 100644 index 000000000..b5344b0b9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8Column.java @@ -0,0 +1,41 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; +import java.util.Map; + +public class Enum8Column extends UInt8Column { + private final Map enumVals; + private final EnumResolutionMethod resolutionMethod; + + public Enum8Column(ClickhouseBinaryColumnDescriptor descriptor, Map enumVals, EnumResolutionMethod resolutionMethod) { + super(descriptor); + this.enumVals = enumVals; + this.resolutionMethod = resolutionMethod; + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new Enum8ColumnReader(nRows, descriptor, enumVals, resolutionMethod); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new Enum8ColumnWriter(data, descriptor, columnIndex, enumVals, resolutionMethod); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8ColumnReader.java new file mode 100644 index 000000000..48e61c861 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8ColumnReader.java @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +import java.util.Map; + +public class Enum8ColumnReader extends SignedInt8ColumnReader implements EnumColumnReader { + public static final int ELEMENT_SIZE = 1; + private final EnumColumnDecoder columnRecoder; + + public Enum8ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descr, Map enumVals, EnumResolutionMethod resolutionMethod) { + super(nRows, descr); + this.columnRecoder = new EnumColumnDecoder(enumVals, resolutionMethod); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + Byte key = (Byte) super.getElementInternal(rowIdx, desired); + return columnRecoder.recodeElement(key, desired); + } + + @Override + public Object[] recodeValues(Object[] src, Class desired) { + return columnRecoder.recodeValues(src, desired); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired != null && desired.isEnum()) { + return (Object[]) java.lang.reflect.Array.newInstance(desired, dim1, dim2); + } + return super.allocateTwoDimArray(desired, dim1, dim2); + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired != null && desired.isEnum()) { + return java.lang.reflect.Array.newInstance(desired, length); + } + return super.allocateOneDimArray(desired, length); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8ColumnWriter.java new file mode 100644 index 000000000..ea518220e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Enum8ColumnWriter.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; +import java.util.Map; + +public class Enum8ColumnWriter extends UInt8ColumnWriter { + private final EnumColumnEncoder columnEncoder; + + public Enum8ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex, + Map enumVals, EnumResolutionMethod resolutionMethod) { + super(data, columnDescriptor, columnIndex); + this.columnEncoder = new EnumColumnEncoder(enumVals, resolutionMethod); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + Number idx = columnEncoder.encode(val); + super.serializeDataElement(sink, idx); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnDecoder.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnDecoder.java new file mode 100644 index 000000000..686e680c4 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnDecoder.java @@ -0,0 +1,71 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import java.util.HashMap; +import java.util.Map; + +class EnumColumnDecoder { + private final Map enumKeyToName; + private final Map enumKeyToOrdinal; + private final EnumResolutionMethod resolutionMethod; + + EnumColumnDecoder(Map enumVals, EnumResolutionMethod resolutionMethod) { + this.enumKeyToName = enumVals; + this.resolutionMethod = resolutionMethod; + this.enumKeyToOrdinal = resolutionMethod == EnumResolutionMethod.ORDINAL ? buildEnumKeyToOrdinal(enumVals) : null; + } + + static Map buildEnumKeyToOrdinal(Map enumVals) { + Map ret = new HashMap<>(); + int idx = 0; + for (Map.Entry entry : enumVals.entrySet()) { + ret.put(entry.getKey(), idx); + ++idx; + } + return ret; + } + + public Object recodeElement(Number key, Class desired) { + if (Number.class.isAssignableFrom(desired)) { + return key; + } + String str = enumKeyToName.get(key); + if (desired.isEnum()) { + if (resolutionMethod == EnumResolutionMethod.NAME) { + return Enum.valueOf(desired, str); + } else if (resolutionMethod == EnumResolutionMethod.KEY) { + return desired.getEnumConstants()[key.intValue()]; + } else { + return desired.getEnumConstants()[enumKeyToOrdinal.get(key)]; + } + } + return str; + } + + Object[] recodeValues(Object[] src, Class desired) { + Number[] bytes = (Number[])src; + if (desired == Object.class) { + desired = String.class; + } + Object[] ret = (Object[]) java.lang.reflect.Array.newInstance(desired, src.length); + for (int idx = 0; idx < ret.length; ++idx) { + Number el = bytes[idx]; + if (el != null) { + ret[idx] = recodeElement(el, desired); + } + } + return ret; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnEncoder.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnEncoder.java new file mode 100644 index 000000000..ab5fc3302 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnEncoder.java @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import java.util.HashMap; +import java.util.Map; + +public class EnumColumnEncoder { + private final Number[] enumOrdinalToKey; + private final Map enumNameToKey; + private final EnumResolutionMethod resolutionMethod; + + public EnumColumnEncoder(Map enumKeyToName, EnumResolutionMethod resolutionMethod) { + this.resolutionMethod = resolutionMethod; + this.enumNameToKey = resolutionMethod == EnumResolutionMethod.NAME ? buildReverseIndex(enumKeyToName) : null; + this.enumOrdinalToKey = resolutionMethod == EnumResolutionMethod.NAME ? null : enumOrdinalToKey(enumKeyToName); + } + + private Number[] enumOrdinalToKey(Map enumVals) { + Number[] ret = new Number[enumVals.size()]; + int idx = 0; + for (Map.Entry entry:enumVals.entrySet()) { + ret[idx] = entry.getKey(); + ++idx; + } + return ret; + } + + private Map buildReverseIndex(Map enumVals) { + Map ret = new HashMap<>(); + for (Map.Entry entry : enumVals.entrySet()) { + ret.put(entry.getValue(), entry.getKey()); + } + return ret; + } + + public Number encode(Object val) { + Number key; + if (val.getClass() == String.class) { + key = enumNameToKey.get(val); + } else if (val.getClass().isEnum()) { + Enum enumVal = (Enum) val; + if (resolutionMethod == EnumResolutionMethod.NAME) { + key = enumNameToKey.get(enumVal.name()); + } else { + int ordinal = enumVal.ordinal(); + if (ordinal < enumOrdinalToKey.length) { + key = enumOrdinalToKey[ordinal]; + } else { + throw new IllegalArgumentException("ordinal " + ordinal + " for enum val " + enumVal + " is too big, max " + (enumOrdinalToKey.length - 1)); + } + } + } else if (val instanceof Number) { + key = (Number) val; + } else { + throw new IllegalArgumentException("don't know how to serialize " + val + " of class " + val.getClass()); + } + if (key == null) { + throw new IllegalArgumentException(val + " is not in dictionary; possible values: " + enumNameToKey.keySet()); + } + return key; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnReader.java new file mode 100644 index 000000000..e324651d0 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumColumnReader.java @@ -0,0 +1,18 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +public interface EnumColumnReader { + Object[] recodeValues(Object[] src, Class desired); +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumResolutionMethod.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumResolutionMethod.java new file mode 100644 index 000000000..2c97d2a27 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/EnumResolutionMethod.java @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import java.util.Arrays; +import java.util.Map; +import java.util.stream.Collectors; + +public enum EnumResolutionMethod { + NAME("by_name"), ORDINAL("by_ordinal"), KEY("by_key_as_ordinal"); + private static final Map index = Arrays + .stream(EnumResolutionMethod.values()) + .collect(Collectors.toMap(el -> el.optVal, el -> el)); + + String optVal; + + EnumResolutionMethod(String optVal) { + this.optVal = optVal; + } + + public static EnumResolutionMethod forOpt(String optVal) { + EnumResolutionMethod ret = index.get(optVal); + if (ret == null) { + throw new IllegalArgumentException("unknown option value " + optVal); + } + return ret; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumn.java new file mode 100644 index 000000000..624ea8407 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumn.java @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class FixedStringColumn extends ClickhouseColumn { + protected final ClickhouseBinaryDatabaseMetadata md; + private final boolean enableStringCache; + + public FixedStringColumn(ClickhouseBinaryColumnDescriptor descriptor, ClickhouseBinaryDatabaseMetadata md, boolean enableStringCache) { + super(descriptor); + this.md = md; + this.enableStringCache = enableStringCache; + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new FixedStringColumnReader(nRows, descriptor, enableStringCache, md); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new FixedStringColumnWriter(data, descriptor, md.getStringCharset(), columnIndex); + } + + @Override + public Object nullValue() { + return StringColumn.ZERO_VALUE; + } + + @Override + public Object[] emptyArray() { + return StringColumn.EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumnReader.java new file mode 100644 index 000000000..13018f368 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumnReader.java @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +public class FixedStringColumnReader extends ClickhouseColumnReader { + private final Charset charset; + private final boolean removeTrailingZerosInStrings; + private final boolean enableStringCache; + private final StringCache cache; + + private List elements; + + protected FixedStringColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor, boolean enableStringCache, ClickhouseBinaryDatabaseMetadata md) { + super(nRows, columnDescriptor); + this.elements = new ArrayList<>(nRows); + this.charset = md.getStringCharset(); + this.removeTrailingZerosInStrings = md.isRemoveTrailingZerosInFixedStrings(); + this.enableStringCache = enableStringCache; + this.cache = enableStringCache ? new StringCache(nRows) : null; + } + + @Override + protected Object[] readItems(ClickhouseStreamDataSource in) { + int elementSize = columnDescriptor.getElementSize(); + while (elements.size() < nRows) { + if (in.readableBytes() < elementSize) { + return null; + } + byte[] stringBytes; + if (nullsMap == null || !nullsMap.get(elements.size())) { + stringBytes = new byte[elementSize]; + in.readBytes(stringBytes); + } else { + in.skipBytes(elementSize); + stringBytes = null; + } + elements.add(stringBytes); + } + Object[] ret = elements.toArray(new byte[elements.size()][]); + elements = null; + return ret; + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + Object tmp = getObjectsArrayElement(rowIdx); + if ((desired == String.class || desired == Object.class) && tmp != null) { + return enableStringCache ? cache.get(rowIdx, () -> buildStringFromElement((byte[]) tmp)) : buildStringFromElement((byte[]) tmp); + } + return tmp; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == byte[].class) { + return new byte[dim1][dim2][]; + } + return new String[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == byte[].class) { + return new byte[length][]; + } + return new String[length]; + } + + private String buildStringFromElement(byte[] tmp) { + int lastNonZeroIdx = removeTrailingZerosInStrings ? ColumnUtils.getLastNonZeroPos(tmp) : tmp.length - 1; + return new String(tmp, 0, lastNonZeroIdx + 1, charset); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumnWriter.java new file mode 100644 index 000000000..a6b2f3d0b --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/FixedStringColumnWriter.java @@ -0,0 +1,46 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.nio.charset.Charset; +import java.util.List; + +public class FixedStringColumnWriter extends ClickhouseColumnWriter { + private final Charset charset; + + public FixedStringColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, Charset charset, int columnIndex) { + super(data, columnDescriptor, columnIndex); + this.charset = charset; + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + byte[] bytes = val.getClass() == byte[].class ? (byte[])val : ((String)val).getBytes(charset); + int elSize = columnDescriptor.getElementSize(); + if (bytes.length > elSize) { + throw new IllegalArgumentException("fixed string bytes are too long: got " + bytes.length + ", max " + elSize); + } + sink.writeBytes(bytes); + sink.writeZero(elSize - bytes.length); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(columnDescriptor.getElementSize()); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32Column.java new file mode 100644 index 000000000..d07a9e3ca --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32Column.java @@ -0,0 +1,48 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class Float32Column extends ClickhouseColumn { + public static final Float[] EMPTY_FLOAT_ARRAY = new Float[0]; + public static final Float ZERO_VALUE = 0.0f; + + public Float32Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new Float32ColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new Float32ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return ZERO_VALUE; + } + + @Override + public Object[] emptyArray() { + return EMPTY_FLOAT_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32ColumnReader.java new file mode 100644 index 000000000..f6cc6f4d9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32ColumnReader.java @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +public class Float32ColumnReader extends ClickhouseColumnReader { + public static final int ELEMENT_SIZE = 4; + + protected Float32ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= ELEMENT_SIZE * nRows) { + float[] data = new float[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + data[i] = in.readFloatLE(); + } else { + in.skipBytes(ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new Float[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new Float[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32ColumnWriter.java new file mode 100644 index 000000000..b74a82b53 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float32ColumnWriter.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class Float32ColumnWriter extends ClickhouseColumnWriter { + public Float32ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + float b = ((Number)val).floatValue(); + sink.writeFloatLE(b); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeFloatLE(0); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64Column.java new file mode 100644 index 000000000..4f540dc7e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64Column.java @@ -0,0 +1,47 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class Float64Column extends ClickhouseColumn { + public static final Double[] EMPTY_FLOAT_ARRAY = new Double[0]; + public static final Double ZERO_DOUBLE = 0d; + + public Float64Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new Float64ColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new Float64ColumnWriter(data, descriptor, columnIndex); + } + + public Object nullValue() { + return ZERO_DOUBLE; + } + + @Override + public Object[] emptyArray() { + return EMPTY_FLOAT_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64ColumnReader.java new file mode 100644 index 000000000..e42264c94 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64ColumnReader.java @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + + +public class Float64ColumnReader extends ClickhouseColumnReader { + public static final int ELEMENT_SIZE = 8; + + protected Float64ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= ELEMENT_SIZE * nRows) { + double[] data = new double[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + data[i] = in.readDoubleLE(); + } else { + in.skipBytes(ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new Double[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new Double[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64ColumnWriter.java new file mode 100644 index 000000000..a60bde693 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Float64ColumnWriter.java @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class Float64ColumnWriter extends ClickhouseColumnWriter { + public Float64ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + Number number = (Number)val; + double b = number.doubleValue(); + sink.writeDoubleLE(b); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeDoubleLE(0); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/GenericDecimalColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/GenericDecimalColumnReader.java new file mode 100644 index 000000000..8f28560f2 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/GenericDecimalColumnReader.java @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; + +public class GenericDecimalColumnReader extends ClickhouseColumnReader { + private final MathContext mc; + + protected GenericDecimalColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor, MathContext mathContext) { + super(nRows, columnDescriptor); + this.mc = mathContext; + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + int elementSize = columnDescriptor.getElementSize(); + if (in.readableBytes() >= elementSize * nRows) { + Numeric[] data = new Numeric[nRows]; + int scale = columnDescriptor.getScale(); + byte[] readBuffer = new byte[elementSize]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + in.readBytes(readBuffer); + BigInteger bi = new BigInteger(ColumnUtils.reverse(readBuffer)); + data[i] = Numeric.create(new BigDecimal(bi, scale, mc)); + } else { + in.skipBytes(elementSize); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new Numeric[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new Numeric[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/GenericDecimalColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/GenericDecimalColumnWriter.java new file mode 100644 index 000000000..da07fc556 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/GenericDecimalColumnWriter.java @@ -0,0 +1,88 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.List; + +public class GenericDecimalColumnWriter extends ClickhouseColumnWriter { + private final BigInteger negAddon; + + public GenericDecimalColumnWriter(List data, ClickhouseBinaryColumnDescriptor descriptor, int columnIndex) { + super(data, descriptor, columnIndex); + this.negAddon = BigInteger.ONE.shiftLeft(columnDescriptor.getElementSize() * 8); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + BigDecimal bd = ((Numeric) val).bigDecimalValue(); + if (bd == null) { + serializeDataNull(sink); + return; + } + ColumnUtils.bigDecimalFitsOrThrow(bd, columnDescriptor); + BigInteger bi = bd.unscaledValue(); + boolean negative = bi.signum() == -1; + if (negative) { + bi = bi.add(negAddon); + } + byte[] bytes = ColumnUtils.reverse(bi.toByteArray()); + sink.writeBytes(bytes, 0, negative ? bytes.length - 1 : bytes.length); + int extraZeros = negative ? 0 : columnDescriptor.getElementSize() - bytes.length; + sink.writeZero(extraZeros); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(columnDescriptor.getElementSize()); + } + + private static void traceBytes(byte[] bytes) { + for (byte b : bytes) { + System.err.print(Integer.toHexString(Byte.toUnsignedInt(b))); + System.err.print(","); + } + System.err.println(); + } + + public static BigInteger parseBigIntegerPositive(String num, int bitlen) { + BigInteger b = new BigInteger(num); + if (b.compareTo(BigInteger.ZERO) < 0) + b = b.add(BigInteger.ONE.shiftLeft(bitlen)); + return b; + } + + public static void main(String[] args) { + BigInteger bi = parseBigIntegerPositive("-2", 16); + System.err.println(bi); + System.err.println("bytes1:"); + traceBytes(bi.toByteArray()); + System.err.println("bytes2:"); + traceBytes(BigInteger.valueOf(65534).toByteArray()); + + BigInteger bi2 = parseBigIntegerPositive("-1", 16); + System.err.println("bytes3_1"); + traceBytes(bi2.toByteArray()); + + bi2 = parseBigIntegerPositive("-1", 15); + System.err.println("bytes3_2"); + traceBytes(bi2.toByteArray()); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4Column.java new file mode 100644 index 000000000..fef8da972 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4Column.java @@ -0,0 +1,62 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.net.Inet4Address; +import java.net.UnknownHostException; +import java.util.List; + +public class IPv4Column extends UInt32Column { + public static final int ELEMENT_SIZE = 4; + public static final Inet4Address[] EMPTY_ARRAY = new Inet4Address[0]; + + public static final Inet4Address ZERO_VALUE = ipv4(new byte[]{0, 0, 0, 0}); + public static final Inet4Address MAX_VALUE = ipv4(new byte[]{Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE}); + public static final Inet4Address MIN_VALUE = ipv4(new byte[]{Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE}); + + private static Inet4Address ipv4(byte[] src) { + try { + return (Inet4Address) Inet4Address.getByAddress(src); + } catch (UnknownHostException ex) { + throw new RuntimeException(ex); + } + } + + public IPv4Column(ClickhouseBinaryColumnDescriptor descr) { + super(descr); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new IPv4ColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new IPv4ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return ZERO_VALUE; + } + + @Override + public Object[] emptyArray() { + return EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4ColumnReader.java new file mode 100644 index 000000000..b7393559d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4ColumnReader.java @@ -0,0 +1,65 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class IPv4ColumnReader extends UnsignedInt32ColumnReader { + + public IPv4ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descriptor) { + super(nRows, descriptor); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + if (desired == InetAddress.class || desired == Inet4Address.class || desired == Object.class || desired == null) { + Long addr = (Long) super.getElementInternal(rowIdx, byte[].class); + try { + return Inet4Address.getByAddress(intBytes(addr)); + } catch (UnknownHostException ex) { + throw new RuntimeException(ex); + } + } + return super.getElementInternal(rowIdx, desired); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == InetAddress.class || desired == Inet4Address.class || desired == Object.class || desired == null) { + return new Inet4Address[dim1][dim2]; + } + return super.allocateTwoDimArray(desired, dim1, dim2); + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == InetAddress.class || desired == Inet4Address.class || desired == Object.class || desired == null) { + return new Inet4Address[length]; + } + return super.allocateOneDimArray(desired, length); + } + + private static byte[] intBytes(Long l) { + return new byte[] { + (byte) (l >>> 24 & 0xFF), + (byte) (l >>> 16 & 0xFF), + (byte) (l >>> 8 & 0xFF), + (byte) (l & 0xFF) + }; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4ColumnWriter.java new file mode 100644 index 000000000..f3744fb63 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv4ColumnWriter.java @@ -0,0 +1,36 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.net.Inet4Address; +import java.util.List; + +public class IPv4ColumnWriter extends UInt32ColumnWriter { + public IPv4ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + Inet4Address addr = (Inet4Address) val; + super.serializeDataElement(sink, Integer.toUnsignedLong(intFromBytes(addr.getAddress()))); + } + + private static int intFromBytes(byte[] b) { + return (0xFF000000 & (b[0] << 24)) | (0xFF0000 & (b[1] << 16)) | (0xFF00 & (b[2] << 8)) | (0xFF & (b[3])); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6Column.java new file mode 100644 index 000000000..9aa5cb173 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6Column.java @@ -0,0 +1,73 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.net.Inet6Address; +import java.net.UnknownHostException; +import java.util.List; + +public class IPv6Column extends FixedStringColumn { + public static final int ELEMENT_SIZE = 16; + public static final Inet6Address EMPTY_ARRAY[] = new Inet6Address[0]; + + public static final Inet6Address ZERO_VALUE = ipv6(new byte[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + public static final Inet6Address MIN_VALUE = ipv6(new byte[]{ + Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE, + Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE, + Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE, + Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE, Byte.MIN_VALUE + }); + public static final Inet6Address MAX_VALUE = ipv6(new byte[]{ + Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, + Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, + Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, + Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE, Byte.MAX_VALUE + }); + + private static Inet6Address ipv6(byte[] src) { + try { + return (Inet6Address) Inet6Address.getByAddress(src); + } catch (UnknownHostException ex) { + throw new RuntimeException(ex); + } + } + + public IPv6Column(ClickhouseBinaryColumnDescriptor descr, ClickhouseBinaryDatabaseMetadata md) { + super(descr, md, false); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new IPv6ColumnReader(nRows, descriptor, md); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new IPv6ColumnWriter(data, descriptor, md.getStringCharset(), columnIndex); + } + + @Override + public Object nullValue() { + return ZERO_VALUE; + } + + @Override + public Object[] emptyArray() { + return EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6ColumnReader.java new file mode 100644 index 000000000..929eceecf --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6ColumnReader.java @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; + +public class IPv6ColumnReader extends FixedStringColumnReader { + + protected IPv6ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor, ClickhouseBinaryDatabaseMetadata md) { + super(nRows, columnDescriptor, false, md); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + if (desired == InetAddress.class || desired == Inet6Address.class || desired == Object.class || desired == null) { + byte[] addr = (byte[]) super.getElementInternal(rowIdx, byte[].class); + try { + return Inet6Address.getByAddress(addr); + } catch (UnknownHostException ex) { + throw new RuntimeException(ex); + } + } + return super.getElementInternal(rowIdx, desired); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == InetAddress.class || desired == Inet6Address.class || desired == Object.class || desired == null) { + return new Inet6Address[dim1][dim2]; + } + return super.allocateTwoDimArray(desired, dim1, dim2); + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == InetAddress.class || desired == Inet6Address.class || desired == Object.class || desired == null) { + return new Inet6Address[length]; + } + return super.allocateOneDimArray(desired, length); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6ColumnWriter.java new file mode 100644 index 000000000..a76d37bd2 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IPv6ColumnWriter.java @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.net.Inet6Address; +import java.nio.charset.Charset; +import java.util.List; + +public class IPv6ColumnWriter extends FixedStringColumnWriter { + public IPv6ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, Charset charset, int columnIndex) { + super(data, columnDescriptor, charset, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + Inet6Address address = (Inet6Address) val; + byte[] bytes = address.getAddress(); + super.serializeDataElement(sink, bytes); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(IPv6Column.ELEMENT_SIZE); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128Column.java new file mode 100644 index 000000000..f1c0051be --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128Column.java @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.math.BigInteger; +import java.util.List; + +public class Int128Column extends ClickhouseColumn { + public static final int ELEMENT_SIZE = 16; + public static final BigInteger[] EMPTY_ARRAY = new BigInteger[0]; + + public static final BigInteger ZERO_VALUE = new BigInteger(new byte[ELEMENT_SIZE]); + public static final BigInteger INT128_MIN_VALUE = new BigInteger("-170141183460469231731687303715884105728"); + public static final BigInteger INT128_MAX_VALUE = new BigInteger( "170141183460469231731687303715884105727"); + + public Int128Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new Int128ColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new Int128ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return ZERO_VALUE; + } + + @Override + public Object[] emptyArray() { + return EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128ColumnReader.java new file mode 100644 index 000000000..8842d339e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128ColumnReader.java @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.math.BigInteger; + +//experimental support at the moment +public class Int128ColumnReader extends ClickhouseColumnReader { + protected Int128ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= Int128Column.ELEMENT_SIZE * nRows) { + BigInteger[] data = new BigInteger[nRows]; + byte[] readBuffer = new byte[Int128Column.ELEMENT_SIZE]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + in.readBytes(readBuffer); + data[i] = new BigInteger(ColumnUtils.reverse(readBuffer)); + } else { + in.skipBytes(Int128Column.ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return ((BigInteger[]) this.itemsArray)[rowIdx]; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new BigInteger[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new BigInteger[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128ColumnWriter.java new file mode 100644 index 000000000..b5306e1f9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Int128ColumnWriter.java @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.math.BigInteger; +import java.util.List; + +public class Int128ColumnWriter extends ClickhouseColumnWriter { + public Int128ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + BigInteger bi = (BigInteger) val; + byte[] bytes = ColumnUtils.reverse(bi.toByteArray()); + sink.writeBytes(bytes); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(Int128Column.ELEMENT_SIZE); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntPairIterator.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntPairIterator.java new file mode 100644 index 000000000..c75d0ba0d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntPairIterator.java @@ -0,0 +1,43 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +public interface IntPairIterator { + IntPairIterator EMPTY = new IntPairIterator() { + @Override + public boolean hasNext() { + return false; + } + + @Override + public void next() { + throw new IllegalStateException(); + } + + @Override + public int getKey() { + throw new IllegalStateException(); + } + + @Override + public int getValue() { + throw new IllegalStateException(); + } + }; + + boolean hasNext(); + void next(); + int getKey(); + int getValue(); +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntervalColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntervalColumn.java new file mode 100644 index 000000000..ab174a4d7 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntervalColumn.java @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.time.Duration; +import java.util.List; + +public class IntervalColumn extends ClickhouseColumn { + public static final Duration[] EMPTY_ARRAY = new Duration[0]; + + public static final Duration ZERO_VALUE = Duration.ZERO; + private final Duration multiplier; + + public IntervalColumn(ClickhouseBinaryColumnDescriptor descriptor, Duration multiplier) { + super(descriptor); + this.multiplier = multiplier; + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new IntervalColumnReader(nRows, descriptor, multiplier); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + throw new IllegalStateException("not implemented"); + } + + @Override + public Object nullValue() { + return ZERO_VALUE; + } + + @Override + public Object[] emptyArray() { + return EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntervalColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntervalColumnReader.java new file mode 100644 index 000000000..c561d459e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/IntervalColumnReader.java @@ -0,0 +1,52 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +import java.time.Duration; + +public class IntervalColumnReader extends SignedInt64ColumnReader { + private final Duration multiplier; + + public IntervalColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descriptor, Duration multiplier) { + super(nRows, descriptor); + this.multiplier = multiplier; + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + Long obj = (Long)super.getElementInternal(rowIdx, desired); + if (desired != Duration.class) { + return obj; + } + return multiplier.multipliedBy(obj); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == Duration.class) { + return new Duration[dim1][dim2]; + } + return super.allocateTwoDimArray(desired, dim1, dim2); + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == Duration.class) { + return new Duration[length]; + } + return super.allocateOneDimArray(desired, length); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ListPairedIterator.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ListPairedIterator.java new file mode 100644 index 000000000..0144eabb3 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ListPairedIterator.java @@ -0,0 +1,40 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import java.util.AbstractMap; +import java.util.Iterator; +import java.util.Map; + +public class ListPairedIterator implements Iterator> { + private final Iterator wrapped1; + private final Iterator wrapped2; + + public ListPairedIterator(Iterator wrapped1, Iterator wrapped2) { + this.wrapped1 = wrapped1; + this.wrapped2 = wrapped2; + } + + @Override + public boolean hasNext() { + return wrapped1.hasNext() && wrapped2.hasNext(); + } + + @Override + public Map.Entry next() { + T key = wrapped1.next(); + T val = wrapped2.next(); + return new AbstractMap.SimpleEntry<>(key, val); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumn.java new file mode 100644 index 000000000..e6283b125 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumn.java @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class LowCardinalityColumn extends ClickhouseColumn { + private final ClickhouseBinaryColumnDescriptor indexDescriptor; + private final ClickhouseColumn indexColumn; + private final ClickhouseBinaryDatabaseMetadata md; + + public LowCardinalityColumn(ClickhouseBinaryColumnDescriptor descriptor, ClickhouseBinaryDatabaseMetadata md) { + super(descriptor); + this.md = md; + this.indexDescriptor = descriptor.copyWithModifiers(false, false); + this.indexColumn = ClickhouseColumns.columnForSpec(indexDescriptor, md); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new LowCardinalityColumnReader(nRows, descriptor, indexDescriptor, md); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new LowCardinalityColumnWriter(data, descriptor, md, columnIndex); + } + + @Override + public Object nullValue() { + return indexColumn.nullValue(); + } + + @Override + public Object[] emptyArray() { + return indexColumn.emptyArray(); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumnReader.java new file mode 100644 index 000000000..6039fbd2b --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumnReader.java @@ -0,0 +1,149 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.util.BitSet; + +public class LowCardinalityColumnReader extends ClickhouseColumnReader { + public static final long SUPPORTED_SERIALIZATION_VERSION = 1; + + private static final ClickhouseColumn[] KEY_COLUMNS = new ClickhouseColumn[] { + ClickhouseColumns.columnForSpec("UInt8", "lcKeyColumn", null), + ClickhouseColumns.columnForSpec("UInt16", "lcKeyColumn", null), + ClickhouseColumns.columnForSpec("UInt32", "lcKeyColumn", null), + ClickhouseColumns.columnForSpec("UInt64", "lcKeyColumn", null) + }; + public static final Object[] EMPTY_ARRAY = new Object[0]; + + private final ClickhouseBinaryColumnDescriptor indexDescr; + private final ClickhouseBinaryDatabaseMetadata md; + private ClickhouseColumnReader indexColumn; + private Long serType; + private Long indexSize; + private Long nKeys; + Long keysSerializationVersion; + + private ClickhouseColumnReader keysColumn; + + public LowCardinalityColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descr, ClickhouseBinaryColumnDescriptor indexColumn, ClickhouseBinaryDatabaseMetadata md) { + super(nRows, descr); + this.indexDescr = indexColumn; + this.md = md; + } + + @Override + protected Object readStatePrefix(ClickhouseStreamDataSource in) { + if (keysSerializationVersion == null) { + if (in.readableBytes() >= 4) { + keysSerializationVersion = in.readLongLE(); + if (keysSerializationVersion != SUPPORTED_SERIALIZATION_VERSION) { + throw new IllegalStateException("unsupported keysSerializationVersion: " + keysSerializationVersion); + } + } + } + return keysSerializationVersion; + } + + @Override + protected BitSet readNullsMap(ClickhouseStreamDataSource in) { + return null; + } + + @Override + protected void readData(ClickhouseStreamDataSource in) { + if (keysSerializationVersion == null) { + return; + } + if (indexSize == null) { + if (in.readableBytes() < 8 + 8) { + return; + } + serType = in.readLongLE(); + indexSize = in.readLongLE(); + } + if (indexSize > Integer.MAX_VALUE) { + throw new IllegalArgumentException("low cardinality index is too big (" + indexSize + "), max " + Integer.MAX_VALUE); + } + if (indexColumn == null) { + int sz = indexSize.intValue(); + indexColumn = ClickhouseColumns.columnForSpec(indexDescr, md, true).reader(sz); + } + if (indexColumn.isPartial()) { + indexColumn.readColumn(in); + if (indexColumn.isPartial()) { + return; + } + } + if (nKeys == null) { + if (in.readableBytes() < 8) { + return; + } + nKeys = in.readLongLE(); + } + int keyType = (int)(serType & 0xf); + if (keysColumn == null) { + keysColumn = uintColumn(keyType).reader(nRows); + } + keysColumn.readColumn(in); + itemsArray = EMPTY_ARRAY; + } + + //called by Array column + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (isPartial()) { + readData(in); + if (isPartial()) { + return null; + } + } + return itemsArray; + } + + @Override + public boolean isPartial() { + return indexSize == null || indexColumn.isPartial() || nKeys == null || keysColumn.isPartial(); + } + + @Override + public Object getElement(int rowIdx, Class desired) { + int key = ((Number)keysColumn.getElement(rowIdx, Number.class)).intValue(); + if (columnDescriptor.isNullable() && key == 0) { + return null; + } + //caveat: caller may change index contents for byte[] elements + return indexColumn.getElementInternal(key, desired); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return indexColumn.allocateTwoDimArray(desired, dim1, dim2); + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return indexColumn.allocateOneDimArray(desired, length); + } + + static ClickhouseColumn uintColumn(int code) { + if (code < 0 || code >= KEY_COLUMNS.length) { + throw new IllegalArgumentException("unknown low-cardinality key-column code " + code); + } + return KEY_COLUMNS[code]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumnWriter.java new file mode 100644 index 000000000..2e1e8b86a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/LowCardinalityColumnWriter.java @@ -0,0 +1,142 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +public class LowCardinalityColumnWriter extends ClickhouseColumnWriter { + //Need to read additional keys. + //Additional keys are stored before indexes as value N and N keys + //after them. + public static final int HAS_ADDITIONAL_KEYS_BIT = 1 << 9; + // # Need to update dictionary. + // # It means that previous granule has different dictionary. + public static final int NEED_UPDATE_DICTIONARY = 1 << 10; + public static final int SERIALIZATION_TYPE = HAS_ADDITIONAL_KEYS_BIT | NEED_UPDATE_DICTIONARY; + + private final ClickhouseBinaryDatabaseMetadata md; + private Map dictionaryIndex; + private List keys; + private int nullAddon; + + public LowCardinalityColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, ClickhouseBinaryDatabaseMetadata md, int columnIndex) { + super(data, columnDescriptor, columnIndex); + this.md = md; + } + + @Override + protected void serializeStatePrefix(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + sink.writeLongLE(1); + } + + @Override + protected void serializeDataInternal(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + dictionaryIndex = new LinkedHashMap<>(); + keys = new ArrayList<>(); + ClickhouseBinaryColumnDescriptor dictionaryWriterDescr = columnDescriptor.copyWithModifiers(false, false); + ClickhouseColumn dictionaryColumn = ClickhouseColumns.columnForSpec(dictionaryWriterDescr, md); + nullAddon = columnDescriptor.isNullable() ? 1 : 0; + super.serializeDataInternal(sink, fromRow, toRow); + int dictionarySize = dictionaryIndex.size() + nullAddon; + //empty array + if (dictionarySize == 0) { + return; + } + int intType = (int) (log2(dictionarySize) / 8); + ClickhouseColumn valuesColumn = LowCardinalityColumnReader.uintColumn(intType); + + int serializationType = SERIALIZATION_TYPE | intType; + sink.writeLongLE(serializationType); + sink.writeLongLE(dictionarySize); + + Collection nullVal = columnDescriptor.isNullable() ? Collections.singleton(dictionaryColumn.nullValue()) : Collections.emptyList(); + ArrayList dictionaryTuples = Stream.concat(nullVal.stream(), dictionaryIndex.keySet().stream()) + .map(LowCardinalityColumnWriter::maybeUnwrapArrayWrapper) + .map(Tuple::of) + .collect(Collectors.toCollection(ArrayList::new)); + + ClickhouseColumnWriter dictionaryWriter = dictionaryColumn.writer(dictionaryTuples, 0); + dictionaryWriter.serializeData(sink, 0, dictionaryTuples.size()); + sink.writeLongLE(data.size()); + ClickhouseColumnWriter valuesColumnWriter = valuesColumn.writer(keys.stream().map(Tuple::of).collect(Collectors.toCollection(ArrayList::new)), 0); + valuesColumnWriter.serializeData(sink, 0, data.size()); + } + + private static Object maybeUnwrapArrayWrapper(Object from) { + if (from.getClass() == ArrayWrapper.class) { + return ((ArrayWrapper) from).array; + } + return from; + } + + private Object maybeWrapArray(Object val) { + if (val.getClass() == byte[].class) { + val = new ArrayWrapper((byte[]) val); + } else if (val.getClass() == String.class) { + //TODO: maybe introduce cache with already observed Strings to skip getBytes() or mimic String.hashCode for byte[] + val = new ArrayWrapper(((String) val).getBytes(md.getStringCharset())); + } + return val; + } + + private double log2(int x) { + return (Math.log(x) / Math.log(2)); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + val = maybeWrapArray(val); + Integer index = dictionaryIndex.computeIfAbsent(val, dictionaryMissVal -> dictionaryIndex.size() + nullAddon); + keys.add(index); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + keys.add(0); + } + + @Override + protected void serializeNullsMap(ClickhouseStreamDataSink sink, int fromRow, int toRow) { + } + + private static class ArrayWrapper { + private final byte[] array; + private final int hash; + + ArrayWrapper(byte[] array) { + this.array = array; + this.hash = Arrays.hashCode(array); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ArrayWrapper that = (ArrayWrapper) o; + return hash == that.hash && Arrays.equals(array, that.array); + } + + @Override + public int hashCode() { + return hash; + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/PairedIterator.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/PairedIterator.java new file mode 100644 index 000000000..ada29f101 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/PairedIterator.java @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class PairedIterator { + public static Iterator> of(List src) { + if (src.size() <= 1) { + return Collections.emptyIterator(); + } + + Iterator iter2 = src.iterator(); + iter2.next(); + return new ListPairedIterator<>(src.iterator(), iter2); + } + + public static IntPairIterator of(int[] src) { + if (src.length <= 1) { + return IntPairIterator.EMPTY; + } + return new ArrayIntPairIterator(src); + } + + public static void main(String[] args) { + Iterator> iter = PairedIterator.of(Arrays.asList("A", "B", "C")); + while (iter.hasNext()) { + Map.Entry n = iter.next(); + System.err.println(n.getKey() + "; " + n.getValue()); + } + + IntPairIterator iter2 = PairedIterator.of(new int[]{1, 2, 3, 4}); + while (iter2.hasNext()) { + iter2.next(); + System.err.println(iter2.getKey() + "; " + iter2.getValue()); + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt16ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt16ColumnReader.java new file mode 100644 index 000000000..848efda16 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt16ColumnReader.java @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +public class SignedInt16ColumnReader extends ClickhouseColumnReader { + public static final int ELEMENT_SIZE = 2; + + public SignedInt16ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= ELEMENT_SIZE * nRows) { + short[] data = new short[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + data[i] = in.readShortLE(); + } else { + in.skipBytes(ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return primitive(rowIdx); + } + + protected short primitive(int rowIdx) { + return ((short[]) this.itemsArray)[rowIdx]; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == short.class) { + return new short[dim1][dim2]; + } + return new Short[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == short.class) { + return new short[length]; + } + return new Short[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt32ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt32ColumnReader.java new file mode 100644 index 000000000..d0af93c5e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt32ColumnReader.java @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +public class SignedInt32ColumnReader extends ClickhouseColumnReader { + public static final int ELEMENT_SIZE = 4; + + public SignedInt32ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= ELEMENT_SIZE * nRows) { + int[] data = new int[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + data[i] = in.readIntLE(); + } else { + in.skipBytes(ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return primitive(rowIdx); + } + + protected int primitive(int rowIdx) { + return ((int[]) this.itemsArray)[rowIdx]; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == int.class) { + return new int[dim1][dim2]; + } + return new Integer[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == int.class) { + return new int[length]; + } + return new Integer[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt64ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt64ColumnReader.java new file mode 100644 index 000000000..d02e9bf8c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt64ColumnReader.java @@ -0,0 +1,83 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.math.BigInteger; + +public class SignedInt64ColumnReader extends ClickhouseColumnReader { + public static final int ELEMENT_SIZE = 8; + + public SignedInt64ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + //TODO: maybe read elements as soon as they arrive if we have enough data (> ELEMENT_SIZE) + //TODO: maybe store all fixed-size types within (direct)buffer (+WeakReference + Queue to release buffer) + if (in.readableBytes() >= ELEMENT_SIZE * nRows) { + long[] data = new long[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + data[i] = in.readLongLE(); + } else { + in.skipBytes(ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return primitive(rowIdx); + } + + protected long primitive(int rowIdx) { + return ((long[]) this.itemsArray)[rowIdx]; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == long.class) { + return new long[dim1][dim2]; + } + return new Long[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == long.class) { + return new long[length]; + } + return new Long[length]; + } + + static BigInteger unsignedBi(long l) { + return new BigInteger(1, new byte[] { + (byte) (l >>> 56 & 0xFF), + (byte) (l >>> 48 & 0xFF), + (byte) (l >>> 40 & 0xFF), + (byte) (l >>> 32 & 0xFF), + (byte) (l >>> 24 & 0xFF), + (byte) (l >>> 16 & 0xFF), + (byte) (l >>> 8 & 0xFF), + (byte) (l & 0xFF) + }); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt8ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt8ColumnReader.java new file mode 100644 index 000000000..b6b17e06a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/SignedInt8ColumnReader.java @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +public class SignedInt8ColumnReader extends ClickhouseColumnReader { + public static final int ELEMENT_SIZE = 1; + + public SignedInt8ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= ELEMENT_SIZE * nRows) { + byte[] data = new byte[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + data[i] = in.readByte(); + } else { + in.skipBytes(ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return primitive(rowIdx); + } + + protected byte primitive(int rowIdx) { + return ((byte[]) this.itemsArray)[rowIdx]; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == byte.class) { + return new byte[dim1][dim2]; + } + return new Byte[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == byte.class) { + return new byte[length]; + } + return new Byte[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringCache.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringCache.java new file mode 100644 index 000000000..481e9b056 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringCache.java @@ -0,0 +1,45 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import java.lang.ref.SoftReference; +import java.util.function.Supplier; + +public class StringCache { + private final int nElements; + private SoftReference stringCache; + + public StringCache(int nElements) { + this.nElements = nElements; + this.stringCache = new SoftReference<>(new String[nElements]); + } + + public String get(int rowIdx, Supplier supplier) { + String[] cache = stringCache.get(); + String ret; + if (cache == null) { + cache = new String[nElements]; + stringCache = new SoftReference<>(cache); + ret = supplier.get(); + cache[rowIdx] = ret; + } else { + ret = cache[rowIdx]; + if (ret == null) { + ret = supplier.get(); + cache[rowIdx] = ret; + } + } + return ret; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumn.java new file mode 100644 index 000000000..5d8ff74d9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumn.java @@ -0,0 +1,53 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class StringColumn extends ClickhouseColumn { + public static final byte[][] EMPTY_ARRAY = new byte[0][]; + public static final byte[] ZERO_VALUE = new byte[0]; + private final boolean enableStringCache; + + private final ClickhouseBinaryDatabaseMetadata md; + public StringColumn(ClickhouseBinaryColumnDescriptor descriptor, ClickhouseBinaryDatabaseMetadata md, boolean enableStringCache) { + super(descriptor); + this.md = md; + this.enableStringCache = enableStringCache; + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new StringColumnReader(nRows, descriptor, enableStringCache, md); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new StringColumnWriter(data, descriptor, md.getStringCharset(), columnIndex); + } + + @Override + public Object nullValue() { + return ZERO_VALUE; + } + + @Override + public Object[] emptyArray() { + return EMPTY_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumnReader.java new file mode 100644 index 000000000..d9f9c36fb --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumnReader.java @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +public class StringColumnReader extends ClickhouseColumnReader { + private Integer curStrLength; + private List elements; + private final Charset charset; + private final boolean enableStringCache; + private final StringCache cache; + + protected StringColumnReader(int nRows, ClickhouseBinaryColumnDescriptor descriptor, boolean enableStringCache, ClickhouseBinaryDatabaseMetadata md) { + super(nRows, descriptor); + this.elements = new ArrayList<>(nRows); + this.charset = md.getStringCharset(); + this.enableStringCache = enableStringCache; + this.cache = enableStringCache ? new StringCache(nRows) : null; + } + + @Override + protected Object[] readItems(ClickhouseStreamDataSource in) { + while (elements.size() < nRows) { + if (curStrLength == null) { + curStrLength = in.readULeb128(); + if (curStrLength == null) { + return null; + } + } + if (in.readableBytes() < curStrLength) { + return null; + } + //no dedicated BLOB type support; will encode(later) into String if user asked for String explicitly + byte[] stringBytes; + if (nullsMap == null || !nullsMap.get(elements.size())) { + stringBytes = new byte[curStrLength]; + in.readBytes(stringBytes); + } else { + stringBytes = null; + in.skipBytes(curStrLength); + } + elements.add(stringBytes); + curStrLength = null; + } + Object[] ret = elements.toArray(new byte[elements.size()][]); + elements = null; + return ret; + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + Object tmp = getObjectsArrayElement(rowIdx); + if ((desired == String.class || desired == Object.class) && tmp != null) { + return enableStringCache ? cache.get(rowIdx, () -> new String((byte[])tmp, charset)) : new String((byte[])tmp, charset); + } + return tmp; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == byte[].class) { + return new byte[dim1][dim2][]; + } + return new String[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == byte[].class) { + return new byte[length][]; + } + return new String[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumnWriter.java new file mode 100644 index 000000000..f0b179b69 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/StringColumnWriter.java @@ -0,0 +1,60 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.nio.charset.Charset; +import java.util.List; + +public class StringColumnWriter extends ClickhouseColumnWriter { + private final Charset charset; + public StringColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, Charset charset, int columnIndex) { + super(data, columnDescriptor, columnIndex); + this.charset = charset; + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + byte[] bytes = val.getClass() == byte[].class ? (byte[])val : ((String)val).getBytes(charset); + sink.writeULeb128(bytes.length); + sink.writeBytes(bytes); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeULeb128(0); + } + + protected int elementsSize(int fromRow, int toRow) { + //max value, usually less + int sz = (toRow - fromRow) * 4; + for (int i = fromRow; i < toRow; ++i) { + Object el = data.get(i).getValue(columnIndex); + if (el != null) { + if (el.getClass() == byte[].class) { + sz += ((byte[])el).length; + } else { + if (el.getClass() == String.class) { + //min value, more for non-ascii chars + sz += ((String)el).length(); + } + } + } + } + return sz; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Triplet.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Triplet.java new file mode 100644 index 000000000..a38664649 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/Triplet.java @@ -0,0 +1,38 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +public class Triplet { + private final L left; + private final M middle; + private final R right; + + public Triplet(L left, M middle, R right) { + this.left = left; + this.middle = middle; + this.right = right; + } + + public L left() { + return left; + } + + public M middle() { + return middle; + } + + public R right() { + return right; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt16Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt16Column.java new file mode 100644 index 000000000..ad2053cce --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt16Column.java @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class UInt16Column extends ClickhouseColumn { + public static final Integer[] EMPTY_INT_ARRAY = new Integer[0]; + public static final Short[] EMPTY_SHORT_ARRAY = new Short[0]; + + public UInt16Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + if (descriptor.isUnsigned()) { + return new UnsignedInt16ColumnReader(nRows, descriptor); + } + return new SignedInt16ColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new UInt16ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + if (descriptor.isUnsigned()) { + return (int) 0; + } else { + return (short) 0; + } + } + + @Override + public Object[] emptyArray() { + if (descriptor.isUnsigned()) { + return EMPTY_INT_ARRAY; + } else { + return EMPTY_SHORT_ARRAY; + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt16ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt16ColumnWriter.java new file mode 100644 index 000000000..33522d87f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt16ColumnWriter.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class UInt16ColumnWriter extends ClickhouseColumnWriter { + public UInt16ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + short b = ((Number)val).shortValue(); + sink.writeShortLE(b); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeShortLE(0); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt32Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt32Column.java new file mode 100644 index 000000000..42f3b08d1 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt32Column.java @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class UInt32Column extends ClickhouseColumn { + public static final Long[] EMPTY_LONG_ARRAY = new Long[0]; + + public UInt32Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + if (descriptor.isUnsigned()) { + return new UnsignedInt32ColumnReader(nRows, descriptor); + } + return new SignedInt32ColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new UInt32ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + if (descriptor.isUnsigned()) { + return 0L; + } + return 0; + } + + @Override + public Object[] emptyArray() { + if (descriptor.isUnsigned()) { + return EMPTY_LONG_ARRAY; + } + return UInt16Column.EMPTY_INT_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt32ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt32ColumnWriter.java new file mode 100644 index 000000000..3e1e78553 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt32ColumnWriter.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class UInt32ColumnWriter extends ClickhouseColumnWriter { + public UInt32ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + int b = ((Number)val).intValue(); + sink.writeIntLE(b); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeIntLE(0); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt64Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt64Column.java new file mode 100644 index 000000000..86ad0064b --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt64Column.java @@ -0,0 +1,59 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; + +import java.math.BigInteger; +import java.util.List; + +public class UInt64Column extends ClickhouseColumn { + public static final Numeric[] EMPTY_NUMERIC_ARRAY = new Numeric[0]; + public static final Numeric UINT64_MIN = Numeric.create(BigInteger.ZERO); + + public UInt64Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + if (descriptor.isUnsigned()) { + return new UnsignedInt64ColumnReader(nRows, descriptor); + } + return new SignedInt64ColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new UInt64ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + if (descriptor.isUnsigned()) { + return UINT64_MIN; + } + return 0L; + } + + @Override + public Object[] emptyArray() { + if (descriptor.isUnsigned()) { + return EMPTY_NUMERIC_ARRAY; + } + return UInt32Column.EMPTY_LONG_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt64ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt64ColumnWriter.java new file mode 100644 index 000000000..1092b57dc --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt64ColumnWriter.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class UInt64ColumnWriter extends ClickhouseColumnWriter { + public UInt64ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + long b = ((Number)val).longValue(); + sink.writeLongLE(b); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeLongLE(0); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt8Column.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt8Column.java new file mode 100644 index 000000000..8eedd9852 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt8Column.java @@ -0,0 +1,58 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class UInt8Column extends ClickhouseColumn { + public static final Byte[] EMPTY_BYTE_ARRAY = new Byte[0]; + + public UInt8Column(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + if (descriptor.isUnsigned()) { + return new UnsignedInt8ColumnReader(nRows, descriptor); + } + return new SignedInt8ColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new UInt8ColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + if (descriptor.isUnsigned()) { + return (short) 0; + } else { + return (byte) 0; + } + } + + @Override + public Object[] emptyArray() { + if (descriptor.isUnsigned()) { + return UInt16Column.EMPTY_SHORT_ARRAY; + } else { + return EMPTY_BYTE_ARRAY; + } + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt8ColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt8ColumnWriter.java new file mode 100644 index 000000000..d9b45f9b9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UInt8ColumnWriter.java @@ -0,0 +1,37 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; + +public class UInt8ColumnWriter extends ClickhouseColumnWriter { + public UInt8ColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + byte b = ((Number)val).byteValue(); + sink.writeByte(b); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeByte(0); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumn.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumn.java new file mode 100644 index 000000000..d1a1ba970 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumn.java @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.Tuple; + +import java.util.List; +import java.util.UUID; + +public class UUIDColumn extends ClickhouseColumn { + public static final UUID[] EMPTY_UUID_ARRAY = new UUID[0]; + + public static final UUID ZERO_UUID = new UUID(0, 0); + public static final int ELEMENT_SIZE = 16; + + public UUIDColumn(ClickhouseBinaryColumnDescriptor descriptor) { + super(descriptor); + } + + @Override + public ClickhouseColumnReader reader(int nRows) { + return new UUIDColumnReader(nRows, descriptor); + } + + @Override + public ClickhouseColumnWriter writer(List data, int columnIndex) { + return new UUIDColumnWriter(data, descriptor, columnIndex); + } + + @Override + public Object nullValue() { + return ZERO_UUID; + } + + @Override + public Object[] emptyArray() { + return EMPTY_UUID_ARRAY; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumnReader.java new file mode 100644 index 000000000..ee4615f8d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumnReader.java @@ -0,0 +1,54 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSource; + +import java.util.UUID; + +public class UUIDColumnReader extends ClickhouseColumnReader { + + protected UUIDColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object readItems(ClickhouseStreamDataSource in) { + if (in.readableBytes() >= UUIDColumn.ELEMENT_SIZE * nRows) { + UUID[] data = new UUID[nRows]; + for (int i = 0; i < nRows; ++i) { + if (nullsMap == null || !nullsMap.get(i)) { + long mostSigBits = in.readLongLE(); + long leastSigBits = in.readLongLE(); + data[i] = new UUID(mostSigBits, leastSigBits); + } else { + in.skipBytes(UUIDColumn.ELEMENT_SIZE); + } + } + return data; + } + return null; + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new UUID[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new UUID[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumnWriter.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumnWriter.java new file mode 100644 index 000000000..6e8cef307 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UUIDColumnWriter.java @@ -0,0 +1,39 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseStreamDataSink; +import io.vertx.sqlclient.Tuple; + +import java.util.List; +import java.util.UUID; + +public class UUIDColumnWriter extends ClickhouseColumnWriter { + public UUIDColumnWriter(List data, ClickhouseBinaryColumnDescriptor columnDescriptor, int columnIndex) { + super(data, columnDescriptor, columnIndex); + } + + @Override + protected void serializeDataElement(ClickhouseStreamDataSink sink, Object val) { + UUID uuid = (UUID) val; + sink.writeLongLE(uuid.getMostSignificantBits()); + sink.writeLongLE(uuid.getLeastSignificantBits()); + } + + @Override + protected void serializeDataNull(ClickhouseStreamDataSink sink) { + sink.writeZero(UUIDColumn.ELEMENT_SIZE); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt16ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt16ColumnReader.java new file mode 100644 index 000000000..de1336ddb --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt16ColumnReader.java @@ -0,0 +1,30 @@ +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +public class UnsignedInt16ColumnReader extends SignedInt16ColumnReader { + public UnsignedInt16ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return Short.toUnsignedInt(primitive(rowIdx)); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == int.class) { + return new int[dim1][dim2]; + } + return new Integer[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == int.class) { + return new int[length]; + } + return new Integer[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt32ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt32ColumnReader.java new file mode 100644 index 000000000..6fcadf746 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt32ColumnReader.java @@ -0,0 +1,30 @@ +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +public class UnsignedInt32ColumnReader extends SignedInt32ColumnReader { + public UnsignedInt32ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return Integer.toUnsignedLong(primitive(rowIdx)); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == long.class) { + return new long[dim1][dim2]; + } + return new Long[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == long.class) { + return new long[length]; + } + return new Long[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt64ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt64ColumnReader.java new file mode 100644 index 000000000..dc29c136c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt64ColumnReader.java @@ -0,0 +1,25 @@ +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.sqlclient.data.Numeric; + +public class UnsignedInt64ColumnReader extends SignedInt64ColumnReader { + public UnsignedInt64ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return Numeric.create(unsignedBi(primitive(rowIdx))); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + return new Numeric[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + return new Numeric[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt8ColumnReader.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt8ColumnReader.java new file mode 100644 index 000000000..e46554d80 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/impl/codec/columns/UnsignedInt8ColumnReader.java @@ -0,0 +1,31 @@ +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; + +public class UnsignedInt8ColumnReader extends SignedInt8ColumnReader { + + public UnsignedInt8ColumnReader(int nRows, ClickhouseBinaryColumnDescriptor columnDescriptor) { + super(nRows, columnDescriptor); + } + + @Override + protected Object getElementInternal(int rowIdx, Class desired) { + return (short)Byte.toUnsignedInt(primitive(rowIdx)); + } + + @Override + protected Object[] allocateTwoDimArray(Class desired, int dim1, int dim2) { + if (desired == short.class) { + return new short[dim1][dim2]; + } + return new Short[dim1][dim2]; + } + + @Override + protected Object allocateOneDimArray(Class desired, int length) { + if (desired == short.class) { + return new short[length]; + } + return new Short[length]; + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/package-info.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/package-info.java new file mode 100644 index 000000000..af8cf1930 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/package-info.java @@ -0,0 +1,17 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +@ModuleGen(name = "vertx-clickhousebinary-client", groupPackage = "io.vertx") +package io.vertx.clickhouseclient.binary; + +import io.vertx.codegen.annotations.ModuleGen; diff --git a/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/spi/ClickhouseBinaryDriver.java b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/spi/ClickhouseBinaryDriver.java new file mode 100644 index 000000000..b67c92e4d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/io/vertx/clickhouseclient/binary/spi/ClickhouseBinaryDriver.java @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.spi; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryConnectionFactory; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryConnectionUriParser; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryPoolImpl; +import io.vertx.core.Vertx; +import io.vertx.core.impl.CloseFuture; +import io.vertx.core.impl.VertxInternal; +import io.vertx.core.json.JsonObject; +import io.vertx.core.spi.metrics.ClientMetrics; +import io.vertx.core.spi.metrics.VertxMetrics; +import io.vertx.sqlclient.PoolOptions; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.impl.PoolImpl; +import io.vertx.sqlclient.impl.tracing.QueryTracer; +import io.vertx.sqlclient.spi.ConnectionFactory; +import io.vertx.sqlclient.spi.Driver; + +import java.util.List; +import java.util.stream.Collectors; + +public class ClickhouseBinaryDriver implements Driver { + private static final String SHARED_CLIENT_KEY = "__vertx.shared.clickhousebinaryclient"; + public static final ClickhouseBinaryDriver INSTANCE = new ClickhouseBinaryDriver(); + + @Override + public ClickhouseBinaryPoolImpl newPool(Vertx vertx, List databases, PoolOptions options, CloseFuture closeFuture) { + VertxInternal vx = (VertxInternal) vertx; + PoolImpl pool; + if (options.isShared()) { + pool = vx.createSharedClient(SHARED_CLIENT_KEY, options.getName(), closeFuture, cf -> newPoolImpl(vx, databases, options, cf)); + } else { + pool = newPoolImpl(vx, databases, options, closeFuture); + } + return new ClickhouseBinaryPoolImpl(vx, closeFuture, pool); + } + + private PoolImpl newPoolImpl(VertxInternal vertx, List databases, PoolOptions options, CloseFuture closeFuture) { + ClickhouseBinaryConnectOptions baseConnectOptions = ClickhouseBinaryConnectOptions.wrap(databases.get(0)); + QueryTracer tracer = vertx.tracer() == null ? null : new QueryTracer(vertx.tracer(), baseConnectOptions); + VertxMetrics vertxMetrics = vertx.metricsSPI(); + ClientMetrics metrics = vertxMetrics != null ? vertxMetrics.createClientMetrics(baseConnectOptions.getSocketAddress(), + "sql", baseConnectOptions.getMetricsName()) : null; + PoolImpl pool = new PoolImpl(vertx, this, tracer, metrics, 1, options, null, null, closeFuture); + List lst = databases.stream().map(o -> createConnectionFactory(vertx, o)).collect(Collectors.toList()); + ConnectionFactory factory = ConnectionFactory.roundRobinSelector(lst); + pool.connectionProvider(factory::connect); + pool.init(); + closeFuture.add(factory); + return pool; + } + + @Override + public ConnectionFactory createConnectionFactory(Vertx vertx, SqlConnectOptions database) { + return new ClickhouseBinaryConnectionFactory((VertxInternal) vertx, ClickhouseBinaryConnectOptions.wrap(database)); + } + + @Override + public SqlConnectOptions parseConnectionUri(String uri) { + JsonObject conf = ClickhouseBinaryConnectionUriParser.parse(uri, false); + return conf == null ? null : new ClickhouseBinaryConnectOptions(conf); + } + + @Override + public boolean acceptsOptions(SqlConnectOptions options) { + return options instanceof ClickhouseBinaryConnectOptions || SqlConnectOptions.class.equals(options.getClass()); + } +} diff --git a/vertx-clickhouse-binary-client/src/main/java/ru/yandex/clickhouse/util/ClickHouseCityHash.java b/vertx-clickhouse-binary-client/src/main/java/ru/yandex/clickhouse/util/ClickHouseCityHash.java new file mode 100644 index 000000000..fe182cfce --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/java/ru/yandex/clickhouse/util/ClickHouseCityHash.java @@ -0,0 +1,274 @@ +/* + * Copyright 2017 YANDEX LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Copyright (C) 2012 tamtam180 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package ru.yandex.clickhouse.util; + +/** + * @author tamtam180 - kirscheless at gmail.com + * @see http://google-opensource.blogspot.jp/2011/04/introducing-cityhash.html + * @see http://code.google.com/p/cityhash/ + * + */ + +/** + * NOTE: The code is modified to be compatible with CityHash128 used in ClickHouse + */ +public class ClickHouseCityHash { + + private static final long k0 = 0xc3a5c85c97cb3127L; + private static final long k1 = 0xb492b66fbe98f273L; + private static final long k2 = 0x9ae16a3b2f90404fL; + private static final long k3 = 0xc949d7c7509e6557L; + + private static long toLongLE(byte[] b, int i) { + return (((long)b[i+7] << 56) + + ((long)(b[i+6] & 255) << 48) + + ((long)(b[i+5] & 255) << 40) + + ((long)(b[i+4] & 255) << 32) + + ((long)(b[i+3] & 255) << 24) + + ((b[i+2] & 255) << 16) + + ((b[i+1] & 255) << 8) + + ((b[i+0] & 255) << 0)); + } + private static long toIntLE(byte[] b, int i) { + return (((b[i+3] & 255L) << 24) + ((b[i+2] & 255L) << 16) + ((b[i+1] & 255L) << 8) + ((b[i+0] & 255L) << 0)); + } + + private static long fetch64(byte[] s, int pos) { + return toLongLE(s, pos); + } + + private static long fetch32(byte[] s, int pos) { + return toIntLE(s, pos); + } + + private static int staticCastToInt(byte b) { + return b & 0xFF; + } + + private static long rotate(long val, int shift) { + return shift == 0 ? val : (val >>> shift) | (val << (64 - shift)); + } + + private static long rotateByAtLeast1(long val, int shift) { + return (val >>> shift) | (val << (64 - shift)); + } + + private static long shiftMix(long val) { + return val ^ (val >>> 47); + } + + private static final long kMul = 0x9ddfea08eb382d69L; + private static long hash128to64(long u, long v) { + long a = (u ^ v) * kMul; + a ^= (a >>> 47); + long b = (v ^ a) * kMul; + b ^= (b >>> 47); + b *= kMul; + return b; + } + + private static long hashLen16(long u, long v) { + return hash128to64(u, v); + } + + private static long hashLen0to16(byte[] s, int pos, int len) { + if (len > 8) { + long a = fetch64(s, pos + 0); + long b = fetch64(s, pos + len - 8); + return hashLen16(a, rotateByAtLeast1(b + len, len)) ^ b; + } + if (len >= 4) { + long a = fetch32(s, pos + 0); + return hashLen16((a << 3) + len, fetch32(s, pos + len - 4)); + } + if (len > 0) { + byte a = s[pos + 0]; + byte b = s[pos + (len >>> 1)]; + byte c = s[pos + len - 1]; + int y = staticCastToInt(a) + (staticCastToInt(b) << 8); + int z = len + (staticCastToInt(c) << 2); + return shiftMix(y * k2 ^ z * k3) * k2; + } + return k2; + } + + + private static long[] weakHashLen32WithSeeds( + long w, long x, long y, long z, + long a, long b) { + + a += w; + b = rotate(b + a + z, 21); + long c = a; + a += x; + a += y; + b += rotate(a, 44); + return new long[]{ a + z, b + c }; + } + + private static long[] weakHashLen32WithSeeds(byte[] s, int pos, long a, long b) { + return weakHashLen32WithSeeds( + fetch64(s, pos + 0), + fetch64(s, pos + 8), + fetch64(s, pos + 16), + fetch64(s, pos + 24), + a, + b + ); + } + + private static long[] cityMurmur(byte[] s, int pos, int len, long seed0, long seed1) { + + long a = seed0; + long b = seed1; + long c = 0; + long d = 0; + + int l = len - 16; + if (l <= 0) { + a = shiftMix(a * k1) * k1; + c = b * k1 + hashLen0to16(s, pos, len); + d = shiftMix(a + (len >= 8 ? fetch64(s, pos + 0) : c)); + } else { + + c = hashLen16(fetch64(s, pos + len - 8) + k1, a); + d = hashLen16(b + len, c + fetch64(s, pos + len - 16)); + a += d; + + do { + a ^= shiftMix(fetch64(s, pos + 0) * k1) * k1; + a *= k1; + b ^= a; + c ^= shiftMix(fetch64(s, pos + 8) * k1) * k1; + c *= k1; + d ^= c; + pos += 16; + l -= 16; + } while (l > 0); + } + + a = hashLen16(a, c); + b = hashLen16(d, b); + + return new long[]{ a ^ b, hashLen16(b, a) }; + } + + private static long[] cityHash128WithSeed(byte[] s, int pos, int len, long seed0, long seed1) { + if (len < 128) { + return cityMurmur(s, pos, len, seed0, seed1); + } + + long[] v = new long[2], w = new long[2]; + long x = seed0; + long y = seed1; + long z = k1 * len; + v[0] = rotate(y ^ k1, 49) * k1 + fetch64(s, pos); + v[1] = rotate(v[0], 42) * k1 + fetch64(s, pos + 8); + w[0] = rotate(y + z, 35) * k1 + x; + w[1] = rotate(x + fetch64(s, pos + 88), 53) * k1; + + // This is the same inner loop as CityHash64(), manually unrolled. + do { + x = rotate(x + y + v[0] + fetch64(s, pos + 16), 37) * k1; + y = rotate(y + v[1] + fetch64(s, pos + 48), 42) * k1; + + x ^= w[1]; + y ^= v[0] ; + + z = rotate(z ^ w[0], 33); + v = weakHashLen32WithSeeds(s, pos, v[1] * k1, x + w[0]); + w = weakHashLen32WithSeeds(s, pos + 32, z + w[1], y); + + { long swap = z; z = x; x = swap; } + pos += 64; + x = rotate(x + y + v[0] + fetch64(s, pos + 16), 37) * k1; + y = rotate(y + v[1] + fetch64(s, pos + 48), 42) * k1; + x ^= w[1]; + y ^= v[0]; + z = rotate(z ^ w[0], 33); + v = weakHashLen32WithSeeds(s, pos, v[1] * k1, x + w[0]); + w = weakHashLen32WithSeeds(s, pos + 32, z + w[1], y); + { long swap = z; z = x; x = swap; } + pos += 64; + len -= 128; + } while (len >= 128); + + y += rotate(w[0], 37) * k0 + z; + x += rotate(v[0] + z, 49) * k0; + + // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s. + for (int tail_done = 0; tail_done < len; ) { + tail_done += 32; + y = rotate(y - x, 42) * k0 + v[1]; + w[0] += fetch64(s, pos + len - tail_done + 16); + x = rotate(x, 49) * k0 + w[0]; + w[0] += v[0]; + v = weakHashLen32WithSeeds(s, pos + len - tail_done, v[0], v[1]); + } + + // At this point our 48 bytes of state should contain more than + // enough information for a strong 128-bit hash. We use two + // different 48-byte-to-8-byte hashes to get a 16-byte final result. + + x = hashLen16(x, v[0]); + y = hashLen16(y, w[0]); + + return new long[]{ + hashLen16(x + v[1], w[1]) + y, + hashLen16(x + w[1], y + v[1]) + }; + } + + + //TODO: maybe switch to external jar, see https://github.com/ClickHouse/clickhouse-jdbc/issues/600 + public static long[] cityHash128(byte[] s, int pos, int len) { + + if (len >= 16) { + return cityHash128WithSeed( + s, pos + 16, + len - 16, + fetch64(s, pos) ^ k3, + fetch64(s, pos + 8) + ); + } else if (len >= 8) { + return cityHash128WithSeed( + new byte[0], 0, 0, + fetch64(s, pos ) ^ (len * k0), + fetch64(s, pos + len -8) ^ k1 + ); + } else { + return cityHash128WithSeed(s, pos, len, k0, k1); + } + } + +} diff --git a/vertx-clickhouse-binary-client/src/main/resources/META-INF/MANIFEST.MF b/vertx-clickhouse-binary-client/src/main/resources/META-INF/MANIFEST.MF new file mode 100644 index 000000000..9750371bf --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/resources/META-INF/MANIFEST.MF @@ -0,0 +1,2 @@ +Automatic-Module-Name: io.vertx.client.sql.clickhouse.binary + diff --git a/vertx-clickhouse-binary-client/src/main/resources/META-INF/services/io.vertx.sqlclient.spi.Driver b/vertx-clickhouse-binary-client/src/main/resources/META-INF/services/io.vertx.sqlclient.spi.Driver new file mode 100644 index 000000000..cabf3f74e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/main/resources/META-INF/services/io.vertx.sqlclient.spi.Driver @@ -0,0 +1 @@ +io.vertx.clickhouseclient.binary.spi.ClickhouseBinaryDriver diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ArraySerDesTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ArraySerDesTest.java new file mode 100644 index 000000000..b64684d74 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ArraySerDesTest.java @@ -0,0 +1,101 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import io.netty.buffer.UnpooledByteBufAllocator; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.codec.*; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumn; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumnReader; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumnWriter; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumns; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.sqlclient.Tuple; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.nio.charset.StandardCharsets; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@RunWith(Parameterized.class) +public class ArraySerDesTest { + private static final Logger LOG = LoggerFactory.getLogger(ArraySerDesTest.class); + + private final ClickhouseColumn col; + private final List data; + + public ArraySerDesTest(String nm, ClickhouseColumn col, List data) { + this.col = col; + this.data = data; + } + + @Parameterized.Parameters(name = "{0}") + public static Iterable dataForTest() { + ClickhouseBinaryColumnDescriptor descr = ClickhouseColumns.columnDescriptorForSpec("Array(Array(Array(LowCardinality(Nullable(String)))))", "name"); + ClickhouseBinaryDatabaseMetadata md = new ClickhouseBinaryDatabaseMetadata("a", "b", + 0, 0,0, 0, "dname", ZoneId.systemDefault(), ZoneId.systemDefault(), "client", + Collections.emptyMap(), StandardCharsets.UTF_8, null, null, null, true, true); + ClickhouseColumn col = ClickhouseColumns.columnForSpec(descr, md); + List data = Arrays.asList( + //row slice: [[0, 2], [0, 1, 2], [0, 0, 0]] (master slice for 2 similar rows: [0,2],[0,2,4],[0,1,2,3,4],[0,0,0,0,0]) + Tuple.of(new String[][][]{ {{}}, {{}} } ), + //row slice: [[0, 1], [0, 3], [0, 0, 1, 3]] + Tuple.of(new String[][][]{ {{}, {"1"}, {"2", "3"}} }), + Tuple.of(new String[][][]{ {{}, {"1"}, {"2", "3"}} }), + Tuple.of(new String[][][]{ {{}}, {{}} } ), + Tuple.of(new String[][][]{ {{}}, {{}} } ), + Tuple.of( new String[][][]{ {{"str1_1", "str1_2", null}, {null}}, {{}} } ), + Tuple.of( new String[][][]{ {{"str1_1", "str1_2", null}, {null}}, {{"str1_3", "str1_4", null}, {null}}} ), + //master slice for 2 rows: [[0, 2], [0, 1, 3], [0, 3, 5, 6], [0, 0, 1, 3, 6, 7, 7]] + //per row slices: [[[0, 1], [0, 3], [0, 0, 1, 3]], [[0, 2], [0, 2, 3], [0, 3, 4, 4]]] + //[0, 1], [0, 3], [0, 0, 1, 3] + Tuple.of(new String[][][]{ {{}, {"1"}, {"2", "3"}} }), + //[0, 2], [0, 2, 3], [0, 3, 4, 4] + Tuple.of( new String[][][]{ {{"str1_1", "str1_2", null}, {null}}, {{}} } ) + ); + + return Arrays.asList(new Object[][]{ + {data.size() + " rows", col, data}, + {"0 rows", col, Collections.emptyList()} + }); + } + + @Test + public void doSerDes() { + ClickhouseColumnWriter writer = col.writer(data, 0); + ByteBuf buf = Unpooled.buffer(); + ClickhouseStreamDataSink sink = new RawClickhouseStreamDataSink(buf); + writer.serializeColumn(sink, 0, data.size()); + sink.finish(); + + ClickhouseColumnReader reader = col.reader(data.size()); + ClickhouseStreamDataSource ds = new RawClickhouseStreamDataSource(StandardCharsets.UTF_8); + ds.moreData(buf, UnpooledByteBufAllocator.DEFAULT); + reader.readColumn(ds); + for (int rowIdx = 0; rowIdx < data.size(); ++rowIdx) { + LOG.info("rowIdx: " + rowIdx); + Object actual = reader.getElement(rowIdx, String.class); + Object expected = data.get(rowIdx).getValue(0); + Assert.assertArrayEquals((Object[])expected, (Object[])actual); + } + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/BasicClickhouseTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/BasicClickhouseTest.java new file mode 100644 index 000000000..1e7906da3 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/BasicClickhouseTest.java @@ -0,0 +1,188 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import io.vertx.clickhouseclient.binary.impl.codec.ClickhouseBinaryColumnDescriptor; +import io.vertx.clickhouseclient.binary.impl.codec.columns.ClickhouseColumns; +import io.vertx.core.Vertx; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.SqlClient; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.math.BigInteger; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +@RunWith(VertxUnitRunner.class) +public class BasicClickhouseTest { + private static final Logger LOG = LoggerFactory.getLogger(BasicClickhouseTest.class); + + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + private ClickhouseBinaryConnectOptions options; + private Vertx vertx; + + @Before + public void setup() { + options = rule.options(); + vertx = Vertx.vertx(); + } + + @After + public void teardDown(TestContext ctx) { + vertx.close(ctx.asyncAssertSuccess()); + } + + @Test + public void baseConnectTest(TestContext ctx) { + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(SqlClient::close)); + } + + @Test + public void loginFailureTest(TestContext ctx) { + ClickhouseBinaryConnectOptions opts = new ClickhouseBinaryConnectOptions(options); + opts.setPassword("wrong-password"); + ClickhouseBinaryConnection.connect(vertx, opts, ctx.asyncAssertFailure()); + } + + @Test + public void testIntegerRanges(TestContext ctx) { + List types = Stream.of("Int8", "Int16", "Int32", "Int64", "Int128") + .flatMap(el -> "Int128".equals(el) + ? Stream.of(el, "Nullable(" + el + ")") + : Stream.of(el, "U" + el, "LowCardinality(Nullable(" + el + "))", "Nullable(U" + el + ")", "LowCardinality(Nullable(U" + el + "))")) + .map(spec -> ClickhouseColumns.columnDescriptorForSpec(spec, "fake_name")) + .collect(Collectors.toList()); + List typeNames = types.stream() + .map(ClickhouseBinaryColumnDescriptor::getUnparsedNativeType).collect(Collectors.toList()); + LOG.info("integer columns: " + typeNames); + Iterator typesIter = types.iterator(); + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + scheduleIntTypeQuery(ctx, typesIter, conn); + })); + } + + private void scheduleIntTypeQuery(TestContext ctx, Iterator typeIterator, ClickhouseBinaryConnection conn) { + if (typeIterator.hasNext()) { + ClickhouseBinaryColumnDescriptor descr = typeIterator.next(); + String nativeType = descr.getUnparsedNativeType(); + //looks like Nullable(UInt128) is broken for min/max at the moment, hence add/subtract + BigInteger minValue = descr.getMinValue().add(BigInteger.ONE); + BigInteger maxValue = descr.getMaxValue().subtract(BigInteger.ONE); + String query = String.format("SELECT CAST('%s', '%s') as min_val, CAST('%s', '%s') as max_val", + minValue, nativeType, maxValue, nativeType); + LOG.info("running query: " + query); + conn.query(query).execute( + ctx.asyncAssertSuccess(res -> { + ctx.assertEquals(1, res.size()); + Row row = res.iterator().next(); + ctx.assertEquals(minValue, row.getBigDecimal("min_val").toBigIntegerExact(), nativeType + " type min failure"); + ctx.assertEquals(maxValue, row.getBigDecimal("max_val").toBigIntegerExact(), nativeType + " type max failure"); + scheduleIntTypeQuery(ctx, typeIterator, conn); + }) + ); + } else { + conn.close(); + } + } + + @Test + public void emptyArrayTest(TestContext ctx) { + arrayTest(ctx, + "select arr from (" + + "select 1 as id, array() as arr UNION ALL " + + "select 2 as id, array('a') as arr UNION ALL " + + "select 3 as id, array() as arr" + + ") t1 order by id", + Arrays.asList(new Object[0], new Object[]{"a"}, new Object[0])); + } + + @Test + public void nonEmptyArrayTest(TestContext ctx) { + arrayTest(ctx, + "select arr from (" + + "select 1 as id, array(array(), array(NULL), array(1, NULL, 2), array(321)) as arr UNION ALL " + + "select 1 as id, array(array(34), array(), array(5, 6, NULL), array(14, NULL)) as arr " + + ") t1 order by id", + Arrays.asList(new Object[][]{{}, {null}, {1, null, 2}, {321}}, new Object[][]{{34}, {}, {5, 6, null}, {14, null}})); + } + + @Test + public void nonEmptyLowCardinalityArrayTest(TestContext ctx) { + arrayTest(ctx, + "select arr from (" + + "select 1 as id, CAST(array(array(), array(NULL), array('a', NULL, 'b'), array('c')), 'Array(Array(LowCardinality(Nullable(String))))') as arr UNION ALL " + + "select 2 as id, CAST(array(array(NULL), array(), array('d', 'e', NULL), array('f', NULL)), 'Array(Array(LowCardinality(Nullable(String))))') as arr" + + ") t1 order by id", + Arrays.asList(new Object[][]{{}, {null}, {"a", null, "b"}, {"c"}}, new Object[][]{{null}, {}, {"d", "e", null}, {"f", null}})); + } + + private void arrayTest(TestContext ctx, String query, List expected) { + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + conn.query(query).execute( + ctx.asyncAssertSuccess(res1 -> { + ctx.assertEquals(res1.size(), expected.size()); + int i = 0; + for (Row row : res1) { + Object[] expectedVal = expected.get(i); + Object[] actualVal = (Object[]) row.getValue(0); + ctx.assertEquals(true, Arrays.deepEquals(expectedVal, actualVal)); + ++i; + } + conn.close(); + }) + ); + })); + } + + @Test + public void baseQueryTest(TestContext ctx) { + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + conn.query("select 4 as resource, 'aa' as str_col1, CAST('abcdef', 'FixedString(6)') as str_col2").execute( + ctx.asyncAssertSuccess(res1 -> { + ctx.assertEquals(1, res1.size()); + conn.close(); + }) + ); + })); + } + + @Test + public void blobTest(TestContext ctx) { + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + conn.query("select 'abcd'").execute( + ctx.asyncAssertSuccess(res1 -> { + ctx.assertEquals(1, res1.size()); + Row row = res1.iterator().next(); + byte[] bytes = row.get(byte[].class, 0); + ctx.assertEquals("abcd", new String(bytes, StandardCharsets.UTF_8)); + conn.close(); + }) + ); + })); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ClickhouseResource.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ClickhouseResource.java new file mode 100644 index 000000000..f20a385d9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ClickhouseResource.java @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import org.junit.rules.ExternalResource; +import org.testcontainers.containers.ClickHouseContainer; +import org.testcontainers.utility.DockerImageName; + +public class ClickhouseResource extends ExternalResource { + private static final String connectionUri = System.getProperty("connection.uri"); + private static final String tlsConnectionUri = System.getProperty("tls.connection.uri"); + + private ClickHouseContainer server; + private ClickhouseBinaryConnectOptions options; + + @Override + protected void before() throws Throwable { + if (isTestingWithExternalDatabase()) { + this.options = ClickhouseBinaryConnectOptions.fromUri(connectionUri); + return; + } + if (this.server != null) { + return; + } + DockerImageName imageName = DockerImageName.parse("clickhouse/clickhouse-server").withTag(clickhouseVersion()); + server = new ClickHouseContainer(imageName); + server.start(); + this.options = (ClickhouseBinaryConnectOptions) new ClickhouseBinaryConnectOptions() + .setPort(server.getMappedPort(ClickHouseContainer.NATIVE_PORT)) + .setHost(server.getContainerIpAddress()) + .setUser(server.getUsername()) + .setPassword(server.getPassword()) + .setDatabase("default") + .addProperty(ClickhouseConstants.OPTION_APPLICATION_NAME, "java-driver") + .addProperty(ClickhouseConstants.OPTION_COMPRESSOR, "lz4_safe") + .addProperty(ClickhouseConstants.OPTION_STRING_CHARSET, "utf-8") + .addProperty(ClickhouseConstants.OPTION_DEFAULT_ZONE_ID, "Europe/Oslo") + .addProperty(ClickhouseConstants.OPTION_DATETIME64_EXTRA_NANOS_MODE, "saturate") + .addProperty(ClickhouseConstants.OPTION_ENUM_RESOLUTION, "by_name") + .addProperty(ClickhouseConstants.OPTION_REMOVE_TRAILING_ZEROS_WHEN_ENCODE_FIXED_STRINGS, "true") + .addProperty(ClickhouseConstants.OPTION_SEND_LOGS_LEVEL, "debug"); + } + + private static String clickhouseVersion() { + String version = System.getProperty("embedded.clickhouse.version"); + return version == null ? "21.8.15.7-alpine" : version; + } + + @Override + protected void after() { + if (server != null) { + server.stop(); + } + } + + public ClickhouseBinaryConnectOptions options() { + return new ClickhouseBinaryConnectOptions(options); + } + + public static boolean isTestingWithExternalDatabase() { + return isSystemPropertyValid(connectionUri); + //|| isSystemPropertyValid(tlsConnectionUri); + } + + private static boolean isSystemPropertyValid(String systemProperty) { + return systemProperty != null && !systemProperty.isEmpty(); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ExtendedClickhouseTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ExtendedClickhouseTest.java new file mode 100644 index 000000000..95d1e0459 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/ExtendedClickhouseTest.java @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import io.vertx.core.Vertx; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.ext.unit.Async; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowStream; +import io.vertx.sqlclient.impl.ArrayTuple; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.concurrent.atomic.LongAdder; + +@RunWith(VertxUnitRunner.class) +public class ExtendedClickhouseTest { + private static final Logger LOG = LoggerFactory.getLogger(ExtendedClickhouseTest.class); + + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + private ClickhouseBinaryConnectOptions options; + private Vertx vertx; + private String query; + + @Before + public void setup(TestContext ctx) { + options = rule.options(); + vertx = Vertx.vertx(); + } + + @After + public void teardDown(TestContext ctx) { + vertx.close(ctx.asyncAssertSuccess()); + } + + @Test + public void extendedQueryTest(TestContext ctx) { + Async async = ctx.async(); + LongAdder adder = new LongAdder(); + final long limit = 55; + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + query = String.format("select name, value from (SELECT name, value from vertx_cl_test_table limit %s) t1 order by name desc", limit); + conn + .prepare(query, ctx.asyncAssertSuccess(ps -> { + RowStream stream = ps.createStream(50, ArrayTuple.EMPTY); + stream.exceptionHandler(err -> { + LOG.error("exceptionHandler: ", err); + ctx.assertEquals(limit, adder.sum()); + async.complete(); + }); + stream.endHandler(v -> { + LOG.info("got End of stream"); + ctx.assertEquals(limit, adder.sum()); + async.complete(); + }); + stream.handler(row -> { + adder.increment(); + //LOG.info("name: " + row.getString("name") + "; value: " + row.getLong("value")); + }); + })); + })); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/NestedExceptionsTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/NestedExceptionsTest.java new file mode 100644 index 000000000..6eb82fda1 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/NestedExceptionsTest.java @@ -0,0 +1,60 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.buffer.Unpooled; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.ClickhouseServerException; +import io.vertx.clickhouseclient.binary.impl.codec.PacketReader; +import org.junit.Test; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.time.ZoneId; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import org.junit.Assert; + +public class NestedExceptionsTest { + @Test + public void checkExceptions() throws IOException { + ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + mapper.findAndRegisterModules(); + ByteBuf buf; + try (InputStream is = NestedExceptionsTest.class.getResourceAsStream("/forged_nested_exception.yaml")) { + Map map = mapper.readValue(is, Map.class); + List queryAnswers = PacketUtil.filterServerBlocks(map); + byte[][] arrays = PacketUtil.asPrimitiveByteArray(queryAnswers); + buf = Unpooled.wrappedBuffer(arrays); + } + + PooledByteBufAllocator allocator = new PooledByteBufAllocator(); + ClickhouseBinaryDatabaseMetadata md = new ClickhouseBinaryDatabaseMetadata("a", "b", + 0, 0,0, 0, "dname", ZoneId.systemDefault(), ZoneId.systemDefault(), "client", + Collections.emptyMap(), StandardCharsets.UTF_8, null, null, null, true, true); + PacketReader rdr = new PacketReader(md, "none", Collections.emptyMap(), null); + ClickhouseServerException exception = (ClickhouseServerException)rdr.receivePacket(allocator, buf); + Assert.assertEquals("DB::Exception", exception.getName()); + ClickhouseServerException nested = (ClickhouseServerException) exception.getCause(); + Assert.assertNotNull(nested); + Assert.assertEquals("DB::Dxception", nested.getName()); + Assert.assertNull(nested.getCause()); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/PacketReaderReplayTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/PacketReaderReplayTest.java new file mode 100644 index 000000000..b84b8d8cc --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/PacketReaderReplayTest.java @@ -0,0 +1,142 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufUtil; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.buffer.Unpooled; +import io.vertx.clickhouseclient.binary.impl.ClickhouseBinaryDatabaseMetadata; +import io.vertx.clickhouseclient.binary.impl.ClickhouseServerException; +import io.vertx.clickhouseclient.binary.impl.codec.PacketReader; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import net.jpountz.lz4.LZ4Factory; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.IOException; +import java.io.InputStream; +import java.util.*; + +@RunWith(Parameterized.class) +public class PacketReaderReplayTest { + private static final Logger LOG = LoggerFactory.getLogger(PacketReaderReplayTest.class); + + private final Map props; + private final ByteBuf buf; + private final LZ4Factory lz4Factory; + + public PacketReaderReplayTest(String replayFile, String fragmented, ByteBuf buf, Map props, LZ4Factory lz4Factory) { + this.buf = buf; + this.props = props; + this.lz4Factory = lz4Factory; + } + + @Parameterized.Parameters(name = "{0}({1})") + public static Iterable dataForTest() throws IOException { + ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); + mapper.findAndRegisterModules(); + List result = new ArrayList<>(); + + final int continuousOffset = 8; + List replayFiles = Arrays.asList( + "/insert_prepare_with_compression.yaml", + "/with_max_block_size_and_2_datablocks_with_compression.yaml", + "/nullable_low_cardinality_with_compression.yaml", + "/nullable_low_cardinality_without_compression.yaml", + "/select_array_of_nullable_string_without_compression.yaml", + "/select_empty_array_without_compression.yaml", + "/ClickhouseBinaryPreparedQueryCachedTest_testConcurrentClose_with_compression.yaml", + "/wrong_db_connection_without_compression.yaml", + "/testConnectInvalidDatabase_20.10.2_without_compression.yaml", + "/testConnectInvalidDatabase_22.8.6.71_without_compression.yaml" + ); + for (String replayFile : replayFiles) { + boolean compression = replayFile.contains("with_compression"); + try (InputStream is = PacketReaderReplayTest.class.getResourceAsStream(replayFile)) { + Map map = mapper.readValue(is, Map.class); + + List queryAnswers = PacketUtil.filterServerBlocks(map); + byte[][] arrays = PacketUtil.asPrimitiveByteArray(queryAnswers); + ByteBuf fragmentedByteBuf = Unpooled.wrappedBuffer(arrays); + ByteBuf continuousBuf = Unpooled.wrappedBuffer(new byte[fragmentedByteBuf.readableBytes()]) + .writerIndex(0); + fragmentedByteBuf.readBytes(continuousBuf); + fragmentedByteBuf.readerIndex(0); + ByteBuf continuousWithOffsetBuf = Unpooled.wrappedBuffer(new byte[fragmentedByteBuf.readableBytes() + continuousOffset], + continuousOffset, fragmentedByteBuf.readableBytes()) + .writerIndex(0); + fragmentedByteBuf.readBytes(continuousWithOffsetBuf); + fragmentedByteBuf.readerIndex(0); + + + Map p = buildProperties(compression); + LZ4Factory f = compression ? LZ4Factory.safeInstance() : null; + result.add(new Object[]{replayFile, "fragmented", fragmentedByteBuf, p, f}); + result.add(new Object[]{replayFile, "continuous", continuousBuf, p, f}); + result.add(new Object[]{replayFile, "continuousWithOffset", continuousWithOffsetBuf, p, f}); + } + } + return result; + } + + @After + public void cleanup() { + buf.release(); + } + + @Test + public void doReplayTest() { + PooledByteBufAllocator allocator = new PooledByteBufAllocator(); + String fullName = "Clickhouse jython-driver"; + LOG.info("all bytes: " + ByteBufUtil.hexDump(buf)); + while (buf.readableBytes() > 0) { + readConnInteraction(allocator, fullName); + } + } + + private void readConnInteraction(PooledByteBufAllocator allocator, String fullName) { + //1st packet: server hello + PacketReader rdr = new PacketReader(null, fullName, props, lz4Factory); + Object firstPacket = rdr.receivePacket(allocator, buf); + //some old versions(e.g. 20.10.2) omit HELLO packet, some sends both HELLO and Exception in case of bad login (e.g. DB does not exist) + if (firstPacket instanceof ClickhouseServerException) { + ClickhouseServerException exception = (ClickhouseServerException) firstPacket; + LOG.info("clickhouse exception: " + exception); + return; + } + ClickhouseBinaryDatabaseMetadata md = (ClickhouseBinaryDatabaseMetadata)firstPacket; + LOG.info("db version: " + md.fullVersion()); + do { + rdr = new PacketReader(md, fullName, props, lz4Factory); + Object packet = rdr.receivePacket(allocator, buf); + LOG.info("packet: " + packet); + } while (!rdr.isEndOfStream() && buf.readableBytes() > 0); + } + + private static Map buildProperties(boolean withCompression) { + Map props = new HashMap<>(); + props.put(ClickhouseConstants.OPTION_APPLICATION_NAME, "jython-driver"); + if (withCompression) { + props.put(ClickhouseConstants.OPTION_COMPRESSOR, "lz4_safe"); + } + props.put(ClickhouseConstants.OPTION_INITIAL_HOSTNAME, "bhorse"); + return props; + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/PacketUtil.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/PacketUtil.java new file mode 100644 index 000000000..da886af4d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/PacketUtil.java @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import org.testcontainers.shaded.org.bouncycastle.util.Pack; + +import java.util.*; +import java.util.stream.Collectors; + +public class PacketUtil { + public static List filterServerBlocks(Map src) { + if (src.containsKey("packets")) { + List> packetsMaps = (List>) src.get("packets"); + List packets = new ArrayList<>(); + for (Map packetFields : packetsMaps) { + Packet packet = new Packet((int) packetFields.get("peer"), (int) packetFields.get("index"), (byte[]) packetFields.get("data")); + packets.add(packet); + } + packets.sort(Comparator.comparing(Packet::index)); + List peer0Packets = + packets.stream() + .filter(pckt -> pckt.peer() == 1) + .map(Packet::data) + .collect(Collectors.toList()); + return peer0Packets; + } else { + Map packets = (Map)src; + return packets.entrySet() + .stream() + .filter(packet -> !packet.getKey().startsWith("peer0_")) + .map(Map.Entry::getValue) + .collect(Collectors.toList()); + } + } + + public static byte[][] asPrimitiveByteArray(List src) { + byte[][] ret = new byte[src.size()][]; + for (int i = 0; i < src.size(); ++i) { + ret[i] = src.get(i); + } + return ret; + } +} + + +class Packet { + private final int peer; + private final int index; + private final byte[] data; + + Packet(int peer, int index, byte[] data) { + this.peer = peer; + this.index = index; + this.data = data; + } + + public int peer() { + return peer; + } + + public int index() { + return index; + } + + public byte[] data() { + return data; + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/Sleep.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/Sleep.java new file mode 100644 index 000000000..3c3b4cac6 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/Sleep.java @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +public class Sleep { + //updates may be async even for non-replicated tables; + public static final int SLEEP_TIME = 100; + + public static void sleepOrThrow(int duration) { + try { + Thread.sleep(duration); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + public static void sleepOrThrow() { + sleepOrThrow(SLEEP_TIME); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/SpecialTypesTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/SpecialTypesTest.java new file mode 100644 index 000000000..704f24dce --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/SpecialTypesTest.java @@ -0,0 +1,158 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary; + +import io.vertx.core.Vertx; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import org.junit.After; +import org.junit.Before; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.time.Duration; +import java.util.Arrays; +import java.util.Optional; + +@RunWith(VertxUnitRunner.class) +public class SpecialTypesTest { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + private ClickhouseBinaryConnectOptions options; + private Vertx vertx; + + @Before + public void setup(TestContext ctx) { + options = rule.options(); + vertx = Vertx.vertx(); + } + + @After + public void teardDown(TestContext ctx) { + vertx.close(ctx.asyncAssertSuccess()); + } + + @Test + public void testNothing(TestContext ctx) { + runQuery(ctx, "SELECT array()", null, null); + } + + @Test + public void testIntervalYear(TestContext ctx) { + runQuery(ctx, "SELECT INTERVAL 4 YEAR", Duration.class, Optional.of(Duration.ofDays(365 * 4))); + } + + @Test + public void testIntervalYearArray(TestContext ctx) { + runQuery(ctx, "SELECT array(toIntervalYear(4), toIntervalYear(1), toIntervalYear(0))", Duration[].class, + Optional.of(new Duration[]{Duration.ofDays(4 * 365), Duration.ofDays(365), Duration.ofDays(0)})); + } + + @Test + public void testIntervalQuarter(TestContext ctx) { + runQuery(ctx, "SELECT INTERVAL 4 QUARTER", Duration.class, Optional.of(Duration.ofDays(120 * 4))); + } + + @Test + public void testIntervalQuarterArray(TestContext ctx) { + runQuery(ctx, "SELECT array(toIntervalQuarter(4), toIntervalQuarter(1), toIntervalQuarter(0))", Duration[].class, + Optional.of(new Duration[]{Duration.ofDays(4 * 120), Duration.ofDays(120), Duration.ofDays(0)})); + } + + @Test + public void testIntervalMonth(TestContext ctx) { + runQuery(ctx, "SELECT INTERVAL 4 MONTH", Duration.class, Optional.of(Duration.ofDays(30 * 4))); + } + + @Test + public void testIntervalMonthArray(TestContext ctx) { + runQuery(ctx, "SELECT array(toIntervalMonth(4), toIntervalMonth(1), toIntervalMonth(0))", Duration[].class, + Optional.of(new Duration[]{Duration.ofDays(4 * 30), Duration.ofDays(30), Duration.ofDays(0)})); + } + + @Test + public void testIntervalWeek(TestContext ctx) { + runQuery(ctx, "SELECT INTERVAL 4 WEEK", Duration.class, Optional.of(Duration.ofDays(7 * 4))); + } + + @Test + public void testIntervalWeekArray(TestContext ctx) { + runQuery(ctx, "SELECT array(toIntervalWeek(4), toIntervalWeek(1), toIntervalWeek(0))", Duration[].class, + Optional.of(new Duration[]{Duration.ofDays(4 * 7), Duration.ofDays(7), Duration.ofDays(0)})); + } + + public void testIntervalDay(TestContext ctx) { + runQuery(ctx, "SELECT INTERVAL 4 DAY", Duration.class, Optional.of(Duration.ofDays(4))); + } + + @Test + public void testIntervalDayArray(TestContext ctx) { + runQuery(ctx, "SELECT array(toIntervalDay(4), toIntervalDay(1), toIntervalDay(0))", Duration[].class, + Optional.of(new Duration[]{Duration.ofDays(4), Duration.ofDays(1), Duration.ofDays(0)})); + } + + @Test + public void testIntervalHour(TestContext ctx) { + runQuery(ctx, "SELECT INTERVAL 4 HOUR", Duration.class, Optional.of(Duration.ofHours(4))); + } + + @Test + public void testIntervalHourArray(TestContext ctx) { + runQuery(ctx, "SELECT array(toIntervalHour(4), toIntervalHour(1), toIntervalHour(0))", Duration[].class, + Optional.of(new Duration[]{Duration.ofHours(4), Duration.ofHours(1), Duration.ofHours(0)})); + } + + @Test + public void testIntervalMinute(TestContext ctx) { + runQuery(ctx, "SELECT INTERVAL 4 MINUTE", Duration.class, Optional.of(Duration.ofMinutes(4))); + } + + @Test + public void testIntervalMinuteArray(TestContext ctx) { + runQuery(ctx, "SELECT array(toIntervalMinute(4), toIntervalMinute(1), toIntervalMinute(0))", Duration[].class, + Optional.of(new Duration[]{Duration.ofMinutes(4), Duration.ofMinutes(1), Duration.ofMinutes(0)})); + } + + @Test + public void testIntervalSecond(TestContext ctx) { + runQuery(ctx, "SELECT INTERVAL 4 SECOND", Duration.class, Optional.of(Duration.ofSeconds(4))); + } + + @Test + public void testIntervalSecondArray(TestContext ctx) { + runQuery(ctx, "SELECT array(toIntervalSecond(4), toIntervalSecond(1), toIntervalSecond(0))", Duration[].class, + Optional.of(new Duration[]{Duration.ofSeconds(4), Duration.ofSeconds(1), Duration.ofSeconds(0)})); + } + + private void runQuery(TestContext ctx, String query, Class desiredCls, Optional expected) { + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + conn.query(query).execute( + ctx.asyncAssertSuccess(res -> { + ctx.assertEquals(1, res.size()); + if (expected != null && expected.isPresent()) { + Row row = res.iterator().next(); + Object val = desiredCls == null ? row.getValue(0) : row.get(desiredCls, 0); + if (desiredCls.isArray()) { + ctx.assertTrue(Arrays.deepEquals((Object[])expected.get(), (Object[])val)); + } else { + ctx.assertEquals(expected.get(), val); + } + } + })); + })); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/AllTypesBase.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/AllTypesBase.java new file mode 100644 index 000000000..f6a7e014b --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/AllTypesBase.java @@ -0,0 +1,227 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnection; +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.clickhouseclient.binary.Sleep; +import io.vertx.core.Vertx; +import io.vertx.core.impl.logging.Logger; +import io.vertx.core.impl.logging.LoggerFactory; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.ColumnChecker; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.*; +import org.junit.rules.TestName; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +@RunWith(VertxUnitRunner.class) +public abstract class AllTypesBase { + private static final Logger LOG = LoggerFactory.getLogger(AllTypesBase.class); + + public static final String TABLE_PREFIX = "vertx_test_"; + protected final String tableSuffix; + protected final MyColumnChecker checker; + protected final boolean hasLowCardinality; + + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Rule + public TestName nameRule = new TestName(); + + protected ClickhouseBinaryConnectOptions options; + protected Vertx vertx; + + public AllTypesBase(String tableSuffix, MyColumnChecker checker) { + this(tableSuffix, checker, true); + } + + public AllTypesBase(String tableSuffix, MyColumnChecker checker, boolean hasLowCardinality) { + this.tableSuffix = tableSuffix; + this.checker = checker; + this.hasLowCardinality = hasLowCardinality; + } + + @Before + public void setup(TestContext ctx) { + options = rule.options(); + options.addProperty(ClickhouseConstants.OPTION_APPLICATION_NAME, + this.getClass().getSimpleName() + "." + nameRule.getMethodName()); + vertx = Vertx.vertx(); + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + conn.query("TRUNCATE TABLE " + tableName()).execute(ctx.asyncAssertSuccess()); + })); + } + + @After + public void teardDown(TestContext ctx) { + vertx.close(ctx.asyncAssertSuccess()); + } + + @Test + public void testEmptyData(TestContext ctx) { + doTest(ctx, Collections.emptyList()); + } + + @Test + public void testData(TestContext ctx) { + doTest(ctx, createBatch()); + } + + public abstract List createBatch(); + + private List allColumnsList(boolean hasLowCardinality) { + List columns = new ArrayList<>(Arrays.asList("id", "simple_t", "nullable_t", "array_t", "array3_t", "nullable_array_t", "nullable_array3_t")); + if (hasLowCardinality) { + columns.addAll(Arrays.asList("simple_lc_t", "nullable_lc_t", "array_lc_t", "array3_lc_t", "nullable_array_lc_t", "nullable_array3_lc_t")); + } + return columns + .stream() + .map(nm -> new ColumnInfo(nm, true)) + .collect(Collectors.toList()); + } + + protected void doTest(TestContext ctx, List batch) { + String tableName = tableName(); + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + List columnsList = allColumnsList(hasLowCardinality); + List insertColumnNames = columnsList.stream().map(ColumnInfo::name).collect(Collectors.toList()); + String insertColumnsStr = String.join(", ", insertColumnNames); + String insertQuery = "INSERT INTO " + tableName + " (" + insertColumnsStr + ") VALUES"; + conn.preparedQuery(insertQuery) + .executeBatch(batch, ctx.asyncAssertSuccess(res2 -> { + Sleep.sleepOrThrow(); + List selectColumns = columnsList.stream().filter(ColumnInfo::selectEnabled).map(ColumnInfo::name).collect(Collectors.toList()); + String selectColumnsStr = String.join(", ", selectColumns); + conn.query("SELECT " + selectColumnsStr + " FROM " + tableName + " ORDER BY id").execute(ctx.asyncAssertSuccess( + res3 -> { + ctx.assertEquals(res3.size(), batch.size(), "row count mismatch"); + int batchIdx = 0; + for (Row actualRow : res3) { + Number id = actualRow.get(Number.class, "id"); + Tuple expectedRow = batch.get(batchIdx); + LOG.info("checking row " + tableSuffix + ":" + id); + for (int colIdx = 0; colIdx < expectedRow.size(); ++colIdx) { + ColumnInfo columnInfo = columnsList.get(colIdx); + if (columnInfo.selectEnabled()) { + String colName = columnInfo.name(); + Object expectedColumnValue = expectedRow.getValue(colIdx); + int actualColIdx = actualRow.getColumnIndex(colName); + checker.checkColumn(actualRow, actualColIdx, colName, (T) expectedColumnValue); + } + } + ++batchIdx; + } + })); + })); + })); + } + + protected String tableName() { + return TABLE_PREFIX + tableSuffix; + } +} + +class MyColumnChecker { + private final Class componentType; + private final ColumnChecker.SerializableBiFunction byIndexGetter; + private final ColumnChecker.SerializableBiFunction byNameGetter; + private final ColumnChecker.SerializableBiFunction arrayByIndexGetter; + private final ColumnChecker.SerializableBiFunction arrayByNameGetter; + + public MyColumnChecker(Class componentType, + ColumnChecker.SerializableBiFunction byIndexGetter, + ColumnChecker.SerializableBiFunction byNameGetter, + ColumnChecker.SerializableBiFunction arrayByIndexGetter, + ColumnChecker.SerializableBiFunction arrayByNameGetter) { + this.componentType = componentType; + this.byIndexGetter = byIndexGetter; + this.byNameGetter = byNameGetter; + this.arrayByNameGetter = arrayByNameGetter; + this.arrayByIndexGetter = arrayByIndexGetter; + } + + public void checkColumn(Row row, int index, String name, R expected) { + ColumnChecker checker = ColumnChecker.checkColumn(index, name); + if ("id".equals(name)) { + checker.returns((Class)expected.getClass(), expected) + .forRow(row); + return; + } + if (componentType == byte[].class && (expected == null || expected.getClass() == byte[].class)) { + //ask driver to turn off String encoding + checker = checker + .returns((tuple, idx) -> tuple.get(byte[].class, idx), + (ColumnChecker.SerializableBiFunction) (r, colName) -> r.get(byte[].class, colName), + (Consumer) actual -> Assert.assertArrayEquals((byte[])actual, (byte[])expected)); + } else { + //arrays are non-nullable + if (expected != null && expected.getClass().isArray()) { + boolean multidimensional = expected.getClass().getComponentType().isArray() && expected.getClass().getComponentType() != byte[].class; + if (componentType == byte[].class || componentType.isEnum()) { + //ask driver to turn off String encoding for BLOBs or force encoding for Enums + checker = checker.returns((tuple, idx) -> tuple.get(expected.getClass(), idx), (r, colName) -> r.get(expected.getClass(), colName), (Object[]) expected); + } else { + checker = checker.returns(Tuple::getValue, Row::getValue, (Object[]) expected); + } + if (!multidimensional && arrayByIndexGetter != null) { + //API does not provide dedicated methods to get multi-dimensional arrays + checker = checker.returns(arrayByIndexGetter, arrayByNameGetter, (Object[]) expected); + } + } else { + //regular non-array elements + Object v = expected; + if (componentType.isEnum()) { + v = expected == null ? null : (R) ((Enum)expected).name(); + } + checker = checker.returns(Tuple::getValue, Row::getValue, v); + if (byIndexGetter != null) { + checker = checker.returns(byIndexGetter, byNameGetter, expected); + } + } + } + checker.forRow(row); + } +} + + +class ColumnInfo { + private final String name; + private final boolean selectEnabled; + + ColumnInfo(String name, boolean selectEnabled) { + this.name = name; + this.selectEnabled = selectEnabled; + } + + public String name() { + return name; + } + + public boolean selectEnabled() { + return selectEnabled; + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/BlobTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/BlobTest.java new file mode 100644 index 000000000..b72fde37f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/BlobTest.java @@ -0,0 +1,79 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class BlobTest extends AllTypesBase { + public BlobTest() { + super("string", new MyColumnChecker<>(byte[].class, null, null, null, null)); + } + + protected static byte[] b(String s) { + return s.getBytes(StandardCharsets.UTF_8); + } + + @Override + public List createBatch() { + byte[] v1 = b("val1"); + byte[] v2 = b("val2"); + byte[] v3 = b("val3"); + byte[] v4 = b("val4"); + byte[] v5 = b("value5"); + byte[] v6 = b("value_value_6"); + byte[] nv = b(""); + byte[] mn = b(""); + byte[] mx = b("not so looooooooooooooooooooooooooooooooooooooong value"); + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new byte[][]{mn, mn}, new byte[][][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, mn}, new byte[][][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new byte[][]{mn, mn}, new byte[][][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, mn}, new byte[][][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new byte[][]{mn, mn}, new byte[][][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, mn}, new byte[][][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new byte[][]{mn, mn}, new byte[][][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, mn}, new byte[][][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new byte[][]{mn, mn}, new byte[][][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, null, mn}, new byte[][][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new byte[][]{mn, mn}, new byte[][][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, null, mn}, new byte[][][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new byte[][]{mn, mn}, new byte[][][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, null, mn}, new byte[][][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new byte[][]{mn, mn}, new byte[][][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, null, mn}, new byte[][][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mx, mx}, new byte[][][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mx, null, mx}, new byte[][][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mx, null, mx}, new byte[][][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mx, null, mx}, new byte[][][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mx, null, mx}, new byte[][][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mx, null, mx}, new byte[][][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new byte[][]{mx, mx}, new byte[][][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mx, null, mx}, new byte[][][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new byte[][]{mn, mx}, new byte[][][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, null, mx}, new byte[][][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new byte[][]{mn, mx}, new byte[][][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, null, mx}, new byte[][][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new byte[][]{mn, mx}, new byte[][][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, null, mx}, new byte[][][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new byte[][]{mn, mx}, new byte[][][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{mn, null, mx}, new byte[][][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new byte[][]{}, new byte[][][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{}, new byte[][][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new byte[][]{}, new byte[][][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{}, new byte[][][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new byte[][]{}, new byte[][][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{}, new byte[][][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new byte[][]{}, new byte[][][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{}, new byte[][][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new byte[][]{}, new byte[][][][]{{{}}}, new byte[][]{}, new byte[][][][]{{{}}}, v2, v3, new byte[][]{}, new byte[][][][]{{{}}}, new byte[][]{}, new byte[][][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new byte[][]{}, new byte[][][][]{{{}}}, new byte[][]{}, new byte[][][][]{{{}}}, v2, v3, new byte[][]{}, new byte[][][][]{{{}}}, new byte[][]{}, new byte[][][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new byte[][]{}, new byte[][][][]{{{}}}, new byte[][]{null}, new byte[][][][]{{{null}}}, v2, v3, new byte[][]{}, new byte[][][][]{{{}}}, new byte[][]{null}, new byte[][][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new byte[][]{}, new byte[][][][]{{{}}}, new byte[][]{null}, new byte[][][][]{{{null}}}, v2, v3, new byte[][]{}, new byte[][][][]{{{}}}, new byte[][]{null}, new byte[][][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new byte[][]{nv}, new byte[][][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv}, new byte[][][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new byte[][]{nv}, new byte[][][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv}, new byte[][][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new byte[][]{nv}, new byte[][][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv}, new byte[][][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new byte[][]{nv}, new byte[][][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv}, new byte[][][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new byte[][]{nv, mn, mx}, new byte[][][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, mn, null, mx}, new byte[][][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new byte[][]{nv, mn, mx}, new byte[][][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv}, new byte[][][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new byte[][]{nv, mn, mx}, new byte[][][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, mn, null, mx}, new byte[][][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new byte[][]{nv, mn, mx}, new byte[][][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv}, new byte[][][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new byte[][]{nv, mn, mx}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, mn, null, mx}, new byte[][][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new byte[][]{nv, mn, mx}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, mn, null, mx}, new byte[][][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new byte[][]{nv, mn, mx}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, mn, null, mx}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new byte[][]{nv, mn, mx}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, mn, null, mx}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new byte[][]{v3, v1, nv, mx, v4}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v3, v1, null, nv, mx, v3}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new byte[][]{v3, v1, nv, mx, v4}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, v2, null, v3, v2}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new byte[][]{v3, v1, nv, mx, v4}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v3, v1, null, nv, mx, v3}, new byte[][][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new byte[][]{v3, v1, nv, mx, v4}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, v2, null, v3, v2}, new byte[][][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new byte[][]{v1, nv, nv}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v3, nv, null}, new byte[][][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new byte[][]{v1, nv, nv}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v2, nv, null}, new byte[][][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new byte[][]{nv, nv, nv}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, null, v4}, new byte[][][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new byte[][]{nv, nv, nv}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{nv, null, nv}, new byte[][][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new byte[][]{v4, nv, nv}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v3, nv, null}, new byte[][][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new byte[][]{v4, nv, nv}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v2, nv, null}, new byte[][][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new byte[][]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new byte[][][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new byte[][]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new byte[][][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new byte[][]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new byte[][][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new byte[][]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new byte[][][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new byte[][]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new byte[][][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/BooleanTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/BooleanTest.java new file mode 100644 index 000000000..0ab504e99 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/BooleanTest.java @@ -0,0 +1,61 @@ +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class BooleanTest extends AllTypesBase { + public BooleanTest() { + super("boolean", new MyColumnChecker<>(Boolean.class, null, null, null, null)); + } + + @Override + public List createBatch() { + Boolean v1 = Boolean.TRUE; + Boolean v2 = Boolean.TRUE; + Boolean v3 = Boolean.TRUE; + Boolean v4 = Boolean.FALSE; + Boolean v5 = Boolean.FALSE; + Boolean v6 = Boolean.TRUE; + Boolean nv = Boolean.FALSE; + Boolean mn = Boolean.FALSE; + Boolean mx = Boolean.TRUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, null, mn}, new Boolean[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, null, mn}, new Boolean[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, null, mn}, new Boolean[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Boolean[]{mn, mn}, new Boolean[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, null, mn}, new Boolean[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mx, null, mx}, new Boolean[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mx, null, mx}, new Boolean[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mx, null, mx}, new Boolean[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mx, null, mx}, new Boolean[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mx, null, mx}, new Boolean[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Boolean[]{mx, mx}, new Boolean[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mx, null, mx}, new Boolean[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Boolean[]{mn, mx}, new Boolean[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, null, mx}, new Boolean[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Boolean[]{mn, mx}, new Boolean[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, null, mx}, new Boolean[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Boolean[]{mn, mx}, new Boolean[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, null, mx}, new Boolean[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Boolean[]{mn, mx}, new Boolean[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{mn, null, mx}, new Boolean[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{}, new Boolean[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{}, new Boolean[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{}, new Boolean[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{}, new Boolean[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}}}, new Boolean[]{}, new Boolean[][][]{{{}}}, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}}}, new Boolean[]{}, new Boolean[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}}}, new Boolean[]{}, new Boolean[][][]{{{}}}, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}}}, new Boolean[]{}, new Boolean[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}}}, new Boolean[]{null}, new Boolean[][][]{{{null}}}, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}}}, new Boolean[]{null}, new Boolean[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}}}, new Boolean[]{null}, new Boolean[][][]{{{null}}}, v2, v3, new Boolean[]{}, new Boolean[][][]{{{}}}, new Boolean[]{null}, new Boolean[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Boolean[]{nv}, new Boolean[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv}, new Boolean[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Boolean[]{nv}, new Boolean[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv}, new Boolean[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Boolean[]{nv}, new Boolean[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv}, new Boolean[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Boolean[]{nv}, new Boolean[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv}, new Boolean[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Boolean[]{nv, mn, mx}, new Boolean[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, mn, null, mx}, new Boolean[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Boolean[]{nv, mn, mx}, new Boolean[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv}, new Boolean[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Boolean[]{nv, mn, mx}, new Boolean[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, mn, null, mx}, new Boolean[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Boolean[]{nv, mn, mx}, new Boolean[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv}, new Boolean[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Boolean[]{nv, mn, mx}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, mn, null, mx}, new Boolean[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Boolean[]{nv, mn, mx}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, mn, null, mx}, new Boolean[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Boolean[]{nv, mn, mx}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, mn, null, mx}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Boolean[]{nv, mn, mx}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, mn, null, mx}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Boolean[]{v3, v1, nv, mx, v4}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v3, v1, null, nv, mx, v3}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Boolean[]{v3, v1, nv, mx, v4}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, v2, null, v3, v2}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Boolean[]{v3, v1, nv, mx, v4}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v3, v1, null, nv, mx, v3}, new Boolean[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Boolean[]{v3, v1, nv, mx, v4}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, v2, null, v3, v2}, new Boolean[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Boolean[]{v1, nv, nv}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v3, nv, null}, new Boolean[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Boolean[]{v1, nv, nv}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v2, nv, null}, new Boolean[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Boolean[]{nv, nv, nv}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, null, v4}, new Boolean[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Boolean[]{nv, nv, nv}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{nv, null, nv}, new Boolean[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Boolean[]{v4, nv, nv}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v3, nv, null}, new Boolean[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Boolean[]{v4, nv, nv}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v2, nv, null}, new Boolean[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Boolean[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Boolean[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Boolean[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Boolean[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Boolean[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Boolean[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Boolean[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Boolean[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Boolean[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Boolean[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTest.java new file mode 100644 index 000000000..7a1b868fa --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTest.java @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.DateColumnReader; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.time.LocalDate; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class DateTest extends AllTypesBase { + public DateTest() { + super("date", new MyColumnChecker<>(LocalDate.class, Tuple::getLocalDate, Row::getLocalDate, Tuple::getArrayOfLocalDates, Row::getArrayOfLocalDates)); + } + + @Override + public List createBatch() { + LocalDate v1 = LocalDate.of(2020, 3, 29); + LocalDate v2 = v1.plusDays(2); + LocalDate v3 = v2.plusDays(3); + LocalDate v4 = v1.minusDays(2); + LocalDate v5 = v2.minusDays(3); + LocalDate v6 = v2.minusDays(4); + LocalDate nv = DateColumnReader.MIN_VALUE; + LocalDate mn = DateColumnReader.MIN_VALUE; + LocalDate mx = DateColumnReader.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, null, mn}, new LocalDate[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, null, mn}, new LocalDate[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, null, mn}, new LocalDate[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new LocalDate[]{mn, mn}, new LocalDate[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, null, mn}, new LocalDate[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mx, null, mx}, new LocalDate[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mx, null, mx}, new LocalDate[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mx, null, mx}, new LocalDate[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mx, null, mx}, new LocalDate[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mx, null, mx}, new LocalDate[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new LocalDate[]{mx, mx}, new LocalDate[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mx, null, mx}, new LocalDate[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new LocalDate[]{mn, mx}, new LocalDate[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, null, mx}, new LocalDate[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new LocalDate[]{mn, mx}, new LocalDate[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, null, mx}, new LocalDate[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new LocalDate[]{mn, mx}, new LocalDate[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, null, mx}, new LocalDate[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new LocalDate[]{mn, mx}, new LocalDate[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{mn, null, mx}, new LocalDate[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{}, new LocalDate[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{}, new LocalDate[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{}, new LocalDate[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{}, new LocalDate[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}}}, new LocalDate[]{}, new LocalDate[][][]{{{}}}, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}}}, new LocalDate[]{}, new LocalDate[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}}}, new LocalDate[]{}, new LocalDate[][][]{{{}}}, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}}}, new LocalDate[]{}, new LocalDate[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}}}, new LocalDate[]{null}, new LocalDate[][][]{{{null}}}, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}}}, new LocalDate[]{null}, new LocalDate[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}}}, new LocalDate[]{null}, new LocalDate[][][]{{{null}}}, v2, v3, new LocalDate[]{}, new LocalDate[][][]{{{}}}, new LocalDate[]{null}, new LocalDate[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new LocalDate[]{nv}, new LocalDate[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv}, new LocalDate[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new LocalDate[]{nv}, new LocalDate[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv}, new LocalDate[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new LocalDate[]{nv}, new LocalDate[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv}, new LocalDate[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new LocalDate[]{nv}, new LocalDate[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv}, new LocalDate[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new LocalDate[]{nv, mn, mx}, new LocalDate[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, mn, null, mx}, new LocalDate[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new LocalDate[]{nv, mn, mx}, new LocalDate[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv}, new LocalDate[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new LocalDate[]{nv, mn, mx}, new LocalDate[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, mn, null, mx}, new LocalDate[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new LocalDate[]{nv, mn, mx}, new LocalDate[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv}, new LocalDate[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new LocalDate[]{nv, mn, mx}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, mn, null, mx}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new LocalDate[]{nv, mn, mx}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, mn, null, mx}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new LocalDate[]{nv, mn, mx}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, mn, null, mx}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new LocalDate[]{nv, mn, mx}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, mn, null, mx}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new LocalDate[]{v3, v1, nv, mx, v4}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v3, v1, null, nv, mx, v3}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new LocalDate[]{v3, v1, nv, mx, v4}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, v2, null, v3, v2}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new LocalDate[]{v3, v1, nv, mx, v4}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v3, v1, null, nv, mx, v3}, new LocalDate[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new LocalDate[]{v3, v1, nv, mx, v4}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, v2, null, v3, v2}, new LocalDate[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new LocalDate[]{v1, nv, nv}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v3, nv, null}, new LocalDate[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new LocalDate[]{v1, nv, nv}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v2, nv, null}, new LocalDate[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new LocalDate[]{nv, nv, nv}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, null, v4}, new LocalDate[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new LocalDate[]{nv, nv, nv}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{nv, null, nv}, new LocalDate[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new LocalDate[]{v4, nv, nv}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v3, nv, null}, new LocalDate[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new LocalDate[]{v4, nv, nv}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v2, nv, null}, new LocalDate[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new LocalDate[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new LocalDate[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new LocalDate[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new LocalDate[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new LocalDate[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new LocalDate[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new LocalDate[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new LocalDate[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTime64Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTime64Test.java new file mode 100644 index 000000000..9a3b6834f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTime64Test.java @@ -0,0 +1,80 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.DateTimeColumnReader; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class DateTime64Test extends AllTypesBase { + public DateTime64Test() { + super("datetime64", new MyColumnChecker<>(OffsetDateTime.class, Tuple::getOffsetDateTime, Row::getOffsetDateTime, Tuple::getArrayOfOffsetDateTimes, Row::getArrayOfOffsetDateTimes), false); + } + + @Override + public List createBatch() { + ZoneId zoneId = ZoneId.of("Europe/Oslo"); + OffsetDateTime v1 = Instant.ofEpochSecond(1617120094L, 300).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v2 = Instant.ofEpochSecond(1617120094L + 10L, 400).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v3 = Instant.ofEpochSecond(1617120094L + 20L, 500).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v4 = Instant.ofEpochSecond(1617120094L - 10L, 600).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v5 = Instant.ofEpochSecond(1617120094L - 20L, 700).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v6 = Instant.ofEpochSecond(1617120094L - 200L, 800).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime nv = Instant.ofEpochSecond(0, 0).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime mn = Instant.ofEpochSecond(0, 0).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime mx = Instant.ofEpochSecond(DateTimeColumnReader.MAX_EPOCH_SECOND, 999).atZone(zoneId).toOffsetDateTime(); + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t + Tuple.of((byte)1, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mn}, new OffsetDateTime[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mn}, new OffsetDateTime[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, null, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, null, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new OffsetDateTime[]{mn, mx}, new OffsetDateTime[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mx}, new OffsetDateTime[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new OffsetDateTime[]{mn, mx}, new OffsetDateTime[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mx}, new OffsetDateTime[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{null}, new OffsetDateTime[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{null}, new OffsetDateTime[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new OffsetDateTime[]{v3, v1, nv, mx, v4}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v3, v1, null, nv, mx, v3}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new OffsetDateTime[]{v3, v1, nv, mx, v4}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v3, v1, null, nv, mx, v3}, new OffsetDateTime[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new OffsetDateTime[]{v1, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v3, nv, null}, new OffsetDateTime[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new OffsetDateTime[]{nv, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, null, v4}, new OffsetDateTime[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new OffsetDateTime[]{v4, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v3, nv, null}, new OffsetDateTime[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTimeTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTimeTest.java new file mode 100644 index 000000000..33c9dd37e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/DateTimeTest.java @@ -0,0 +1,81 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.DateTimeColumnReader; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class DateTimeTest extends AllTypesBase { + + public DateTimeTest() { + super("datetime", new MyColumnChecker<>(OffsetDateTime.class, Tuple::getOffsetDateTime, Row::getOffsetDateTime, Tuple::getArrayOfOffsetDateTimes, Row::getArrayOfOffsetDateTimes)); + } + + @Override + public List createBatch() { + ZoneId zoneId = ZoneId.of("Europe/Oslo"); + OffsetDateTime v1 = Instant.ofEpochSecond(1617120094L).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v2 = Instant.ofEpochSecond(1617120094L + 10L).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v3 = Instant.ofEpochSecond(1617120094L + 20L).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v4 = Instant.ofEpochSecond(1617120094L - 10L).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v5 = Instant.ofEpochSecond(1617120094L - 20L).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime v6 = Instant.ofEpochSecond(1617120094L - 200L).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime nv = Instant.ofEpochSecond(0).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime mn = Instant.ofEpochSecond(0).atZone(zoneId).toOffsetDateTime(); + OffsetDateTime mx = Instant.ofEpochSecond(DateTimeColumnReader.MAX_EPOCH_SECOND).atZone(zoneId).toOffsetDateTime(); + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mn}, new OffsetDateTime[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mn}, new OffsetDateTime[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mn}, new OffsetDateTime[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new OffsetDateTime[]{mn, mn}, new OffsetDateTime[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mn}, new OffsetDateTime[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, null, mx}, new OffsetDateTime[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, null, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, null, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, null, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, null, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new OffsetDateTime[]{mx, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mx, null, mx}, new OffsetDateTime[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new OffsetDateTime[]{mn, mx}, new OffsetDateTime[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mx}, new OffsetDateTime[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new OffsetDateTime[]{mn, mx}, new OffsetDateTime[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mx}, new OffsetDateTime[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new OffsetDateTime[]{mn, mx}, new OffsetDateTime[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mx}, new OffsetDateTime[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new OffsetDateTime[]{mn, mx}, new OffsetDateTime[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{mn, null, mx}, new OffsetDateTime[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{null}, new OffsetDateTime[][][]{{{null}}}, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{null}, new OffsetDateTime[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{null}, new OffsetDateTime[][][]{{{null}}}, v2, v3, new OffsetDateTime[]{}, new OffsetDateTime[][][]{{{}}}, new OffsetDateTime[]{null}, new OffsetDateTime[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv}, new OffsetDateTime[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new OffsetDateTime[]{nv, mn, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, mn, null, mx}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new OffsetDateTime[]{v3, v1, nv, mx, v4}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v3, v1, null, nv, mx, v3}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new OffsetDateTime[]{v3, v1, nv, mx, v4}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, v2, null, v3, v2}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new OffsetDateTime[]{v3, v1, nv, mx, v4}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v3, v1, null, nv, mx, v3}, new OffsetDateTime[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new OffsetDateTime[]{v3, v1, nv, mx, v4}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, v2, null, v3, v2}, new OffsetDateTime[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new OffsetDateTime[]{v1, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v3, nv, null}, new OffsetDateTime[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new OffsetDateTime[]{v1, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v2, nv, null}, new OffsetDateTime[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new OffsetDateTime[]{nv, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, null, v4}, new OffsetDateTime[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new OffsetDateTime[]{nv, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{nv, null, nv}, new OffsetDateTime[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new OffsetDateTime[]{v4, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v3, nv, null}, new OffsetDateTime[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new OffsetDateTime[]{v4, nv, nv}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v2, nv, null}, new OffsetDateTime[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new OffsetDateTime[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new OffsetDateTime[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal128Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal128Test.java new file mode 100644 index 000000000..91d6c125d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal128Test.java @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.Decimal128Column; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import org.junit.runner.RunWith; + +import java.math.MathContext; +import java.math.RoundingMode; + +@RunWith(VertxUnitRunner.class) +public class Decimal128Test extends HugeDecimalTest { + public Decimal128Test() { + super("decimal128", new MathContext(Decimal128Column.MAX_PRECISION, RoundingMode.HALF_EVEN)); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal256Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal256Test.java new file mode 100644 index 000000000..1d40bb71c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal256Test.java @@ -0,0 +1,28 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.Decimal256Column; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import org.junit.runner.RunWith; + +import java.math.MathContext; +import java.math.RoundingMode; + +@RunWith(VertxUnitRunner.class) +public class Decimal256Test extends HugeDecimalTest { + public Decimal256Test() { + super("decimal256", new MathContext(Decimal256Column.MAX_PRECISION, RoundingMode.HALF_EVEN)); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal32Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal32Test.java new file mode 100644 index 000000000..1ef2366ba --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal32Test.java @@ -0,0 +1,97 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.Decimal32Column; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class Decimal32Test extends AllTypesBase { + public static final int SCALE = 4; + + public static final MathContext MATH_CONTEXT = new MathContext(Decimal32Column.MAX_PRECISION, RoundingMode.HALF_EVEN); + + public Decimal32Test() { + super("decimal32", new MyColumnChecker<>(Numeric.class, Tuple::getNumeric, Row::getNumeric, Tuple::getArrayOfNumerics, Row::getArrayOfNumerics), false); + } + + private Numeric nm(Integer src) { + BigInteger bi = BigInteger.valueOf(src); + BigDecimal bd = new BigDecimal(bi, SCALE, MATH_CONTEXT); + return Numeric.create(bd); + } + + @Override + public List createBatch() { + int mni = Integer.MAX_VALUE / 3; + int mxi = Integer.MIN_VALUE / 3; + + Numeric v1 = nm(mxi / 3); + Numeric v2 = nm(mni / 3); + Numeric v3 = nm(mxi / 4); + Numeric v4 = nm(mni / 4); + Numeric v5 = nm(mxi / 5); + Numeric v6 = nm(mni / 5); + Numeric nv = nm(0); + + Numeric mn = nm(mni); + Numeric mx = nm(mxi); + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t + Tuple.of((byte)1, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, v1, null, nv, mx, v3}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, v1, null, nv, mx, v3}, new Numeric[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Numeric[]{v1, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Numeric[]{nv, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, null, v4}, new Numeric[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Numeric[]{v4, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal64Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal64Test.java new file mode 100644 index 000000000..5dc3969d2 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Decimal64Test.java @@ -0,0 +1,94 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.Decimal64Column; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; +import org.junit.runner.RunWith; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.math.RoundingMode; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class Decimal64Test extends AllTypesBase { + public static final int SCALE = 4; + + public static final MathContext MATH_CONTEXT = new MathContext(Decimal64Column.MAX_PRECISION, RoundingMode.HALF_EVEN); + + public Decimal64Test() { + super("decimal64", new MyColumnChecker<>(Numeric.class, Tuple::getNumeric, Row::getNumeric, Tuple::getArrayOfNumerics, Row::getArrayOfNumerics), false); + } + + private Numeric nm(Long src) { + BigInteger bi = BigInteger.valueOf(src); + BigDecimal bd = new BigDecimal(bi, SCALE, MATH_CONTEXT); + return Numeric.create(bd); + } + + @Override + public List createBatch() { + long mnl = Long.MIN_VALUE / 10; + long mxl = Long.MAX_VALUE / 10; + + Numeric v1 = nm(mxl / 3); + Numeric v2 = nm(mnl / 4); + Numeric v3 = nm(mxl / 5); + Numeric v4 = nm(mnl / 6); + Numeric v5 = nm(mxl / 7); + Numeric v6 = nm(mnl / 7); + Numeric nv = nm(0L); + Numeric mn = nm(mnl); + Numeric mx = nm(mxl); + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t + Tuple.of((byte)1, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, v1, null, nv, mx, v3}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, v1, null, nv, mx, v3}, new Numeric[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Numeric[]{v1, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Numeric[]{nv, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, null, v4}, new Numeric[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Numeric[]{v4, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Enum16Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Enum16Test.java new file mode 100644 index 000000000..d37ad1326 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Enum16Test.java @@ -0,0 +1,25 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class Enum16Test extends EnumTest { + public Enum16Test() { + super("enum16"); + } +} + diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Enum8Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Enum8Test.java new file mode 100644 index 000000000..4bff0e1cd --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Enum8Test.java @@ -0,0 +1,24 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class Enum8Test extends EnumTest { + public Enum8Test() { + super("enum8"); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/EnumTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/EnumTest.java new file mode 100644 index 000000000..3cad32264 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/EnumTest.java @@ -0,0 +1,77 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.sqlclient.Tuple; + +import java.util.Arrays; +import java.util.List; + +public abstract class EnumTest extends AllTypesBase { + public EnumTest(String tableSuffix) { + this(tableSuffix, TestEnum.class); + } + + private EnumTest(String tableSuffix, Class cls) { + super(tableSuffix, new MyColumnChecker<>(cls, + (row, idx) -> row.get(cls, idx), (tp, name) -> tp.get(cls, name), null, null), false); + } + + @Override + public List createBatch() { + TestEnum v1 = TestEnum.v0; + TestEnum v2 = TestEnum.v1; + TestEnum v3 = TestEnum.v2; + TestEnum v4 = TestEnum.v3; + TestEnum v5 = TestEnum.v4; + TestEnum v6 = TestEnum.v5; + TestEnum nv = TestEnum.v0; + TestEnum mn = TestEnum.v3; + TestEnum mx = TestEnum.v6; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t + Tuple.of((byte)1, mn, mn, new TestEnum[]{mn, mn}, new TestEnum[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mn, mn}, new TestEnum[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new TestEnum[]{mn, mn}, new TestEnum[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mn, mn}, new TestEnum[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new TestEnum[]{mn, mn}, new TestEnum[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mn, null, mn}, new TestEnum[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new TestEnum[]{mn, mn}, new TestEnum[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mn, null, mn}, new TestEnum[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new TestEnum[]{mx, mx}, new TestEnum[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mx, mx}, new TestEnum[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new TestEnum[]{mx, mx}, new TestEnum[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mx, mx}, new TestEnum[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new TestEnum[]{mx, mx}, new TestEnum[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mx, null, mx}, new TestEnum[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new TestEnum[]{mx, mx}, new TestEnum[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mx, null, mx}, new TestEnum[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new TestEnum[]{mn, mx}, new TestEnum[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mn, null, mx}, new TestEnum[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new TestEnum[]{mn, mx}, new TestEnum[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{mn, null, mx}, new TestEnum[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new TestEnum[]{}, new TestEnum[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{}, new TestEnum[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new TestEnum[]{}, new TestEnum[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{}, new TestEnum[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new TestEnum[]{}, new TestEnum[][][]{{{}}}, new TestEnum[]{}, new TestEnum[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new TestEnum[]{}, new TestEnum[][][]{{{}}}, new TestEnum[]{}, new TestEnum[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new TestEnum[]{}, new TestEnum[][][]{{{}}}, new TestEnum[]{null}, new TestEnum[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new TestEnum[]{}, new TestEnum[][][]{{{}}}, new TestEnum[]{null}, new TestEnum[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new TestEnum[]{nv}, new TestEnum[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{nv}, new TestEnum[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new TestEnum[]{nv}, new TestEnum[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{nv}, new TestEnum[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new TestEnum[]{nv, mn, mx}, new TestEnum[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{nv, mn, null, mx}, new TestEnum[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new TestEnum[]{nv, mn, mx}, new TestEnum[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{nv, mn, null, mx}, new TestEnum[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new TestEnum[]{nv, mn, mx}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{nv, mn, null, mx}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new TestEnum[]{nv, mn, mx}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{nv, mn, null, mx}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new TestEnum[]{v3, v1, nv, mx, v4}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{v3, v1, null, nv, mx, v3}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new TestEnum[]{v3, v1, nv, mx, v4}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{v3, v1, null, nv, mx, v3}, new TestEnum[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new TestEnum[]{v1, nv, nv}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{v3, nv, null}, new TestEnum[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new TestEnum[]{nv, nv, nv}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{nv, null, v4}, new TestEnum[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new TestEnum[]{v4, nv, nv}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{v3, nv, null}, new TestEnum[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new TestEnum[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new TestEnum[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new TestEnum[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new TestEnum[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new TestEnum[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} + diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/FixedStringTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/FixedStringTest.java new file mode 100644 index 000000000..694281be9 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/FixedStringTest.java @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class FixedStringTest extends AllTypesBase { + public FixedStringTest() { + super("fixedstring", new MyColumnChecker<>(String.class, Tuple::getString, Row::getString, Tuple::getArrayOfStrings, Row::getArrayOfStrings)); + } + + @Test + public void testArrayDeduplication(TestContext ctx) { + new StringArrayDeduplicationTester(tableName(), vertx, options).test(ctx); + } + + @Override + public List createBatch() { + String v1 = "val1"; + String v2 = "val2"; + String v3 = "val3"; + String v4 = "val4"; + String v5 = "value5"; + String v6 = "v6"; + String nv = ""; + String mn = ""; + String mx = "123456789123"; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, mn}, new String[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, mn}, new String[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, mn}, new String[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, mn}, new String[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mn}, new String[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mn}, new String[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mn}, new String[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mn}, new String[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, mx}, new String[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new String[]{mn, mx}, new String[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mx}, new String[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new String[]{mn, mx}, new String[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mx}, new String[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new String[]{mn, mx}, new String[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mx}, new String[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new String[]{mn, mx}, new String[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mx}, new String[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new String[]{}, new String[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{}, new String[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new String[]{}, new String[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{}, new String[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new String[]{}, new String[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{}, new String[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new String[]{}, new String[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{}, new String[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{}, new String[][][]{{{}}}, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{}, new String[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{}, new String[][][]{{{}}}, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{}, new String[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{null}, new String[][][]{{{null}}}, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{null}, new String[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{null}, new String[][][]{{{null}}}, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{null}, new String[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new String[]{v3, v1, nv, mx, v4}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v3, v1, null, nv, mx, v3}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new String[]{v3, v1, nv, mx, v4}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, v2, null, v3, v2}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new String[]{v3, v1, nv, mx, v4}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v3, v1, null, nv, mx, v3}, new String[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new String[]{v3, v1, nv, mx, v4}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, v2, null, v3, v2}, new String[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new String[]{v1, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v3, nv, null}, new String[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new String[]{v1, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v2, nv, null}, new String[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new String[]{nv, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, null, v4}, new String[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new String[]{nv, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, null, nv}, new String[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new String[]{v4, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v3, nv, null}, new String[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new String[]{v4, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v2, nv, null}, new String[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new String[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new String[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new String[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new String[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Float32Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Float32Test.java new file mode 100644 index 000000000..9c0078087 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Float32Test.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class Float32Test extends AllTypesBase { + public Float32Test() { + super("float32", new MyColumnChecker<>(Float.class, Tuple::getFloat, Row::getFloat, Tuple::getArrayOfFloats, Row::getArrayOfFloats)); + } + + @Override + public List createBatch() { + Float v1 = Float.MAX_VALUE / 2; + Float v2 = Float.MIN_VALUE / 2; + Float v3 = Float.MAX_VALUE / 3; + Float v4 = Float.NaN; + Float v5 = Float.NEGATIVE_INFINITY; + Float v6 = Float.POSITIVE_INFINITY; + Float nv = 0.0f; + Float mn = Float.MIN_VALUE; + Float mx = Float.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Float[]{mn, mn}, new Float[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, mn}, new Float[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Float[]{mn, mn}, new Float[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, mn}, new Float[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Float[]{mn, mn}, new Float[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, mn}, new Float[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Float[]{mn, mn}, new Float[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, mn}, new Float[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Float[]{mn, mn}, new Float[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, null, mn}, new Float[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Float[]{mn, mn}, new Float[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, null, mn}, new Float[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Float[]{mn, mn}, new Float[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, null, mn}, new Float[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Float[]{mn, mn}, new Float[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, null, mn}, new Float[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mx, mx}, new Float[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mx, null, mx}, new Float[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mx, null, mx}, new Float[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mx, null, mx}, new Float[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mx, null, mx}, new Float[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mx, null, mx}, new Float[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Float[]{mx, mx}, new Float[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mx, null, mx}, new Float[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Float[]{mn, mx}, new Float[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, null, mx}, new Float[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Float[]{mn, mx}, new Float[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, null, mx}, new Float[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Float[]{mn, mx}, new Float[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, null, mx}, new Float[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Float[]{mn, mx}, new Float[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{mn, null, mx}, new Float[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Float[]{}, new Float[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{}, new Float[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Float[]{}, new Float[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{}, new Float[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Float[]{}, new Float[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{}, new Float[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Float[]{}, new Float[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{}, new Float[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Float[]{}, new Float[][][]{{{}}}, new Float[]{}, new Float[][][]{{{}}}, v2, v3, new Float[]{}, new Float[][][]{{{}}}, new Float[]{}, new Float[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Float[]{}, new Float[][][]{{{}}}, new Float[]{}, new Float[][][]{{{}}}, v2, v3, new Float[]{}, new Float[][][]{{{}}}, new Float[]{}, new Float[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Float[]{}, new Float[][][]{{{}}}, new Float[]{null}, new Float[][][]{{{null}}}, v2, v3, new Float[]{}, new Float[][][]{{{}}}, new Float[]{null}, new Float[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Float[]{}, new Float[][][]{{{}}}, new Float[]{null}, new Float[][][]{{{null}}}, v2, v3, new Float[]{}, new Float[][][]{{{}}}, new Float[]{null}, new Float[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Float[]{nv}, new Float[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv}, new Float[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Float[]{nv}, new Float[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv}, new Float[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Float[]{nv}, new Float[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv}, new Float[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Float[]{nv}, new Float[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv}, new Float[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Float[]{nv, mn, mx}, new Float[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, mn, null, mx}, new Float[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Float[]{nv, mn, mx}, new Float[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv}, new Float[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Float[]{nv, mn, mx}, new Float[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, mn, null, mx}, new Float[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Float[]{nv, mn, mx}, new Float[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv}, new Float[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Float[]{nv, mn, mx}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, mn, null, mx}, new Float[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Float[]{nv, mn, mx}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, mn, null, mx}, new Float[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Float[]{nv, mn, mx}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, mn, null, mx}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Float[]{nv, mn, mx}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, mn, null, mx}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Float[]{v3, v1, nv, mx, v4}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v3, v1, null, nv, mx, v3}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Float[]{v3, v1, nv, mx, v4}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, v2, null, v3, v2}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Float[]{v3, v1, nv, mx, v4}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v3, v1, null, nv, mx, v3}, new Float[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Float[]{v3, v1, nv, mx, v4}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, v2, null, v3, v2}, new Float[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Float[]{v1, nv, nv}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v3, nv, null}, new Float[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Float[]{v1, nv, nv}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v2, nv, null}, new Float[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Float[]{nv, nv, nv}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, null, v4}, new Float[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Float[]{nv, nv, nv}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{nv, null, nv}, new Float[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Float[]{v4, nv, nv}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v3, nv, null}, new Float[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Float[]{v4, nv, nv}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v2, nv, null}, new Float[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Float[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Float[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Float[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Float[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Float[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Float[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Float[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Float[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Float[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Float[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Float64Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Float64Test.java new file mode 100644 index 000000000..f811c1fd1 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Float64Test.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class Float64Test extends AllTypesBase { + public Float64Test() { + super("float64", new MyColumnChecker<>(Double.class, Tuple::getDouble, Row::getDouble, Tuple::getArrayOfDoubles, Row::getArrayOfDoubles)); + } + + @Override + public List createBatch() { + Double v1 = Double.MAX_VALUE / 2; + Double v2 = Double.MIN_VALUE / 2; + Double v3 = Double.MAX_VALUE / 3; + Double v4 = Double.NaN; + Double v5 = Double.NEGATIVE_INFINITY; + Double v6 = Double.POSITIVE_INFINITY; + Double nv = 0.0; + Double mn = Double.MIN_VALUE; + Double mx = Double.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Double[]{mn, mn}, new Double[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, mn}, new Double[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Double[]{mn, mn}, new Double[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, mn}, new Double[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Double[]{mn, mn}, new Double[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, mn}, new Double[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Double[]{mn, mn}, new Double[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, mn}, new Double[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Double[]{mn, mn}, new Double[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, null, mn}, new Double[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Double[]{mn, mn}, new Double[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, null, mn}, new Double[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Double[]{mn, mn}, new Double[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, null, mn}, new Double[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Double[]{mn, mn}, new Double[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, null, mn}, new Double[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mx, mx}, new Double[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mx, null, mx}, new Double[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mx, null, mx}, new Double[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mx, null, mx}, new Double[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mx, null, mx}, new Double[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mx, null, mx}, new Double[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Double[]{mx, mx}, new Double[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mx, null, mx}, new Double[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Double[]{mn, mx}, new Double[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, null, mx}, new Double[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Double[]{mn, mx}, new Double[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, null, mx}, new Double[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Double[]{mn, mx}, new Double[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, null, mx}, new Double[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Double[]{mn, mx}, new Double[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{mn, null, mx}, new Double[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Double[]{}, new Double[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{}, new Double[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Double[]{}, new Double[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{}, new Double[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Double[]{}, new Double[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{}, new Double[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Double[]{}, new Double[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{}, new Double[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Double[]{}, new Double[][][]{{{}}}, new Double[]{}, new Double[][][]{{{}}}, v2, v3, new Double[]{}, new Double[][][]{{{}}}, new Double[]{}, new Double[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Double[]{}, new Double[][][]{{{}}}, new Double[]{}, new Double[][][]{{{}}}, v2, v3, new Double[]{}, new Double[][][]{{{}}}, new Double[]{}, new Double[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Double[]{}, new Double[][][]{{{}}}, new Double[]{null}, new Double[][][]{{{null}}}, v2, v3, new Double[]{}, new Double[][][]{{{}}}, new Double[]{null}, new Double[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Double[]{}, new Double[][][]{{{}}}, new Double[]{null}, new Double[][][]{{{null}}}, v2, v3, new Double[]{}, new Double[][][]{{{}}}, new Double[]{null}, new Double[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Double[]{nv}, new Double[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv}, new Double[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Double[]{nv}, new Double[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv}, new Double[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Double[]{nv}, new Double[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv}, new Double[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Double[]{nv}, new Double[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv}, new Double[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Double[]{nv, mn, mx}, new Double[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, mn, null, mx}, new Double[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Double[]{nv, mn, mx}, new Double[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv}, new Double[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Double[]{nv, mn, mx}, new Double[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, mn, null, mx}, new Double[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Double[]{nv, mn, mx}, new Double[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv}, new Double[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Double[]{nv, mn, mx}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, mn, null, mx}, new Double[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Double[]{nv, mn, mx}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, mn, null, mx}, new Double[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Double[]{nv, mn, mx}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, mn, null, mx}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Double[]{nv, mn, mx}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, mn, null, mx}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Double[]{v3, v1, nv, mx, v4}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v3, v1, null, nv, mx, v3}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Double[]{v3, v1, nv, mx, v4}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, v2, null, v3, v2}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Double[]{v3, v1, nv, mx, v4}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v3, v1, null, nv, mx, v3}, new Double[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Double[]{v3, v1, nv, mx, v4}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, v2, null, v3, v2}, new Double[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Double[]{v1, nv, nv}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v3, nv, null}, new Double[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Double[]{v1, nv, nv}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v2, nv, null}, new Double[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Double[]{nv, nv, nv}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, null, v4}, new Double[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Double[]{nv, nv, nv}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{nv, null, nv}, new Double[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Double[]{v4, nv, nv}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v3, nv, null}, new Double[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Double[]{v4, nv, nv}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v2, nv, null}, new Double[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Double[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Double[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Double[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Double[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Double[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Double[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Double[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Double[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Double[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Double[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/HugeDecimalTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/HugeDecimalTest.java new file mode 100644 index 000000000..31b6ff89a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/HugeDecimalTest.java @@ -0,0 +1,93 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; +import org.junit.runner.RunWith; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.MathContext; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public abstract class HugeDecimalTest extends AllTypesBase { + public static final int SCALE = 4; + public final MathContext mc; + + public HugeDecimalTest(String tableSuffix, MathContext mc) { + super(tableSuffix, new MyColumnChecker<>(Numeric.class, Tuple::getNumeric, Row::getNumeric, Tuple::getArrayOfNumerics, Row::getArrayOfNumerics), false); + this.mc = mc; + } + + private Numeric nm(Long src) { + BigInteger bi = BigInteger.valueOf(src); + BigDecimal bd = new BigDecimal(bi, SCALE, mc); + return Numeric.create(bd); + } + + @Override + public List createBatch() { + long mnl = Long.MIN_VALUE; + long mxl = Long.MAX_VALUE; + + Numeric v1 = nm(mxl / 3); + Numeric v2 = nm(mnl / 4); + Numeric v3 = nm(mxl / 5); + Numeric v4 = nm(mnl / 6); + Numeric v5 = nm(mxl / 7); + Numeric v6 = nm(mnl / 7); + Numeric nv = nm(0L); + Numeric mn = nm(mnl); + Numeric mx = nm(mxl); + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t + Tuple.of((byte)1, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, v1, null, nv, mx, v3}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, v1, null, nv, mx, v3}, new Numeric[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Numeric[]{v1, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Numeric[]{nv, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, null, v4}, new Numeric[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Numeric[]{v4, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/IPv4Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/IPv4Test.java new file mode 100644 index 000000000..5b10135c6 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/IPv4Test.java @@ -0,0 +1,85 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.IPv4Column; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.net.Inet4Address; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class IPv4Test extends AllTypesBase { + public IPv4Test() { + super("ipv4", new MyColumnChecker<>(Inet4Address.class, null, null, null, null)); + } + + private static Inet4Address ipv4(int b1, int b2, int b3, int b4) { + try { + return (Inet4Address) Inet4Address.getByAddress(new byte[]{(byte)b1, (byte)b2, (byte)b3, (byte)b4}); + } catch (UnknownHostException ex) { + throw new RuntimeException(ex); + } + } + + @Override + public List createBatch() { + Inet4Address v1 = ipv4(192, 168, 1, 1); + Inet4Address v2 = ipv4(10, 23, 1, 1); + Inet4Address v3 = ipv4(1, 1, 1, 1); + Inet4Address v4 = ipv4(8, 8, 8, 8); + Inet4Address v5 = ipv4(1, 2, 3, 4); + Inet4Address v6 = ipv4(100, 100, 100, 100); + Inet4Address nv = IPv4Column.ZERO_VALUE; + Inet4Address mn = IPv4Column.MIN_VALUE; + Inet4Address mx = IPv4Column.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, null, mn}, new Inet4Address[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, null, mn}, new Inet4Address[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, null, mn}, new Inet4Address[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet4Address[]{mn, mn}, new Inet4Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, null, mn}, new Inet4Address[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mx, null, mx}, new Inet4Address[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mx, null, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mx, null, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mx, null, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mx, null, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet4Address[]{mx, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mx, null, mx}, new Inet4Address[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Inet4Address[]{mn, mx}, new Inet4Address[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, null, mx}, new Inet4Address[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Inet4Address[]{mn, mx}, new Inet4Address[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, null, mx}, new Inet4Address[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Inet4Address[]{mn, mx}, new Inet4Address[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, null, mx}, new Inet4Address[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Inet4Address[]{mn, mx}, new Inet4Address[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{mn, null, mx}, new Inet4Address[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{}, new Inet4Address[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{}, new Inet4Address[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{}, new Inet4Address[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{}, new Inet4Address[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, new Inet4Address[]{}, new Inet4Address[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, new Inet4Address[]{}, new Inet4Address[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, new Inet4Address[]{null}, new Inet4Address[][][]{{{null}}}, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, new Inet4Address[]{null}, new Inet4Address[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, new Inet4Address[]{null}, new Inet4Address[][][]{{{null}}}, v2, v3, new Inet4Address[]{}, new Inet4Address[][][]{{{}}}, new Inet4Address[]{null}, new Inet4Address[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Inet4Address[]{nv}, new Inet4Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv}, new Inet4Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet4Address[]{nv}, new Inet4Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv}, new Inet4Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Inet4Address[]{nv}, new Inet4Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv}, new Inet4Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet4Address[]{nv}, new Inet4Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv}, new Inet4Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Inet4Address[]{nv, mn, mx}, new Inet4Address[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, mn, null, mx}, new Inet4Address[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet4Address[]{nv, mn, mx}, new Inet4Address[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv}, new Inet4Address[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Inet4Address[]{nv, mn, mx}, new Inet4Address[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, mn, null, mx}, new Inet4Address[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet4Address[]{nv, mn, mx}, new Inet4Address[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv}, new Inet4Address[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Inet4Address[]{nv, mn, mx}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, mn, null, mx}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet4Address[]{nv, mn, mx}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, mn, null, mx}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Inet4Address[]{nv, mn, mx}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, mn, null, mx}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet4Address[]{nv, mn, mx}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, mn, null, mx}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Inet4Address[]{v3, v1, nv, mx, v4}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v3, v1, null, nv, mx, v3}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Inet4Address[]{v3, v1, nv, mx, v4}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, v2, null, v3, v2}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Inet4Address[]{v3, v1, nv, mx, v4}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v3, v1, null, nv, mx, v3}, new Inet4Address[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Inet4Address[]{v3, v1, nv, mx, v4}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, v2, null, v3, v2}, new Inet4Address[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Inet4Address[]{v1, nv, nv}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v3, nv, null}, new Inet4Address[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Inet4Address[]{v1, nv, nv}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v2, nv, null}, new Inet4Address[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Inet4Address[]{nv, nv, nv}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, null, v4}, new Inet4Address[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Inet4Address[]{nv, nv, nv}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{nv, null, nv}, new Inet4Address[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Inet4Address[]{v4, nv, nv}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v3, nv, null}, new Inet4Address[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Inet4Address[]{v4, nv, nv}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v2, nv, null}, new Inet4Address[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Inet4Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Inet4Address[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Inet4Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Inet4Address[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Inet4Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Inet4Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet4Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Inet4Address[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/IPv6Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/IPv6Test.java new file mode 100644 index 000000000..e3e69dad6 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/IPv6Test.java @@ -0,0 +1,91 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.IPv6Column; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.net.Inet6Address; +import java.net.UnknownHostException; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class IPv6Test extends AllTypesBase { + public IPv6Test() { + super("ipv6", new MyColumnChecker<>(Inet6Address.class, null, null, null, null)); + } + + private static Inet6Address ipv6(int b1, int b2, int b3, int b4, int b5, int b6, int b7, int b8, + int b9, int b10, int b11, int b12, int b13, int b14, int b15, int b16) { + try { + return (Inet6Address) Inet6Address.getByAddress(new byte[]{ + (byte)b1, (byte)b2, (byte)b3, (byte)b4, + (byte)b5, (byte)b6, (byte)b7, (byte)b8, + (byte)b9, (byte)b10, (byte)b11, (byte)b12, + (byte)b13, (byte)b14, (byte)b15, (byte)b16 + }); + } catch (UnknownHostException ex) { + throw new RuntimeException(ex); + } + } + + @Override + public List createBatch() { + Inet6Address v1 = ipv6(192, 168, 35, 255, 44, 42, 42, 55, 78, 90, -120, 22, 10, -67, -90, -43); + Inet6Address v2 = ipv6(14, 23, 21, 54, 76, 90, 12, 11, -43, -11, -55, 93, 43, 87, -32, -21); + Inet6Address v3 = ipv6(32, 11, 85, 0, 14, -12, -98, 120, 43, 32, -65, 2, 41, -9, 0, 11); + Inet6Address v4 = ipv6(11, 0, 0, 0, 14, -43, 2, 65, 32, 14, 87, 3, 11, -9, 97, 11); + Inet6Address v5 = ipv6(11, 98, 32, 65, 11, -46, 0, 31, 99, 104, 54, 11, 11, -65, 111, 14); + Inet6Address v6 = ipv6(10, 10, 22, 78, -43, -46, 2, 98, 99, 43, 11, 2, -11, -33, 0, 1); + Inet6Address nv = IPv6Column.ZERO_VALUE; + Inet6Address mn = IPv6Column.MIN_VALUE; + Inet6Address mx = IPv6Column.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, null, mn}, new Inet6Address[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, null, mn}, new Inet6Address[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, null, mn}, new Inet6Address[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet6Address[]{mn, mn}, new Inet6Address[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, null, mn}, new Inet6Address[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mx, null, mx}, new Inet6Address[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mx, null, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mx, null, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mx, null, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mx, null, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Inet6Address[]{mx, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mx, null, mx}, new Inet6Address[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Inet6Address[]{mn, mx}, new Inet6Address[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, null, mx}, new Inet6Address[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Inet6Address[]{mn, mx}, new Inet6Address[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, null, mx}, new Inet6Address[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Inet6Address[]{mn, mx}, new Inet6Address[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, null, mx}, new Inet6Address[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Inet6Address[]{mn, mx}, new Inet6Address[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{mn, null, mx}, new Inet6Address[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{}, new Inet6Address[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{}, new Inet6Address[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{}, new Inet6Address[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{}, new Inet6Address[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, new Inet6Address[]{}, new Inet6Address[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, new Inet6Address[]{}, new Inet6Address[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, new Inet6Address[]{null}, new Inet6Address[][][]{{{null}}}, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, new Inet6Address[]{null}, new Inet6Address[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, new Inet6Address[]{null}, new Inet6Address[][][]{{{null}}}, v2, v3, new Inet6Address[]{}, new Inet6Address[][][]{{{}}}, new Inet6Address[]{null}, new Inet6Address[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Inet6Address[]{nv}, new Inet6Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv}, new Inet6Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet6Address[]{nv}, new Inet6Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv}, new Inet6Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Inet6Address[]{nv}, new Inet6Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv}, new Inet6Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet6Address[]{nv}, new Inet6Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv}, new Inet6Address[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Inet6Address[]{nv, mn, mx}, new Inet6Address[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, mn, null, mx}, new Inet6Address[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet6Address[]{nv, mn, mx}, new Inet6Address[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv}, new Inet6Address[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Inet6Address[]{nv, mn, mx}, new Inet6Address[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, mn, null, mx}, new Inet6Address[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet6Address[]{nv, mn, mx}, new Inet6Address[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv}, new Inet6Address[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Inet6Address[]{nv, mn, mx}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, mn, null, mx}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet6Address[]{nv, mn, mx}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, mn, null, mx}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Inet6Address[]{nv, mn, mx}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, mn, null, mx}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Inet6Address[]{nv, mn, mx}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, mn, null, mx}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Inet6Address[]{v3, v1, nv, mx, v4}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v3, v1, null, nv, mx, v3}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Inet6Address[]{v3, v1, nv, mx, v4}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, v2, null, v3, v2}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Inet6Address[]{v3, v1, nv, mx, v4}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v3, v1, null, nv, mx, v3}, new Inet6Address[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Inet6Address[]{v3, v1, nv, mx, v4}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, v2, null, v3, v2}, new Inet6Address[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Inet6Address[]{v1, nv, nv}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v3, nv, null}, new Inet6Address[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Inet6Address[]{v1, nv, nv}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v2, nv, null}, new Inet6Address[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Inet6Address[]{nv, nv, nv}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, null, v4}, new Inet6Address[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Inet6Address[]{nv, nv, nv}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{nv, null, nv}, new Inet6Address[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Inet6Address[]{v4, nv, nv}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v3, nv, null}, new Inet6Address[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Inet6Address[]{v4, nv, nv}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v2, nv, null}, new Inet6Address[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Inet6Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Inet6Address[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Inet6Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Inet6Address[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Inet6Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Inet6Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Inet6Address[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Inet6Address[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int128Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int128Test.java new file mode 100644 index 000000000..d387c6efb --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int128Test.java @@ -0,0 +1,92 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.impl.codec.columns.Int128Column; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Tuple; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; + + +@RunWith(VertxUnitRunner.class) +public class Int128Test extends AllTypesBase { + public Int128Test() { + super("int128", new MyColumnChecker<>(BigInteger.class, null, null, null, null)); + } + + @Ignore + @Test + public void testEmptyData(TestContext ctx) { + //experimental support at the moment + } + + @Ignore + @Test + public void testData(TestContext ctx) { + //experimental support at the moment + } + + @Override + public List createBatch() { + BigInteger v1 = BigInteger.valueOf(Long.MAX_VALUE); + BigInteger v2 = BigInteger.valueOf(Long.MIN_VALUE); + BigInteger v3 = BigInteger.valueOf(Integer.MAX_VALUE); + BigInteger v4 = BigInteger.valueOf(Integer.MIN_VALUE); + BigInteger v5 = BigInteger.valueOf(Long.MAX_VALUE / 2); + BigInteger v6 = BigInteger.valueOf(Long.MIN_VALUE / 2); + BigInteger nv = Int128Column.ZERO_VALUE; + BigInteger mn = Int128Column.INT128_MIN_VALUE; + BigInteger mx = Int128Column.INT128_MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, null, mn}, new BigInteger[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, null, mn}, new BigInteger[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, null, mn}, new BigInteger[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new BigInteger[]{mn, mn}, new BigInteger[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, null, mn}, new BigInteger[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mx, null, mx}, new BigInteger[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mx, null, mx}, new BigInteger[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mx, null, mx}, new BigInteger[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mx, null, mx}, new BigInteger[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mx, null, mx}, new BigInteger[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new BigInteger[]{mx, mx}, new BigInteger[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mx, null, mx}, new BigInteger[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new BigInteger[]{mn, mx}, new BigInteger[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, null, mx}, new BigInteger[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new BigInteger[]{mn, mx}, new BigInteger[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, null, mx}, new BigInteger[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new BigInteger[]{mn, mx}, new BigInteger[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, null, mx}, new BigInteger[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new BigInteger[]{mn, mx}, new BigInteger[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{mn, null, mx}, new BigInteger[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{}, new BigInteger[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{}, new BigInteger[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{}, new BigInteger[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{}, new BigInteger[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}}}, new BigInteger[]{}, new BigInteger[][][]{{{}}}, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}}}, new BigInteger[]{}, new BigInteger[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}}}, new BigInteger[]{}, new BigInteger[][][]{{{}}}, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}}}, new BigInteger[]{}, new BigInteger[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}}}, new BigInteger[]{null}, new BigInteger[][][]{{{null}}}, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}}}, new BigInteger[]{null}, new BigInteger[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}}}, new BigInteger[]{null}, new BigInteger[][][]{{{null}}}, v2, v3, new BigInteger[]{}, new BigInteger[][][]{{{}}}, new BigInteger[]{null}, new BigInteger[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new BigInteger[]{nv}, new BigInteger[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv}, new BigInteger[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new BigInteger[]{nv}, new BigInteger[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv}, new BigInteger[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new BigInteger[]{nv}, new BigInteger[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv}, new BigInteger[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new BigInteger[]{nv}, new BigInteger[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv}, new BigInteger[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new BigInteger[]{nv, mn, mx}, new BigInteger[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, mn, null, mx}, new BigInteger[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new BigInteger[]{nv, mn, mx}, new BigInteger[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv}, new BigInteger[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new BigInteger[]{nv, mn, mx}, new BigInteger[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, mn, null, mx}, new BigInteger[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new BigInteger[]{nv, mn, mx}, new BigInteger[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv}, new BigInteger[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new BigInteger[]{nv, mn, mx}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, mn, null, mx}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new BigInteger[]{nv, mn, mx}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, mn, null, mx}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new BigInteger[]{nv, mn, mx}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, mn, null, mx}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new BigInteger[]{nv, mn, mx}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, mn, null, mx}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new BigInteger[]{v3, v1, nv, mx, v4}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v3, v1, null, nv, mx, v3}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new BigInteger[]{v3, v1, nv, mx, v4}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, v2, null, v3, v2}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new BigInteger[]{v3, v1, nv, mx, v4}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v3, v1, null, nv, mx, v3}, new BigInteger[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new BigInteger[]{v3, v1, nv, mx, v4}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, v2, null, v3, v2}, new BigInteger[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new BigInteger[]{v1, nv, nv}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v3, nv, null}, new BigInteger[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new BigInteger[]{v1, nv, nv}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v2, nv, null}, new BigInteger[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new BigInteger[]{nv, nv, nv}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, null, v4}, new BigInteger[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new BigInteger[]{nv, nv, nv}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{nv, null, nv}, new BigInteger[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new BigInteger[]{v4, nv, nv}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v3, nv, null}, new BigInteger[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new BigInteger[]{v4, nv, nv}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v2, nv, null}, new BigInteger[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new BigInteger[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new BigInteger[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new BigInteger[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new BigInteger[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new BigInteger[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new BigInteger[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new BigInteger[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new BigInteger[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int16Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int16Test.java new file mode 100644 index 000000000..d6df64d95 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int16Test.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class Int16Test extends AllTypesBase { + public Int16Test() { + super("int16", new MyColumnChecker<>(Short.class, Tuple::getShort, Row::getShort, Tuple::getArrayOfShorts, Row::getArrayOfShorts)); + } + + @Override + public List createBatch() { + Short v1 = 10; + Short v2 = Short.MIN_VALUE / 3; + Short v3 = Short.MAX_VALUE / 3; + Short v4 = Short.MIN_VALUE / 2; + Short v5 = Short.MAX_VALUE / 2; + Short v6 = -70; + Short nv = 0; + Short mn = Short.MIN_VALUE; + Short mx = Short.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, mn}, new Short[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, mn}, new Short[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, mn}, new Short[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, mn}, new Short[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mn}, new Short[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mn}, new Short[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mn}, new Short[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mn}, new Short[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, mx}, new Short[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Short[]{mn, mx}, new Short[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mx}, new Short[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Short[]{mn, mx}, new Short[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mx}, new Short[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Short[]{mn, mx}, new Short[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mx}, new Short[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Short[]{mn, mx}, new Short[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mx}, new Short[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{}, new Short[][][]{{{}}}, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{}, new Short[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{}, new Short[][][]{{{}}}, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{}, new Short[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{null}, new Short[][][]{{{null}}}, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{null}, new Short[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{null}, new Short[][][]{{{null}}}, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{null}, new Short[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Short[]{v3, v1, nv, mx, v4}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v3, v1, null, nv, mx, v3}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Short[]{v3, v1, nv, mx, v4}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, v2, null, v3, v2}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Short[]{v3, v1, nv, mx, v4}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v3, v1, null, nv, mx, v3}, new Short[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Short[]{v3, v1, nv, mx, v4}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, v2, null, v3, v2}, new Short[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Short[]{v1, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v3, nv, null}, new Short[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Short[]{v1, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v2, nv, null}, new Short[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Short[]{nv, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, null, v4}, new Short[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Short[]{nv, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, null, nv}, new Short[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Short[]{v4, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v3, nv, null}, new Short[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Short[]{v4, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v2, nv, null}, new Short[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Short[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Short[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Short[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Short[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int32Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int32Test.java new file mode 100644 index 000000000..347b938dc --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int32Test.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class Int32Test extends AllTypesBase { + public Int32Test() { + super("int32", new MyColumnChecker<>(Integer.class, Tuple::getInteger, Row::getInteger, Tuple::getArrayOfIntegers, Row::getArrayOfIntegers)); + } + + @Override + public List createBatch() { + Integer v1 = 10; + Integer v2 = Integer.MIN_VALUE / 3; + Integer v3 = Integer.MAX_VALUE / 3; + Integer v4 = Integer.MIN_VALUE / 2; + Integer v5 = Integer.MAX_VALUE / 2; + Integer v6 = -70; + Integer nv = 0; + Integer mn = Integer.MIN_VALUE; + Integer mx = Integer.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, mn}, new Integer[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, mn}, new Integer[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, mn}, new Integer[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, mn}, new Integer[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mn}, new Integer[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mn}, new Integer[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mn}, new Integer[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mn}, new Integer[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, mx}, new Integer[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Integer[]{mn, mx}, new Integer[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mx}, new Integer[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Integer[]{mn, mx}, new Integer[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mx}, new Integer[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Integer[]{mn, mx}, new Integer[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mx}, new Integer[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Integer[]{mn, mx}, new Integer[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mx}, new Integer[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{}, new Integer[][][]{{{}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{}, new Integer[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{}, new Integer[][][]{{{}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{}, new Integer[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{null}, new Integer[][][]{{{null}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{null}, new Integer[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{null}, new Integer[][][]{{{null}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{null}, new Integer[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Integer[]{v3, v1, nv, mx, v4}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v3, v1, null, nv, mx, v3}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Integer[]{v3, v1, nv, mx, v4}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, v2, null, v3, v2}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Integer[]{v3, v1, nv, mx, v4}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v3, v1, null, nv, mx, v3}, new Integer[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Integer[]{v3, v1, nv, mx, v4}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, v2, null, v3, v2}, new Integer[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Integer[]{v1, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v3, nv, null}, new Integer[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Integer[]{v1, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v2, nv, null}, new Integer[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Integer[]{nv, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, null, v4}, new Integer[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Integer[]{nv, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, null, nv}, new Integer[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Integer[]{v4, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v3, nv, null}, new Integer[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Integer[]{v4, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v2, nv, null}, new Integer[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Integer[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Integer[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Integer[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Integer[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int64Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int64Test.java new file mode 100644 index 000000000..640aecd1c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int64Test.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class Int64Test extends AllTypesBase { + public Int64Test() { + super("int64", new MyColumnChecker<>(Long.class, Tuple::getLong, Row::getLong, Tuple::getArrayOfLongs, Row::getArrayOfLongs)); + } + + @Override + public List createBatch() { + Long v1 = 10L; + Long v2 = Long.MIN_VALUE / 3; + Long v3 = Long.MAX_VALUE / 3; + Long v4 = Long.MIN_VALUE / 2; + Long v5 = Long.MAX_VALUE / 2; + Long v6 = -70L; + Long nv = 0L; + Long mn = Long.MIN_VALUE; + Long mx = Long.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, mn}, new Long[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, mn}, new Long[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, mn}, new Long[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, mn}, new Long[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mn}, new Long[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mn}, new Long[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mn}, new Long[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mn}, new Long[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, mx}, new Long[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Long[]{mn, mx}, new Long[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mx}, new Long[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Long[]{mn, mx}, new Long[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mx}, new Long[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Long[]{mn, mx}, new Long[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mx}, new Long[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Long[]{mn, mx}, new Long[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mx}, new Long[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{}, new Long[][][]{{{}}}, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{}, new Long[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{}, new Long[][][]{{{}}}, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{}, new Long[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{null}, new Long[][][]{{{null}}}, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{null}, new Long[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{null}, new Long[][][]{{{null}}}, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{null}, new Long[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Long[]{v3, v1, nv, mx, v4}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v3, v1, null, nv, mx, v3}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Long[]{v3, v1, nv, mx, v4}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, v2, null, v3, v2}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Long[]{v3, v1, nv, mx, v4}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v3, v1, null, nv, mx, v3}, new Long[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Long[]{v3, v1, nv, mx, v4}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, v2, null, v3, v2}, new Long[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Long[]{v1, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v3, nv, null}, new Long[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Long[]{v1, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v2, nv, null}, new Long[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Long[]{nv, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, null, v4}, new Long[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Long[]{nv, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, null, nv}, new Long[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Long[]{v4, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v3, nv, null}, new Long[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Long[]{v4, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v2, nv, null}, new Long[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Long[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Long[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Long[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Long[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int8Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int8Test.java new file mode 100644 index 000000000..f6ffe91e3 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/Int8Test.java @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class Int8Test extends AllTypesBase { + public Int8Test() { + super("int8", new MyColumnChecker<>(Byte.class, null, null, null, null)); + } + + @Override + public List createBatch() { + Byte v1 = 10; + Byte v2 = Byte.MIN_VALUE / 3; + Byte v3 = Byte.MAX_VALUE / 3; + Byte v4 = Byte.MIN_VALUE / 2; + Byte v5 = Byte.MAX_VALUE / 2; + Byte v6 = -70; + Byte nv = 0; + Byte mn = Byte.MIN_VALUE; + Byte mx = Byte.MAX_VALUE; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Byte[]{mn, mn}, new Byte[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, mn}, new Byte[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Byte[]{mn, mn}, new Byte[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, mn}, new Byte[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Byte[]{mn, mn}, new Byte[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, mn}, new Byte[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Byte[]{mn, mn}, new Byte[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, mn}, new Byte[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Byte[]{mn, mn}, new Byte[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, null, mn}, new Byte[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Byte[]{mn, mn}, new Byte[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, null, mn}, new Byte[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Byte[]{mn, mn}, new Byte[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, null, mn}, new Byte[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Byte[]{mn, mn}, new Byte[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, null, mn}, new Byte[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mx, mx}, new Byte[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mx, null, mx}, new Byte[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mx, null, mx}, new Byte[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mx, null, mx}, new Byte[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mx, null, mx}, new Byte[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mx, null, mx}, new Byte[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Byte[]{mx, mx}, new Byte[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mx, null, mx}, new Byte[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Byte[]{mn, mx}, new Byte[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, null, mx}, new Byte[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Byte[]{mn, mx}, new Byte[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, null, mx}, new Byte[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Byte[]{mn, mx}, new Byte[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, null, mx}, new Byte[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Byte[]{mn, mx}, new Byte[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{mn, null, mx}, new Byte[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Byte[]{}, new Byte[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{}, new Byte[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Byte[]{}, new Byte[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{}, new Byte[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Byte[]{}, new Byte[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{}, new Byte[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Byte[]{}, new Byte[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{}, new Byte[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Byte[]{}, new Byte[][][]{{{}}}, new Byte[]{}, new Byte[][][]{{{}}}, v2, v3, new Byte[]{}, new Byte[][][]{{{}}}, new Byte[]{}, new Byte[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Byte[]{}, new Byte[][][]{{{}}}, new Byte[]{}, new Byte[][][]{{{}}}, v2, v3, new Byte[]{}, new Byte[][][]{{{}}}, new Byte[]{}, new Byte[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Byte[]{}, new Byte[][][]{{{}}}, new Byte[]{null}, new Byte[][][]{{{null}}}, v2, v3, new Byte[]{}, new Byte[][][]{{{}}}, new Byte[]{null}, new Byte[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Byte[]{}, new Byte[][][]{{{}}}, new Byte[]{null}, new Byte[][][]{{{null}}}, v2, v3, new Byte[]{}, new Byte[][][]{{{}}}, new Byte[]{null}, new Byte[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Byte[]{nv}, new Byte[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv}, new Byte[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Byte[]{nv}, new Byte[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv}, new Byte[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Byte[]{nv}, new Byte[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv}, new Byte[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Byte[]{nv}, new Byte[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv}, new Byte[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Byte[]{nv, mn, mx}, new Byte[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, mn, null, mx}, new Byte[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Byte[]{nv, mn, mx}, new Byte[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv}, new Byte[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Byte[]{nv, mn, mx}, new Byte[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, mn, null, mx}, new Byte[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Byte[]{nv, mn, mx}, new Byte[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv}, new Byte[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Byte[]{nv, mn, mx}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, mn, null, mx}, new Byte[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Byte[]{nv, mn, mx}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, mn, null, mx}, new Byte[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Byte[]{nv, mn, mx}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, mn, null, mx}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Byte[]{nv, mn, mx}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, mn, null, mx}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Byte[]{v3, v1, nv, mx, v4}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v3, v1, null, nv, mx, v3}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Byte[]{v3, v1, nv, mx, v4}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, v2, null, v3, v2}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Byte[]{v3, v1, nv, mx, v4}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v3, v1, null, nv, mx, v3}, new Byte[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Byte[]{v3, v1, nv, mx, v4}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, v2, null, v3, v2}, new Byte[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Byte[]{v1, nv, nv}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v3, nv, null}, new Byte[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Byte[]{v1, nv, nv}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v2, nv, null}, new Byte[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Byte[]{nv, nv, nv}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, null, v4}, new Byte[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Byte[]{nv, nv, nv}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{nv, null, nv}, new Byte[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Byte[]{v4, nv, nv}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v3, nv, null}, new Byte[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Byte[]{v4, nv, nv}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v2, nv, null}, new Byte[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Byte[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Byte[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Byte[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Byte[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Byte[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Byte[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Byte[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Byte[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Byte[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Byte[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/StringArrayDeduplicationTester.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/StringArrayDeduplicationTester.java new file mode 100644 index 000000000..ae98086f1 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/StringArrayDeduplicationTester.java @@ -0,0 +1,66 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnection; +import io.vertx.core.Vertx; +import io.vertx.ext.unit.TestContext; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.RowIterator; +import io.vertx.sqlclient.Tuple; + +import java.util.Arrays; +import java.util.List; + +public class StringArrayDeduplicationTester { + private final String tableName; + private final ClickhouseBinaryConnectOptions options; + private final Vertx vertx; + + public StringArrayDeduplicationTester(String tableName, Vertx vertx, ClickhouseBinaryConnectOptions options) { + this.tableName = tableName; + this.options = options; + this.vertx = vertx; + } + + public void test(TestContext ctx) { + List batch = Arrays.asList( + Tuple.of(1, "dedup", (Object) new Object[][][]{ {{"str1_1", "str1_2", null, "dedup3", "dedup1"}, {null}}, {{"str1_3", "str1_4", null}, {null, "dedup2"}} }), + Tuple.of(2, "val", (Object) new Object[][][]{ {{"str2_1", "str2_2", null, "dedup2"}, {null, "dedup1"}} }), + Tuple.of(3, "dedup", (Object) new Object[][][]{ {{"str3_1", "str3_2", null}, {null}, {"dedup3"}} }) + ); + ClickhouseBinaryConnection.connect(vertx, options, ctx.asyncAssertSuccess(conn -> { + conn.preparedQuery(String.format("INSERT INTO %s (id, nullable_lc_t, nullable_array3_lc_t) VALUES", tableName)).executeBatch(batch, ctx.asyncAssertSuccess(result -> { + conn.query("SELECT nullable_lc_t, nullable_array3_lc_t FROM " + tableName + " ORDER BY id").execute(ctx.asyncAssertSuccess( + res3 -> { + ctx.assertEquals(res3.size(), batch.size(), "row count mismatch"); + RowIterator rows = res3.iterator(); + Row row1 = rows.next(); + Row row2 = rows.next(); + Row row3 = rows.next(); + String val1 = row1.getString(0); + String val2 = row3.getString(0); + ctx.assertTrue(val1 == val2); + String[][][] arr1 = row1.get(String[][][].class, 1); + String[][][] arr2 = row2.get(String[][][].class, 1); + String[][][] arr3 = row3.get(String[][][].class, 1); + ctx.assertTrue(arr1[0][0][3] == arr3[0][2][0]);//dedup3 + ctx.assertTrue(arr1[0][0][4] == arr2[0][1][1]);//dedup1 + ctx.assertTrue(arr1[1][1][1] == arr2[0][0][3]);//dedup2 + })); + })); + })); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/StringTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/StringTest.java new file mode 100644 index 000000000..a8bb4aa84 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/StringTest.java @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class StringTest extends AllTypesBase { + public StringTest() { + super("string", new MyColumnChecker<>(String.class, Tuple::getString, Row::getString, Tuple::getArrayOfStrings, Row::getArrayOfStrings)); + } + + @Test + public void testArrayDeduplication(TestContext ctx) { + new StringArrayDeduplicationTester(tableName(), vertx, options).test(ctx); + } + + @Override + public List createBatch() { + String v1 = "val1"; + String v2 = "val2"; + String v3 = "val3"; + String v4 = "val4"; + String v5 = "value5"; + String v6 = "value_value_6"; + String nv = ""; + String mn = ""; + String mx = "not so looooooooooooooooooooooooooooooooooooooong value"; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, mn}, new String[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, mn}, new String[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, mn}, new String[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, mn}, new String[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mn}, new String[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mn}, new String[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mn}, new String[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mn, mn}, new String[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mn}, new String[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, mx}, new String[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new String[]{mx, mx}, new String[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mx, null, mx}, new String[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new String[]{mn, mx}, new String[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mx}, new String[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new String[]{mn, mx}, new String[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mx}, new String[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new String[]{mn, mx}, new String[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mx}, new String[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new String[]{mn, mx}, new String[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{mn, null, mx}, new String[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new String[]{}, new String[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{}, new String[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new String[]{}, new String[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{}, new String[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new String[]{}, new String[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{}, new String[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new String[]{}, new String[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{}, new String[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{}, new String[][][]{{{}}}, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{}, new String[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{}, new String[][][]{{{}}}, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{}, new String[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{null}, new String[][][]{{{null}}}, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{null}, new String[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{null}, new String[][][]{{{null}}}, v2, v3, new String[]{}, new String[][][]{{{}}}, new String[]{null}, new String[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv}, new String[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new String[]{nv, mn, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, mn, null, mx}, new String[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new String[]{v3, v1, nv, mx, v4}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v3, v1, null, nv, mx, v3}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new String[]{v3, v1, nv, mx, v4}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, v2, null, v3, v2}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new String[]{v3, v1, nv, mx, v4}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v3, v1, null, nv, mx, v3}, new String[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new String[]{v3, v1, nv, mx, v4}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, v2, null, v3, v2}, new String[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new String[]{v1, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v3, nv, null}, new String[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new String[]{v1, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v2, nv, null}, new String[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new String[]{nv, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, null, v4}, new String[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new String[]{nv, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{nv, null, nv}, new String[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new String[]{v4, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v3, nv, null}, new String[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new String[]{v4, nv, nv}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v2, nv, null}, new String[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new String[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new String[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new String[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new String[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new String[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new String[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/TestEnum.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/TestEnum.java new file mode 100644 index 000000000..740f43a44 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/TestEnum.java @@ -0,0 +1,18 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +enum TestEnum { + v0, v1, v2, v3, v4, v5, v6 +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt16Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt16Test.java new file mode 100644 index 000000000..9db5606a8 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt16Test.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class UInt16Test extends AllTypesBase { + public UInt16Test() { + super("uint16", new MyColumnChecker<>(Integer.class, Tuple::getInteger, Row::getInteger, Tuple::getArrayOfIntegers, Row::getArrayOfIntegers)); + } + + @Override + public List createBatch() { + Integer mx = 65535; + Integer v1 = 10; + Integer v2 = mx / 6; + Integer v3 = mx / 5; + Integer v4 = mx / 4; + Integer v5 = mx / 3; + Integer v6 = mx / 2; + Integer nv = 0; + Integer mn = 0; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, mn}, new Integer[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, mn}, new Integer[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, mn}, new Integer[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, mn}, new Integer[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mn}, new Integer[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mn}, new Integer[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mn}, new Integer[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mn, mn}, new Integer[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mn}, new Integer[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, mx}, new Integer[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Integer[]{mx, mx}, new Integer[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mx, null, mx}, new Integer[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Integer[]{mn, mx}, new Integer[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mx}, new Integer[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Integer[]{mn, mx}, new Integer[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mx}, new Integer[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Integer[]{mn, mx}, new Integer[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mx}, new Integer[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Integer[]{mn, mx}, new Integer[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{mn, null, mx}, new Integer[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{}, new Integer[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{}, new Integer[][][]{{{}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{}, new Integer[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{}, new Integer[][][]{{{}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{}, new Integer[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{null}, new Integer[][][]{{{null}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{null}, new Integer[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{null}, new Integer[][][]{{{null}}}, v2, v3, new Integer[]{}, new Integer[][][]{{{}}}, new Integer[]{null}, new Integer[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv}, new Integer[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Integer[]{nv, mn, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, mn, null, mx}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Integer[]{v3, v1, nv, mx, v4}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v3, v1, null, nv, mx, v3}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Integer[]{v3, v1, nv, mx, v4}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, v2, null, v3, v2}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Integer[]{v3, v1, nv, mx, v4}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v3, v1, null, nv, mx, v3}, new Integer[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Integer[]{v3, v1, nv, mx, v4}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, v2, null, v3, v2}, new Integer[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Integer[]{v1, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v3, nv, null}, new Integer[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Integer[]{v1, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v2, nv, null}, new Integer[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Integer[]{nv, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, null, v4}, new Integer[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Integer[]{nv, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{nv, null, nv}, new Integer[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Integer[]{v4, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v3, nv, null}, new Integer[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Integer[]{v4, nv, nv}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v2, nv, null}, new Integer[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Integer[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Integer[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Integer[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Integer[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Integer[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Integer[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt32Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt32Test.java new file mode 100644 index 000000000..be3d2f88c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt32Test.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class UInt32Test extends AllTypesBase { + public UInt32Test() { + super("uint32", new MyColumnChecker<>(Long.class, Tuple::getLong, Row::getLong, Tuple::getArrayOfLongs, Row::getArrayOfLongs)); + } + + @Override + public List createBatch() { + Long mx = 4294967295L; + Long v1 = 10L; + Long v2 = mx / 6; + Long v3 = mx / 5; + Long v4 = mx / 4; + Long v5 = mx / 3; + Long v6 = mx / 2; + Long nv = 0L; + Long mn = 0L; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, mn}, new Long[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, mn}, new Long[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, mn}, new Long[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, mn}, new Long[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mn}, new Long[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mn}, new Long[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mn}, new Long[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mn, mn}, new Long[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mn}, new Long[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, mx}, new Long[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Long[]{mx, mx}, new Long[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mx, null, mx}, new Long[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Long[]{mn, mx}, new Long[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mx}, new Long[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Long[]{mn, mx}, new Long[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mx}, new Long[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Long[]{mn, mx}, new Long[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mx}, new Long[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Long[]{mn, mx}, new Long[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{mn, null, mx}, new Long[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{}, new Long[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{}, new Long[][][]{{{}}}, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{}, new Long[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{}, new Long[][][]{{{}}}, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{}, new Long[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{null}, new Long[][][]{{{null}}}, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{null}, new Long[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{null}, new Long[][][]{{{null}}}, v2, v3, new Long[]{}, new Long[][][]{{{}}}, new Long[]{null}, new Long[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv}, new Long[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Long[]{nv, mn, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, mn, null, mx}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Long[]{v3, v1, nv, mx, v4}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v3, v1, null, nv, mx, v3}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Long[]{v3, v1, nv, mx, v4}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, v2, null, v3, v2}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Long[]{v3, v1, nv, mx, v4}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v3, v1, null, nv, mx, v3}, new Long[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Long[]{v3, v1, nv, mx, v4}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, v2, null, v3, v2}, new Long[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Long[]{v1, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v3, nv, null}, new Long[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Long[]{v1, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v2, nv, null}, new Long[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Long[]{nv, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, null, v4}, new Long[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Long[]{nv, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{nv, null, nv}, new Long[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Long[]{v4, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v3, nv, null}, new Long[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Long[]{v4, nv, nv}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v2, nv, null}, new Long[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Long[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Long[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Long[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Long[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Long[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Long[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt64Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt64Test.java new file mode 100644 index 000000000..1a8e1721c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt64Test.java @@ -0,0 +1,82 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; +import org.junit.runner.RunWith; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class UInt64Test extends AllTypesBase { + public UInt64Test() { + super("uint64", new MyColumnChecker<>(Numeric.class, Tuple::getNumeric, Row::getNumeric, Tuple::getArrayOfNumerics, Row::getArrayOfNumerics)); + } + + private BigInteger bi(int src) { + return BigInteger.valueOf(src); + } + + @Override + public List createBatch() { + BigInteger mxBi = new BigInteger("18446744073709551615"); + Numeric mx = Numeric.create(mxBi); + Numeric v1 = Numeric.create(BigInteger.TEN); + Numeric v2 = Numeric.create(mxBi.divide( bi(6))); + Numeric v3 = Numeric.create(mxBi.divide(bi(5))); + Numeric v4 = Numeric.create(mxBi.divide(bi(4))); + Numeric v5 = Numeric.create(mxBi.divide(bi(3))); + Numeric v6 = Numeric.create(mxBi.divide(bi(2))); + Numeric nv = Numeric.create(BigInteger.ZERO); + Numeric mn = Numeric.create(BigInteger.ZERO); + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Numeric[]{mn, mn}, new Numeric[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mn}, new Numeric[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Numeric[]{mx, mx}, new Numeric[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mx, null, mx}, new Numeric[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Numeric[]{mn, mx}, new Numeric[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{mn, null, mx}, new Numeric[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{}, new Numeric[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}}, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}}, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{}, new Numeric[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}}, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}}, v2, v3, new Numeric[]{}, new Numeric[][][]{{{}}}, new Numeric[]{null}, new Numeric[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv}, new Numeric[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Numeric[]{nv, mn, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, mn, null, mx}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, v1, null, nv, mx, v3}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, v2, null, v3, v2}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, v1, null, nv, mx, v3}, new Numeric[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Numeric[]{v3, v1, nv, mx, v4}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, v2, null, v3, v2}, new Numeric[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Numeric[]{v1, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Numeric[]{v1, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v2, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Numeric[]{nv, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, null, v4}, new Numeric[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Numeric[]{nv, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{nv, null, nv}, new Numeric[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Numeric[]{v4, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v3, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Numeric[]{v4, nv, nv}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v2, nv, null}, new Numeric[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Numeric[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Numeric[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Numeric[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt8Test.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt8Test.java new file mode 100644 index 000000000..8df66036c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UInt8Test.java @@ -0,0 +1,75 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import org.junit.runner.RunWith; + +import java.util.Arrays; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class UInt8Test extends AllTypesBase { + public UInt8Test() { + super("uint8", new MyColumnChecker<>(Short.class, Tuple::getShort, Row::getShort, Tuple::getArrayOfShorts, Row::getArrayOfShorts)); + } + + @Override + public List createBatch() { + Short v1 = 10; + Short v2 = 20; + Short v3 = 30; + Short v4 = 40; + Short v5 = 60; + Short v6 = 70; + Short nv = 0; + Short mn = 0; + Short mx = 255; + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t simple_lc_t nullable_lc_t array_lc_t array3_lc_t nullable_array_lc_t nullable_array3_lc_t + Tuple.of((byte)1, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, mn}, new Short[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, mn}, new Short[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, mn}, new Short[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, mn}, new Short[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mn}, new Short[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mn}, new Short[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mn}, new Short[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mn, mn}, new Short[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mn}, new Short[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, mx}, new Short[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}}, mx, mx, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}}, mn, mn, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}}, mn, mn, new Short[]{mx, mx}, new Short[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mx, null, mx}, new Short[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new Short[]{mn, mx}, new Short[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mx}, new Short[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mx, mx, new Short[]{mn, mx}, new Short[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mx}, new Short[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new Short[]{mn, mx}, new Short[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mx}, new Short[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, mn, mn, new Short[]{mn, mx}, new Short[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{mn, null, mx}, new Short[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{}, new Short[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{}, new Short[][][]{{{}}}, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{}, new Short[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{}, new Short[][][]{{{}}}, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{}, new Short[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{null}, new Short[][][]{{{null}}}, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{null}, new Short[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{null}, new Short[][][]{{{null}}}, v2, v3, new Short[]{}, new Short[][][]{{{}}}, new Short[]{null}, new Short[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv}, new Short[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v2, v3, new Short[]{nv, mn, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, mn, null, mx}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new Short[]{v3, v1, nv, mx, v4}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v3, v1, null, nv, mx, v3}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Short[]{v3, v1, nv, mx, v4}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, v2, null, v3, v2}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new Short[]{v3, v1, nv, mx, v4}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v3, v1, null, nv, mx, v3}, new Short[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, null, new Short[]{v3, v1, nv, mx, v4}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, v2, null, v3, v2}, new Short[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new Short[]{v1, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v3, nv, null}, new Short[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v1, v1, new Short[]{v1, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v2, nv, null}, new Short[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new Short[]{nv, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, null, v4}, new Short[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, nv, nv, new Short[]{nv, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{nv, null, nv}, new Short[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new Short[]{v4, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v3, nv, null}, new Short[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Short[]{v4, nv, nv}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v2, nv, null}, new Short[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Short[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Short[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Short[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, v6, v5, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new Short[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new Short[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new Short[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UUIDTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UUIDTest.java new file mode 100644 index 000000000..32a51f36e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/alltypes/UUIDTest.java @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.alltypes; + +import io.vertx.sqlclient.Tuple; + +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +public class UUIDTest extends AllTypesBase { + public UUIDTest() { + super("uuid", new MyColumnChecker<>(UUID.class, null, null, null, null), false); + } + + @Override + public List createBatch() { + UUID v1 = new UUID(1000, 2000); + UUID v2 = new UUID(-1000, -2000); + UUID v3 = new UUID(Integer.MIN_VALUE, Integer.MIN_VALUE); + UUID v4 = new UUID(Integer.MAX_VALUE, Integer.MAX_VALUE); + UUID v5 = new UUID(Long.MIN_VALUE / 2 , Long.MIN_VALUE / 2); + UUID v6 = new UUID(Long.MAX_VALUE / 2, Long.MAX_VALUE / 2); + UUID nv = new UUID(0, 0); + UUID mn = new UUID(Long.MIN_VALUE, Long.MIN_VALUE); + UUID mx = new UUID(Long.MAX_VALUE, Long.MAX_VALUE); + + return Arrays.asList( + // id simple_t nullable_t array_t array3_t nullable_array_t nullable_array3_t + Tuple.of((byte)1, mn, mn, new UUID[]{mn, mn}, new UUID[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mn, mn}, new UUID[][][]{{{mn, null, mn}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)2, mn, mn, new UUID[]{mn, mn}, new UUID[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mn, mn}, new UUID[][][]{{{mn, null, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)3, mn, mn, new UUID[]{mn, mn}, new UUID[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mn, null, mn}, new UUID[][][]{{{mn, mn, null}, {mn, mn, null}, {null}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)4, mn, mn, new UUID[]{mn, mn}, new UUID[][][]{{{mn, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mn, null, mn}, new UUID[][][]{{{mn, null, mn}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)5, mx, mx, new UUID[]{mx, mx}, new UUID[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mx, mx}, new UUID[][][]{{{mx, null, mx}, {mx, mx, null}, {}}, {{mn, mn}, {mn, null, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)6, mn, mn, new UUID[]{mx, mx}, new UUID[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mx, mx}, new UUID[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{null}, {}, {}}} ), + Tuple.of((byte)7, mx, mx, new UUID[]{mx, mx}, new UUID[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mx, null, mx}, new UUID[][][]{{{mx, mx}, {mx, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)8, mn, mn, new UUID[]{mx, mx}, new UUID[][][]{{{mx, mx}, {mx, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mx, null, mx}, new UUID[][][]{{{mx, mx}, {mx, null, mx, null}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {null}, {}}} ), + Tuple.of((byte)9, mx, mx, new UUID[]{mn, mx}, new UUID[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mn, null, mx}, new UUID[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)10, mn, mn, new UUID[]{mn, mx}, new UUID[][][]{{{mn, mx}, {mn, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{mn, null, mx}, new UUID[][][]{{{mn, mx, null}, {mn, null, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)11, v2, v3, new UUID[]{}, new UUID[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{}, new UUID[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)12, v2, v3, new UUID[]{}, new UUID[][][]{{{}, {}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{}, new UUID[][][]{{{}, {}, {}}, {{}, {}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)13, v2, v3, new UUID[]{}, new UUID[][][]{{{}}}, new UUID[]{}, new UUID[][][]{{{}}} ), + Tuple.of((byte)14, v2, v3, new UUID[]{}, new UUID[][][]{{{}}}, new UUID[]{}, new UUID[][][]{{{}}} ), + Tuple.of((byte)15, v2, v3, new UUID[]{}, new UUID[][][]{{{}}}, new UUID[]{null}, new UUID[][][]{{{null}}} ), + Tuple.of((byte)16, v2, v3, new UUID[]{}, new UUID[][][]{{{}}}, new UUID[]{null}, new UUID[][][]{{{null}}} ), + Tuple.of((byte)17, v2, v3, new UUID[]{nv}, new UUID[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{nv}, new UUID[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)18, v2, v3, new UUID[]{nv}, new UUID[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{nv}, new UUID[][][]{{{nv, nv}, {nv, nv}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)19, v2, v3, new UUID[]{nv, mn, mx}, new UUID[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{nv, mn, null, mx}, new UUID[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)20, v2, v3, new UUID[]{nv, mn, mx}, new UUID[][][]{{{v2, nv, mn}, {v3, mn, nv, mx}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{nv, mn, null, mx}, new UUID[][][]{{{v2, nv, mn, null}, {v3, mn, nv, mx}, {}}, {{mn, mn, null}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)21, v2, v3, new UUID[]{nv, mn, mx}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{nv, mn, null, mx}, new UUID[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)22, v2, v3, new UUID[]{nv, mn, mx}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{nv, mn, null, mx}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, null, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)23, nv, null, new UUID[]{v3, v1, nv, mx, v4}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{v3, v1, null, nv, mx, v3}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5, null}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)24, nv, null, new UUID[]{v3, v1, nv, mx, v4}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{v3, v1, null, nv, mx, v3}, new UUID[][][]{{{nv, mn, mx, null, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)25, v1, v1, new UUID[]{v1, nv, nv}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{v3, nv, null}, new UUID[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)26, nv, nv, new UUID[]{nv, nv, nv}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{nv, null, v4}, new UUID[][][]{{{nv, null, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)27, v6, v5, new UUID[]{v4, nv, nv}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{v3, nv, null}, new UUID[][][]{{{nv, mn, null, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)28, v6, v5, new UUID[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new UUID[][][]{{{nv, mn, mx, v1, null, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ), + Tuple.of((byte)29, v6, v5, new UUID[]{v1, nv, mn, mx, v2, v3, v4, v5, v6}, new UUID[][][]{{{nv, mn, mx, v1, v2, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}}, new UUID[]{v1, nv, mn, mx, v2, v3, v4, v5, v6, null}, new UUID[][][]{{{nv, mn, mx, v1, v2, null, v3, v4, v5}, {mn, mn}, {}}, {{mn, mn}, {mn, mn}, {}}, {{}, {}, {}}} ) + ); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnsTestReader.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnsTestReader.java new file mode 100644 index 000000000..befe3ba4f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/impl/codec/columns/ClickhouseColumnsTestReader.java @@ -0,0 +1,67 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.impl.codec.columns; + +import io.vertx.clickhouseclient.binary.impl.codec.QueryParsers; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + + +@RunWith(Parameterized.class) +public class ClickhouseColumnsTestReader { + private final String enumDefinition; + private final java.util.function.Function converter; + + public ClickhouseColumnsTestReader(String enumType, String enumDefinition, Function converter) { + this.enumDefinition = enumDefinition; + this.converter = converter; + } + + @Parameterized.Parameters(name = "{0}") + public static Iterable dataForTest() { + java.util.function.Function byteConverter = Integer::byteValue; + java.util.function.Function shortConverter = Integer::shortValue; + return Arrays.asList(new Object[][]{ + {"Enum8", "Enum8('aa4' = 1, '1b3b2' = 22, '1b3b3' = 24,'1b3b4' = 25,'1b3b5'= 26,'1b3b6' =27,'1b3b7'=28,'neg1'=-1, 'neg2' = -22)", byteConverter}, + {"Enum16", "Enum16('aa4' = 1, '1b3b2' = 22, '1b3b3' = 24,'1b3b4' = 25,'1b3b5'= 26,'1b3b6' =27,'1b3b7'=28,'neg1'=-1, 'neg2' = -22)", shortConverter} + }); + } + + private T key(Integer k) { + return converter.apply(k); + } + + @Test + public void testParseEnumVals() { + Map vals = QueryParsers.parseEnumValues(enumDefinition); + Map expected = new HashMap<>(); + expected.put(key(1), "aa4"); + expected.put(key(22), "1b3b2"); + expected.put(key(24), "1b3b3"); + expected.put(key(25), "1b3b4"); + expected.put(key(26), "1b3b5"); + expected.put(key(27), "1b3b6"); + expected.put(key(28), "1b3b7"); + expected.put(key(-1), "neg1"); + expected.put(key(-22), "neg2"); + Assert.assertEquals(expected, vals); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryCollectorTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryCollectorTest.java new file mode 100644 index 000000000..b8415707a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryCollectorTest.java @@ -0,0 +1,31 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.tck.CollectorTestBase; +import org.junit.ClassRule; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryCollectorTest extends CollectorTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected void initConnector() { + connector = ClientConfig.CONNECT.connect(vertx, rule.options()); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryConnectionAutoRetryTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryConnectionAutoRetryTest.java new file mode 100644 index 000000000..0bd44349e --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryConnectionAutoRetryTest.java @@ -0,0 +1,51 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.tck.ConnectionAutoRetryTestBase; +import org.junit.ClassRule; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryConnectionAutoRetryTest extends ConnectionAutoRetryTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + public void setUp() throws Exception { + super.setUp(); + options = rule.options(); + } + + @Override + public void tearDown(TestContext ctx) { + connectionConnector.close(); + poolConnector.close(); + super.tearDown(ctx); + } + + @Override + protected void initialConnector(int proxyPort) { + SqlConnectOptions proxyOptions = new ClickhouseBinaryConnectOptions(options); + proxyOptions.setPort(proxyPort); + proxyOptions.setHost("localhost"); + connectionConnector = ClientConfig.CONNECT.connect(vertx, proxyOptions); + poolConnector = ClientConfig.POOLED.connect(vertx, proxyOptions); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryConnectionTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryConnectionTest.java new file mode 100644 index 000000000..854b2d90f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryConnectionTest.java @@ -0,0 +1,64 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.spi.DatabaseMetadata; +import io.vertx.sqlclient.tck.ConnectionTestBase; +import org.junit.ClassRule; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryConnectionTest extends ConnectionTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Rule + public TestName nameRule = new TestName(); + + @Override + public void setUp() throws Exception { + super.setUp(); + options = new ClickhouseBinaryConnectOptions(rule.options()); + options.addProperty(ClickhouseConstants.OPTION_APPLICATION_NAME, + this.getClass().getSimpleName() + "." + nameRule.getMethodName()); + connector = ClientConfig.CONNECT.connect(vertx, options); + } + + @Override + public void tearDown(TestContext ctx) { + connector.close(); + super.tearDown(ctx); + } + + @Override + protected void validateDatabaseMetaData(TestContext ctx, DatabaseMetadata md) { + ctx.assertTrue(md.majorVersion() >= 20); + ctx.assertTrue(md.productName().toLowerCase().contains("ClickHouse".toLowerCase())); + } + + //TODO: find a way to test that reliably with latest ClickHouse versions (see InitCommandCodec); 20.11.2.1 and older work fine + @Override + @Test + public void testConnectInvalidDatabase(TestContext ctx) { + super.testConnectInvalidDatabase(ctx); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDataTypeDecodeTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDataTypeDecodeTest.java new file mode 100644 index 000000000..4eae21fad --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDataTypeDecodeTest.java @@ -0,0 +1,143 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.data.Numeric; +import io.vertx.sqlclient.tck.BinaryDataTypeDecodeTestBase; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.sql.JDBCType; +import java.time.LocalDate; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryDataTypeDecodeTest extends BinaryDataTypeDecodeTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + public ClickhouseBinaryDataTypeDecodeTest() { + } + + @Override + protected JDBCType getNumericJDBCType() { + return JDBCType.DECIMAL; + } + + @Override + protected Class getNumericClass() { + return Numeric.class; + } + + @Override + protected Number getNumericValue(Number value) { + return Numeric.create(value); + } + + @Override + protected Number getNumericValue(String value) { + return Numeric.parse(value); + } + + @Override + protected void initConnector() { + connector = ClientConfig.CONNECT.connect(vertx, rule.options()); + } + + @Test + public void testSelectAll(TestContext ctx) { + //no time support + connector.connect(ctx.asyncAssertSuccess(conn -> { + conn.preparedQuery("SELECT " + + "test_int_2," + + "test_int_4," + + "test_int_8," + + "test_float_4," + + "test_float_8," + + "test_numeric," + + "test_decimal," + + "test_boolean," + + "test_char," + + "test_varchar," + + "test_date " + + "from basicdatatype where id = 1").execute(ctx.asyncAssertSuccess(result -> { + ctx.assertEquals(1, result.size()); + Row row = result.iterator().next(); + ctx.assertEquals(11, row.size()); + ctx.assertEquals((short) 32767, row.getShort(0)); + ctx.assertEquals(Short.valueOf((short) 32767), row.getShort("test_int_2")); + ctx.assertEquals(2147483647, row.getInteger(1)); + ctx.assertEquals(2147483647, row.getInteger("test_int_4")); + ctx.assertEquals(9223372036854775807L, row.getLong(2)); + ctx.assertEquals(9223372036854775807L, row.getLong("test_int_8")); + ctx.assertEquals(3.40282E38F, row.getFloat(3)); + ctx.assertEquals(3.40282E38F, row.getFloat("test_float_4")); + ctx.assertEquals(1.7976931348623157E308, row.getDouble(4)); + ctx.assertEquals(1.7976931348623157E308, row.getDouble("test_float_8")); + ctx.assertEquals(Numeric.create(999.99), row.get(Numeric.class, 5)); + ctx.assertEquals(Numeric.create(999.99), row.getValue("test_numeric")); + ctx.assertEquals(Numeric.create(12345), row.get(Numeric.class, 6)); + ctx.assertEquals(Numeric.create(12345), row.getValue("test_decimal")); + ctx.assertEquals(true, row.getValue(7)); + ctx.assertEquals(true, row.getValue("test_boolean")); + ctx.assertEquals("testchar", row.getString(8)); + ctx.assertEquals("testchar", row.getString("test_char")); + ctx.assertEquals("testvarchar", row.getString(9)); + ctx.assertEquals("testvarchar", row.getString("test_varchar")); + ctx.assertEquals(LocalDate.parse("2019-01-01"), row.getValue(10)); + ctx.assertEquals(LocalDate.parse("2019-01-01"), row.getValue("test_date")); + conn.close(); + })); + })); + } + + @Test + public void testNullValues(TestContext ctx) { + //no time support + connector.connect(ctx.asyncAssertSuccess(conn -> { + conn.preparedQuery("SELECT " + + "test_int_2," + + "test_int_4," + + "test_int_8," + + "test_float_4," + + "test_float_8," + + "test_numeric," + + "test_decimal," + + "test_boolean," + + "test_char," + + "test_varchar," + + "test_date " + + "from basicdatatype where id = 3").execute(ctx.asyncAssertSuccess(result -> { + ctx.assertEquals(1, result.size()); + Row row = result.iterator().next(); + ctx.assertEquals(11, row.size()); + for (int i = 0; i < 11; i++) { + ctx.assertNull(row.getValue(i)); + } + conn.close(); + })); + })); + } + + @Ignore + @Test + public void testTime(TestContext ctx) { + //No time support + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDataTypeEncodeTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDataTypeEncodeTest.java new file mode 100644 index 000000000..e538c7c91 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDataTypeEncodeTest.java @@ -0,0 +1,154 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.clickhouseclient.binary.Sleep; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Row; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.data.Numeric; +import io.vertx.sqlclient.tck.BinaryDataTypeEncodeTestBase; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.sql.JDBCType; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryDataTypeEncodeTest extends BinaryDataTypeEncodeTestBase { + + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected JDBCType getNumericJDBCType() { + return JDBCType.DECIMAL; + } + + @Override + protected Class getNumericClass() { + return Numeric.class; + } + + @Override + protected Number getNumericValue(Number value) { + return Numeric.create(value); + } + + @Override + protected Number getNumericValue(String value) { + return Numeric.parse(value); + } + + @Override + protected void initConnector() { + connector = ClientConfig.CONNECT.connect(vertx, rule.options()); + } + + @Override + protected String statement(String... parts) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i > 0) { + sb.append("$").append((i)); + } + sb.append(parts[i]); + } + return sb.toString(); + } + + @Ignore + @Test + public void testTime(TestContext ctx) { + //no time support + } + + @Test + @Override + public void testDouble(TestContext ctx) { + //Double.MIN_VALUE does not work here (due to 4.9E-324 != 0.0 error) + //22.9.1.2603: Fails with 'java.lang.AssertionError: Not equals : 4.9E-322 != 4.84E-322' + //No way to test with 22.9.1.2603: docker container is broken due to a 'Poco::Exception. Code: 1000, e.code() = 0, Not found: https_port (version 22.9.1.2603 (official build))' + //22.8.6.71 (and earlier) is fine + testEncodeGeneric(ctx, "test_float_8", Double.class, Row::getDouble, (double) Double.MIN_VALUE * 2); + } + + @Test + @Override + public void testFloat4(TestContext ctx) { + testEncodeGeneric(ctx, "test_float_4", Float.class, Row::getFloat, -2.402823e38F); + } + + //no time support, copied and modified test from parent + @Test + @Override + public void testNullValues(TestContext ctx) { + connector.connect(ctx.asyncAssertSuccess(conn -> { + conn + .preparedQuery(statement("ALTER TABLE basicdatatype UPDATE" + + " test_int_2 = ", + ", test_int_4 = ", + ", test_int_8 = ", + ", test_float_4 = ", + ", test_float_8 = ", + ", test_numeric = ", + ", test_decimal = ", + ", test_boolean = ", + ", test_char = ", + ", test_varchar = ", + ", test_date = ", + " WHERE id = 2")) + .execute(Tuple.tuple() + .addValue(null) + .addValue(null) + .addValue(null) + .addValue(null) + .addValue(null) + .addValue(null) + .addValue(null) + .addValue(null) + .addValue(null) + .addValue(null) + .addValue(null), + ctx.asyncAssertSuccess(updateResult -> { + Sleep.sleepOrThrow(); + conn + .preparedQuery("SELECT * FROM basicdatatype WHERE id = 2") + .execute(ctx.asyncAssertSuccess(result -> { + ctx.assertEquals(1, result.size()); + Row row = result.iterator().next(); + ctx.assertEquals(12, row.size()); + ctx.assertEquals(2, row.getInteger(0)); + for (int i = 1; i < 12; i++) { + ctx.assertNull(row.getValue(i)); + } + conn.close(); + })); + })); + })); + } + + @Override + protected void maybeSleep() { + Sleep.sleepOrThrow(); + } + + @Override + protected String encodeGenericUpdateStatement(String columnName, int id) { + return statement("ALTER TABLE basicdatatype UPDATE " + columnName + " = ", " WHERE id = " + id); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDriverTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDriverTest.java new file mode 100644 index 000000000..f1042a6cc --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryDriverTest.java @@ -0,0 +1,34 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.tck.DriverTestBase; +import org.junit.ClassRule; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryDriverTest extends DriverTestBase { + + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected SqlConnectOptions defaultOptions() { + return rule.options(); + } + +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedBatchTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedBatchTest.java new file mode 100644 index 000000000..214cf3e5f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedBatchTest.java @@ -0,0 +1,72 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.clickhouseclient.binary.Sleep; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Tuple; +import io.vertx.sqlclient.tck.PreparedBatchTestBase; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.util.ArrayList; +import java.util.List; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryPreparedBatchTest extends PreparedBatchTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected String statement(String... parts) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i > 0) { + sb.append("$").append((i)); + } + sb.append(parts[i]); + } + return sb.toString(); + } + + @Override + protected void initConnector() { + connector = ClientConfig.CONNECT.connect(vertx, rule.options()); + } + + @Test + public void testBatchQuery(TestContext ctx) { + connector.connect(ctx.asyncAssertSuccess(conn -> { + List batch = new ArrayList<>(); + batch.add(Tuple.of(1)); + batch.add(Tuple.of(3)); + batch.add(Tuple.of(5)); + //select multi-batches are not supported + conn.preparedQuery(statement("SELECT * FROM immutable WHERE id=", "")).executeBatch(batch, ctx.asyncAssertFailure()); + })); + } + + @Override + protected int expectedInsertBatchSize(List batch) { + return batch.size(); + } + + @Override + protected void maybeSleep() { + Sleep.sleepOrThrow(); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryCachedTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryCachedTest.java new file mode 100644 index 000000000..e7fa1167d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryCachedTest.java @@ -0,0 +1,148 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseConstants; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.tck.PreparedQueryCachedTestBase; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestName; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryPreparedQueryCachedTest extends PreparedQueryCachedTestBase { + + @Rule + public TestName nameRule = new TestName(); + + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected void initConnector() { + options = new ClickhouseBinaryConnectOptions(rule.options()); + options.addProperty(ClickhouseConstants.OPTION_APPLICATION_NAME, + this.getClass().getSimpleName() + "." + nameRule.getMethodName()); + connector = ClientConfig.CONNECT.connect(vertx, options); + } + + @Override + protected String statement(String... parts) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i > 0) { + sb.append("$").append((i)); + } + sb.append(parts[i]); + } + return sb.toString(); + } + + @Override + @Test + @Ignore + public void testQueryCursor(TestContext ctx) { + //TODO cursor support + super.testQueryCursor(ctx); + } + + @Override + @Test + @Ignore + public void testQueryCloseCursor(TestContext ctx) { + //TODO cursor support + super.testQueryCloseCursor(ctx); + } + + @Override + @Test + @Ignore + public void testQueryStreamCloseCursor(TestContext ctx) { + //TODO cursor support + super.testQueryStreamCloseCursor(ctx); + } + + @Override + @Test + @Ignore + public void testStreamQueryPauseInBatch(TestContext ctx) { + // TODO streaming support + super.testStreamQueryPauseInBatch(ctx); + } + + @Override + @Test + @Ignore + public void testStreamQueryPauseInBatchFromAnotherThread(TestContext ctx) { + // TODO streaming support + super.testStreamQueryPauseInBatchFromAnotherThread(ctx); + } + + @Override + @Test + @Ignore + public void testStreamQueryPauseResume(TestContext ctx) { + // TODO streaming support + super.testStreamQueryPauseResume(ctx); + } + + @Override + @Test + @Ignore + public void testStreamQuery(TestContext ctx) { + // TODO streaming support + super.testStreamQuery(ctx); + } + + @Override + @Test + @Ignore + public void testPreparedQueryParamCoercionTypeError(TestContext ctx) { + //no real prepared selects support + } + + @Override + @Ignore + @Test + public void testPrepareError(TestContext ctx) { + //no real prepared selects support + } + + @Override + @Ignore + @Test + public void testPreparedUpdateWithNullParams(TestContext ctx) { + //no real prepared selects support + } + + @Override + @Ignore + @Test + public void testPreparedUpdate(TestContext ctx) { + //Clickhouse does not return real affected row count + } + + @Override + @Ignore + @Test + public void testPreparedUpdateWithParams(TestContext ctx) { + //Clickhouse does not return real affected row count + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryPooledTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryPooledTest.java new file mode 100644 index 000000000..d8303129f --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryPooledTest.java @@ -0,0 +1,27 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryPreparedQueryPooledTest extends ClickhouseBinaryPreparedQueryTestBase { + @Override + protected void initConnector() { + options = rule.options(); + connector = ClientConfig.POOLED.connect(vertx, options); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryTest.java new file mode 100644 index 000000000..850222b7a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryTest.java @@ -0,0 +1,26 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.ext.unit.junit.VertxUnitRunner; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryPreparedQueryTest extends ClickhouseBinaryPreparedQueryTestBase { + @Override + protected void initConnector() { + options = rule.options(); + connector = ClientConfig.CONNECT.connect(vertx, options); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryTestBase.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryTestBase.java new file mode 100644 index 000000000..385aac667 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryPreparedQueryTestBase.java @@ -0,0 +1,129 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.TestContext; +import io.vertx.sqlclient.tck.PreparedQueryTestBase; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; + +public abstract class ClickhouseBinaryPreparedQueryTestBase extends PreparedQueryTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected String statement(String... parts) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i > 0) { + sb.append("$").append((i)); + } + sb.append(parts[i]); + } + return sb.toString(); + } + + @Override + @Test + @Ignore + public void testQueryCursor(TestContext ctx) { + //TODO cursor support + super.testQueryCursor(ctx); + } + + @Override + @Test + @Ignore + public void testQueryCloseCursor(TestContext ctx) { + //TODO cursor support + super.testQueryCloseCursor(ctx); + } + + @Override + @Test + @Ignore + public void testQueryStreamCloseCursor(TestContext ctx) { + //TODO cursor support + super.testQueryStreamCloseCursor(ctx); + } + + @Override + @Test + @Ignore + public void testStreamQueryPauseInBatch(TestContext ctx) { + // TODO streaming support + super.testStreamQueryPauseInBatch(ctx); + } + + @Override + @Test + @Ignore + public void testStreamQueryPauseInBatchFromAnotherThread(TestContext ctx) { + // TODO streaming support + super.testStreamQueryPauseInBatchFromAnotherThread(ctx); + } + + @Override + @Test + @Ignore + public void testStreamQueryPauseResume(TestContext ctx) { + // TODO streaming support + super.testStreamQueryPauseResume(ctx); + } + + @Override + @Test + @Ignore + public void testStreamQuery(TestContext ctx) { + // TODO streaming support + super.testStreamQuery(ctx); + } + + @Override + @Test + @Ignore + public void testPreparedQueryParamCoercionTypeError(TestContext ctx) { + //no real prepared selects support + } + + @Override + @Ignore + @Test + public void testPrepareError(TestContext ctx) { + //no real prepared selects support + } + + @Override + @Ignore + @Test + public void testPreparedUpdateWithNullParams(TestContext ctx) { + //no real prepared selects support + } + + @Override + @Ignore + @Test + public void testPreparedUpdate(TestContext ctx) { + //Clickhouse does not return real affected row count + } + + @Override + @Ignore + @Test + public void testPreparedUpdateWithParams(TestContext ctx) { + //Clickhouse does not return real affected row count + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinarySimpleQueryPooledTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinarySimpleQueryPooledTest.java new file mode 100644 index 000000000..56ea6520c --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinarySimpleQueryPooledTest.java @@ -0,0 +1,60 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.clickhouseclient.binary.Sleep; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.tck.SimpleQueryTestBase; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinarySimpleQueryPooledTest extends SimpleQueryTestBase { + + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected void initConnector() { + connector = ClientConfig.POOLED.connect(vertx, rule.options()); + } + + @Ignore + @Test + public void testDelete(TestContext ctx) { + //no way to return count of altered rows + } + + @Ignore + @Test + public void testInsert(TestContext ctx) { + //no way to return count of inserted rows (can be emulated) + } + + @Ignore + @Test + public void testUpdate(TestContext ctx) { + //no way to return count of altered rows + } + + @Override + protected void cleanTestTable(TestContext ctx) { + super.cleanTestTable(ctx); + Sleep.sleepOrThrow(); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinarySimpleQueryTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinarySimpleQueryTest.java new file mode 100644 index 000000000..e24a6dd12 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinarySimpleQueryTest.java @@ -0,0 +1,60 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.clickhouseclient.binary.Sleep; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.tck.SimpleQueryTestBase; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinarySimpleQueryTest extends SimpleQueryTestBase { + + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected void initConnector() { + connector = ClientConfig.CONNECT.connect(vertx, rule.options()); + } + + @Ignore + @Test + public void testDelete(TestContext ctx) { + //no way to return count of altered rows + } + + @Ignore + @Test + public void testInsert(TestContext ctx) { + //no way to return count of inserted rows (can be emulated) + } + + @Ignore + @Test + public void testUpdate(TestContext ctx) { + //no way to return count of altered rows + } + + @Override + protected void cleanTestTable(TestContext ctx) { + super.cleanTestTable(ctx); + Sleep.sleepOrThrow(); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTextDataTypeDecodeTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTextDataTypeDecodeTest.java new file mode 100644 index 000000000..695b7b3ba --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTextDataTypeDecodeTest.java @@ -0,0 +1,63 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.data.Numeric; +import io.vertx.sqlclient.tck.TextDataTypeDecodeTestBase; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.sql.JDBCType; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryTextDataTypeDecodeTest extends TextDataTypeDecodeTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected JDBCType getNumericJDBCType() { + return JDBCType.DECIMAL; + } + + @Override + protected Class getNumericClass() { + return Numeric.class; + } + + @Override + protected Number getNumericValue(Number value) { + return Numeric.create(value); + } + + @Override + protected Number getNumericValue(String value) { + return Numeric.parse(value); + } + + @Override + protected void initConnector() { + connector = ClientConfig.CONNECT.connect(vertx, rule.options()); + } + + @Ignore + @Test + public void testTime(TestContext ctx) { + //no time support + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTracingTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTracingTest.java new file mode 100644 index 000000000..f4494e1b2 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTracingTest.java @@ -0,0 +1,56 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryPool; +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.core.Vertx; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.Pool; +import io.vertx.sqlclient.PoolOptions; +import io.vertx.sqlclient.tck.TracingTestBase; +import org.junit.ClassRule; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryTracingTest extends TracingTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected Pool createPool(Vertx vertx) { + return ClickhouseBinaryPool.pool(vertx, rule.options(), new PoolOptions()); + } + + @Override + protected String statement(String... parts) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < parts.length; i++) { + if (i > 0) { + sb.append("$").append((i)); + } + sb.append(parts[i]); + } + return sb.toString(); + } + + @Ignore + @Test + public void testTraceBatchQuery(TestContext ctx) { + //no batch support for SELECTs + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTransactionTest.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTransactionTest.java new file mode 100644 index 000000000..980081150 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClickhouseBinaryTransactionTest.java @@ -0,0 +1,69 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseResource; +import io.vertx.ext.unit.TestContext; +import io.vertx.ext.unit.junit.VertxUnitRunner; +import io.vertx.sqlclient.data.Numeric; +import io.vertx.sqlclient.tck.DataTypeTestBase; +import org.junit.ClassRule; +import org.junit.Test; +import org.junit.runner.RunWith; + +import java.sql.JDBCType; + +@RunWith(VertxUnitRunner.class) +public class ClickhouseBinaryTransactionTest extends DataTypeTestBase { + @ClassRule + public static ClickhouseResource rule = new ClickhouseResource(); + + @Override + protected JDBCType getNumericJDBCType() { + return JDBCType.DECIMAL; + } + + @Override + protected Class getNumericClass() { + return Numeric.class; + } + + @Override + protected Number getNumericValue(Number value) { + return Numeric.create(value); + } + + @Override + protected Number getNumericValue(String value) { + return Numeric.parse(value); + } + + @Override + protected void initConnector() { + connector = ClientConfig.CONNECT.connect(vertx, rule.options()); + } + + + @Test + public void testTransactionsAreNotSupported(TestContext ctx) { + //transactions are not supported by DB at the moment + connector.connect(ctx.asyncAssertSuccess(res1 -> { + res1.begin(ctx.asyncAssertFailure( + err -> { + ctx.assertEquals(UnsupportedOperationException.class, err.getClass()); + } + )); + })); + } +} diff --git a/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClientConfig.java b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClientConfig.java new file mode 100644 index 000000000..7d19167a0 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/java/io/vertx/clickhouseclient/binary/tck/ClientConfig.java @@ -0,0 +1,74 @@ +/* + * + * Copyright (c) 2021 Vladimir Vishnevskii + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 + * which is available at https://www.apache.org/licenses/LICENSE-2.0. + * + * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 + * + */ + +package io.vertx.clickhouseclient.binary.tck; + +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnectOptions; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryConnection; +import io.vertx.clickhouseclient.binary.ClickhouseBinaryPool; +import io.vertx.core.AsyncResult; +import io.vertx.core.Future; +import io.vertx.core.Handler; +import io.vertx.core.Vertx; +import io.vertx.sqlclient.PoolOptions; +import io.vertx.sqlclient.SqlClient; +import io.vertx.sqlclient.SqlConnectOptions; +import io.vertx.sqlclient.tck.Connector; + +public enum ClientConfig { + CONNECT() { + @Override + Connector connect(Vertx vertx, SqlConnectOptions options) { + return new Connector() { + @Override + public void connect(Handler> handler) { + ClickhouseBinaryConnection.connect(vertx, new ClickhouseBinaryConnectOptions(options.toJson()), ar -> { + if (ar.succeeded()) { + handler.handle(Future.succeededFuture(ar.result())); + } else { + handler.handle(Future.failedFuture(ar.cause())); + } + }); + } + @Override + public void close() { + } + }; + } + }, + + POOLED() { + @Override + Connector connect(Vertx vertx, SqlConnectOptions options) { + ClickhouseBinaryPool pool = ClickhouseBinaryPool.pool(vertx, new ClickhouseBinaryConnectOptions(options.toJson()), new PoolOptions().setMaxSize(1)); + return new Connector() { + @Override + public void connect(Handler> handler) { + pool.getConnection(ar -> { + if (ar.succeeded()) { + handler.handle(Future.succeededFuture(ar.result())); + } else { + handler.handle(Future.failedFuture(ar.cause())); + } + }); + } + @Override + public void close() { + pool.close(); + } + }; + } + }; + + abstract Connector connect(Vertx vertx, SqlConnectOptions options); +} diff --git a/vertx-clickhouse-binary-client/src/test/python/gen_all_types_tables.py b/vertx-clickhouse-binary-client/src/test/python/gen_all_types_tables.py new file mode 100755 index 000000000..4b96fd3ea --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/python/gen_all_types_tables.py @@ -0,0 +1,45 @@ +#! /usr/bin/python3 + +ELEMENTARY_TYPES = [ 'Boolean', + 'Int8', 'UInt8', 'Int16', 'UInt16', 'Int32', 'UInt32', 'Int64', 'UInt64', 'Int128', 'String', + {'table': 'FixedString', 'type': 'FixedString(12)'}, + 'DateTime', {'table': 'datetime64', 'type': 'DateTime64(3)'}, 'Date', 'UUID', + {'table': 'Decimal32', 'type': 'Decimal32(4)'}, + {'table': 'Decimal64', 'type': 'Decimal64(4)'}, + {'table': 'Decimal128', 'type': 'Decimal128(4)'}, + {'table': 'Decimal256', 'type': 'Decimal256(4)'}, + {'table': 'Enum8', 'type': 'Enum8(\'v0\' = -128, \'v1\' = -2,\'v2\' = -1, \'v3\' = 0,\'v4\' = 1, \'v5\' = 2, \'v6\' = 127)'}, + {'table': 'Enum16', 'type': 'Enum16(\'v0\' = -32768, \'v1\' = -2,\'v2\' = -1, \'v3\' = 0,\'v4\' = 1, \'v5\' = 2, \'v6\' = 32767)'}, + 'Float32', 'Float64', 'IPv6', 'IPv4']; + +print('set allow_suspicious_low_cardinality_types=true;'); +print('set allow_experimental_bigint_types=true;'); + +for elem_spec in ELEMENTARY_TYPES: + table_name = elem_spec['table'] if isinstance(elem_spec, dict) else elem_spec; + table_name = "vertx_test_{0}".format(table_name.lower()); + type_name = elem_spec['type'] if isinstance(elem_spec, dict) else elem_spec; + print('DROP TABLE IF EXISTS {0};'.format(table_name)); + print('CREATE TABLE {0} ('.format(table_name)); + columns = ['id Int8']; + low_cardinality = type_name != 'UUID' and not type_name.startswith('DateTime64') \ + and not type_name.startswith('Decimal32(') and not type_name.startswith('Decimal64(') \ + and not type_name.startswith('Decimal128(') \ + and not type_name.startswith('Decimal256(') \ + and not type_name.startswith('Enum'); + columns.append('simple_t {0}'.format(type_name)); + columns.append('nullable_t Nullable({0})'.format(type_name)); + columns.append('array_t Array({0})'.format(type_name)); + columns.append('array3_t Array(Array(Array({0})))'.format(type_name)); + columns.append('nullable_array_t Array(Nullable({0}))'.format(type_name)); + columns.append('nullable_array3_t Array(Array(Array(Nullable({0}))))'.format(type_name)); + + if low_cardinality: + columns.append('simple_lc_t LowCardinality({0})'.format(type_name)); + columns.append('nullable_lc_t LowCardinality(Nullable({0}))'.format(type_name)); + columns.append('array_lc_t Array(LowCardinality({0}))'.format(type_name)); + columns.append('array3_lc_t Array(Array(Array(LowCardinality({0}))))'.format(type_name)); + columns.append('nullable_array_lc_t Array(LowCardinality(Nullable({0})))'.format(type_name)); + columns.append('nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable({0})))))'.format(type_name)); + print(' ', ',\n '.join(columns)); + print(') engine = Memory();'); diff --git a/vertx-clickhouse-binary-client/src/test/resources/ClickhouseBinaryPreparedQueryCachedTest_testConcurrentClose_with_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/ClickhouseBinaryPreparedQueryCachedTest_testConcurrentClose_with_compression.yaml new file mode 100644 index 000000000..859c27037 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/ClickhouseBinaryPreparedQueryCachedTest_testConcurrentClose_with_compression.yaml @@ -0,0 +1,79 @@ +# Packet 189 +peer0_0: !!binary | + AEZDbGlja0hvdXNlIENsaWNraG91c2VOYXRpdmVQcmVwYXJlZFF1ZXJ5Q2FjaGVkVGVzdC50ZXN0 + Q29uY3VycmVudENsb3NlFAqpqQMHZGVmYXVsdAdkZWZhdWx0B2RlZmF1bHQ= +# Packet 191 +peer1_0: !!binary | + AApDbGlja0hvdXNlFQOvqQMNRXVyb3BlL01vc2NvdwZiaG9yc2UD +# Packet 193 +peer0_1: !!binary | + AQABAAAJMC4wLjAuMDowAQh2bGFkaW1pcgZiaG9yc2VGQ2xpY2tIb3VzZSBDbGlja2hvdXNlTmF0 + aXZlUHJlcGFyZWRRdWVyeUNhY2hlZFRlc3QudGVzdENvbmN1cnJlbnRDbG9zZRQKqakDAAIPc2Vu + ZF9sb2dzX2xldmVsAQVkZWJ1ZwAAAgEXU0VMRUNUICogRlJPTSBpbW11dGFibGUCAKeDrGzVXHp8 + taxGvduG4hSCFAAAAAoAAACgAQAC/////wAAAA== +# Packet 195 +peer1_1: !!binary | + CgABAAL/////AAgBCmV2ZW50X3RpbWUIRGF0ZVRpbWVZWV9gF2V2ZW50X3RpbWVfbWljcm9zZWNv + bmRzBlVJbnQzMqjNCQAJaG9zdF9uYW1lBlN0cmluZwZiaG9yc2UIcXVlcnlfaWQGU3RyaW5nJDcx + MzdlMjIzLTJlMmYtNDM0Yy1iYTQyLTBkZDJiMzU5MjFkNgl0aHJlYWRfaWQGVUludDY0jQQAAAAA + AAAIcHJpb3JpdHkESW50OAcGc291cmNlBlN0cmluZwxleGVjdXRlUXVlcnkEdGV4dAZTdHJpbmdH + KGZyb20gMTI3LjAuMC4xOjM3Mzc2LCB1c2luZyBwcm9kdWN0aW9uIHBhcnNlcikgU0VMRUNUICog + RlJPTSBpbW11dGFibGU= +# Packet 197 +peer1_2: !!binary | + AQDMr9H3xEk130UQKUNmLuitgi0AAAAiAAAA8BMBAAL/////AAIAAmlkBUludDMyB21lc3NhZ2UG + U3RyaW5n +# Packet 199 +peer1_3: !!binary | + CgABAAL/////AAgCCmV2ZW50X3RpbWUIRGF0ZVRpbWVZWV9gWVlfYBdldmVudF90aW1lX21pY3Jv + c2Vjb25kcwZVSW50MzJ4zwkA988JAAlob3N0X25hbWUGU3RyaW5nBmJob3JzZQZiaG9yc2UIcXVl + cnlfaWQGU3RyaW5nJDcxMzdlMjIzLTJlMmYtNDM0Yy1iYTQyLTBkZDJiMzU5MjFkNiQ3MTM3ZTIy + My0yZTJmLTQzNGMtYmE0Mi0wZGQyYjM1OTIxZDYJdGhyZWFkX2lkBlVJbnQ2NI0EAAAAAAAAjQQA + AAAAAAAIcHJpb3JpdHkESW50OAcHBnNvdXJjZQZTdHJpbmciZGVmYXVsdC5pbW11dGFibGUgKFNl + bGVjdEV4ZWN1dG9yKSJkZWZhdWx0LmltbXV0YWJsZSAoU2VsZWN0RXhlY3V0b3IpBHRleHQGU3Ry + aW5nFktleSBjb25kaXRpb246IHVua25vd250U2VsZWN0ZWQgMi8yIHBhcnRzIGJ5IHBhcnRpdGlv + biBrZXksIDIgcGFydHMgYnkgcHJpbWFyeSBrZXksIDIvNCBtYXJrcyBieSBwcmltYXJ5IGtleSwg + MiBtYXJrcyB0byByZWFkIGZyb20gMiByYW5nZXM= +# Packet 201 +peer1_4: !!binary | + AQD4NBJnntW3moTD/45FsVjSgpQCAADHAgAA8C0BAAL/////AAILAmlkBUludDMyAQAAAAIAAAAD + AAAABAAAAAUAAAAGAAAABwAAAAgAAAAJAAAACgAAAAsUAPm7bWVzc2FnZQZTdHJpbmciZm9ydHVu + ZTogTm8gc3VjaCBmaWxlIG9yIGRpcmVjdG9yeURBIGNvbXB1dGVyIHNjaWVudGlzdCBpcyBzb21l + b25lIHdobyBmaXhlcyB0aGluZ3MgdGhhdCBhcmVuJ3QgYnJva2VuLjFBZnRlciBlbm91Z2ggZGVj + aW1hbCBwbGFjZXMsIG5vYm9keSBnaXZlcyBhIGRhbW4uP0EgYmFkIHJhbmRvbSBudW1iZXIgZ2Vu + ZXJhdG9yOiAxLAMAhTQuMzNlKzY3FgAXS7cA4HByb2dyYW0gZG9lcyB3ngDwAnlvdSB0ZWxsIGl0 + IHRvIGRvhQAWdBwARXdhbnQcAHAuSUVtYWNz9ACQYSBuaWNlIG9whwD1KGluZyBzeXN0ZW0sIGJ1 + dCBJIHByZWZlciBVTklYLiDigJQgVG9tIENocmlzdGFlbnNlbihBbnmPABB0igCgcnVucyByaWdo + dGAA029ic29sZXRlLj5BIGxoAeBvbmx5IGFzIHN0cm9uZwoA8gFpdHMgd2Vha2VzdCBsaW5rbADz + HkRvbmFsZCBLbnV0aB5GZWF0dXJlOiBBIGJ1ZyB3aXRoIHNlbmlvcml0eS4xQ9IB8gJzIG1ha2Ug + dmVyeSBmYXN0LAsAoGFjY3VyYXRlIG26APEQa2VzLk88c2NyaXB0PmFsZXJ0KCJUaGlzIHNob3Vs + ZDoB8AJiZSBkaXNwbGF5ZWQgaW4gYfoBUXdzZXIgMQDwAiBib3guIik7PC9zY3JpcHQ+ +# Packet 203 +peer1_5: !!binary | + AQCK4ZfoR2KBBKzMdIBzeLopglwAAABRAAAA8CcBAAL/////AAIBAmlkBUludDMyDAAAAAdtZXNz + YWdlBlN0cmluZyrjg5Xjg6zjg7zjg6Djg68JAPAIgq/jga7jg5njg7Pjg4Hjg57jg7zjgq8= +# Packet 205 +peer1_6: !!binary | + BgwCgAwAAAE= +# Packet 207 +peer1_7: !!binary | + Awy0BgwAAA== +# Packet 209 +peer1_8: !!binary | + AQCng6xs1Vx6fLWsRr3bhuIUghQAAAAKAAAAoAEAAv////8AAAA= +# Packet 211 +peer1_9: !!binary | + AwAAAAAA +# Packet 213 +peer1_10: !!binary | + CgABAAL/////AAgCCmV2ZW50X3RpbWUIRGF0ZVRpbWVZWV9gWVlfYBdldmVudF90aW1lX21pY3Jv + c2Vjb25kcwZVSW50MzLT0wkA7dMJAAlob3N0X25hbWUGU3RyaW5nBmJob3JzZQZiaG9yc2UIcXVl + cnlfaWQGU3RyaW5nJDcxMzdlMjIzLTJlMmYtNDM0Yy1iYTQyLTBkZDJiMzU5MjFkNiQ3MTM3ZTIy + My0yZTJmLTQzNGMtYmE0Mi0wZGQyYjM1OTIxZDYJdGhyZWFkX2lkBlVJbnQ2NI0EAAAAAAAAjQQA + AAAAAAAIcHJpb3JpdHkESW50OAYHBnNvdXJjZQZTdHJpbmcMZXhlY3V0ZVF1ZXJ5DU1lbW9yeVRy + YWNrZXIEdGV4dAZTdHJpbmdLUmVhZCAxMiByb3dzLCA4MjAuMDAgQiBpbiAwLjAwMTUyMTY1NSBz + ZWMuLCA3ODg2IHJvd3Mvc2VjLiwgNTI2LjI2IEtpQi9zZWMuJlBlYWsgbWVtb3J5IHVzYWdlIChm + b3IgcXVlcnkpOiAwLjAwIEIu +# Packet 215 +peer1_11: !!binary | + BQ== diff --git a/vertx-clickhouse-binary-client/src/test/resources/forged_nested_exception.yaml b/vertx-clickhouse-binary-client/src/test/resources/forged_nested_exception.yaml new file mode 100644 index 000000000..21f4bdfc3 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/forged_nested_exception.yaml @@ -0,0 +1,30 @@ +# Packet 136 +peer0_0: !!binary | + AE1DbGlja0hvdXNlIENsaWNraG91c2VOYXRpdmVQcmVwYXJlZFF1ZXJ5Q2FjaGVkVGVzdC50ZXN0 + Q29ubmVjdEludmFsaWREYXRhYmFzZRQKqakDD2ludmFsaWREYXRhYmFzZQdkZWZhdWx0B2RlZmF1 + bHQ= +# Packet 138 +peer1_0: !!binary | + AlEAAAANREI6OkV4Y2VwdGlvbjdEQjo6RXhjZXB0aW9uOiBEYXRhYmFzZSBgaW52YWxpZERhdGFi + YXNlYCBkb2Vzbid0IGV4aXN0pwQwLiBEQjo6VENQSGFuZGxlcjo6cnVuSW1wbCgpIEAgMHhmOGJi + NmRmIGluIC91c3IvYmluL2NsaWNraG91c2UKMS4gREI6OlRDUEhhbmRsZXI6OnJ1bigpIEAgMHhm + OGNiZWM5IGluIC91c3IvYmluL2NsaWNraG91c2UKMi4gUG9jbzo6TmV0OjpUQ1BTZXJ2ZXJDb25u + ZWN0aW9uOjpzdGFydCgpIEAgMHgxMWY4MDFhZiBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjMuIFBv + Y286Ok5ldDo6VENQU2VydmVyRGlzcGF0Y2hlcjo6cnVuKCkgQCAweDExZjgxYmMxIGluIC91c3Iv + YmluL2NsaWNraG91c2UKNC4gUG9jbzo6UG9vbGVkVGhyZWFkOjpydW4oKSBAIDB4MTIwYjgyZTkg + aW4gL3Vzci9iaW4vY2xpY2tob3VzZQo1LiBQb2NvOjpUaHJlYWRJbXBsOjpydW5uYWJsZUVudHJ5 + KHZvaWQqKSBAIDB4MTIwYjQxNGEgaW4gL3Vzci9iaW4vY2xpY2tob3VzZQo2LiBzdGFydF90aHJl + YWQgQCAweDhlYTcgaW4gL2xpYi94ODZfNjQtbGludXgtZ251L2xpYnB0aHJlYWQtMi4zMS5zbwo3 + LiBfX2Nsb25lIEAgMHhmZGRlZiBpbiAvbGliL3g4Nl82NC1saW51eC1nbnUvbGliYy0yLjMxLnNv + CgFRAAAADURCOjpEeGNlcHRpb243REI6OkV4Y2VwdGlvbjogRGF0YWJhc2UgYGludmFsaWREYXRh + YmFzZWAgZG9lc24ndCBleGlzdKcEMC4gREI6OlRDUEhhbmRsZXI6OnJ1bkltcGwoKSBAIDB4Zjhi + YjZkZiBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjEuIERCOjpUQ1BIYW5kbGVyOjpydW4oKSBAIDB4 + ZjhjYmVjOSBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjIuIFBvY286Ok5ldDo6VENQU2VydmVyQ29u + bmVjdGlvbjo6c3RhcnQoKSBAIDB4MTFmODAxYWYgaW4gL3Vzci9iaW4vY2xpY2tob3VzZQozLiBQ + b2NvOjpOZXQ6OlRDUFNlcnZlckRpc3BhdGNoZXI6OnJ1bigpIEAgMHgxMWY4MWJjMSBpbiAvdXNy + L2Jpbi9jbGlja2hvdXNlCjQuIFBvY286OlBvb2xlZFRocmVhZDo6cnVuKCkgQCAweDEyMGI4MmU5 + IGluIC91c3IvYmluL2NsaWNraG91c2UKNS4gUG9jbzo6VGhyZWFkSW1wbDo6cnVubmFibGVFbnRy + eSh2b2lkKikgQCAweDEyMGI0MTRhIGluIC91c3IvYmluL2NsaWNraG91c2UKNi4gc3RhcnRfdGhy + ZWFkIEAgMHg4ZWE3IGluIC9saWIveDg2XzY0LWxpbnV4LWdudS9saWJwdGhyZWFkLTIuMzEuc28K + Ny4gX19jbG9uZSBAIDB4ZmRkZWYgaW4gL2xpYi94ODZfNjQtbGludXgtZ251L2xpYmMtMi4zMS5z + bwoA diff --git a/vertx-clickhouse-binary-client/src/test/resources/init.sql b/vertx-clickhouse-binary-client/src/test/resources/init.sql new file mode 100644 index 000000000..6c463b08a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/init.sql @@ -0,0 +1,504 @@ +-- USE testschema; +-- datatype testing table + +-- immutable table for select query testing -- +-- used by TCK +DROP TABLE IF EXISTS immutable; +CREATE TABLE immutable +( + id Int32, + message varchar(2048) +) engine = Memory(); + +INSERT INTO immutable (id, message) VALUES (1, 'fortune: No such file or directory'); +INSERT INTO immutable (id, message) VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.'); +INSERT INTO immutable (id, message) VALUES (3, 'After enough decimal places, nobody gives a damn.'); +INSERT INTO immutable (id, message) VALUES (4, 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1'); +INSERT INTO immutable (id, message) VALUES (5, 'A computer program does what you tell it to do, not what you want it to do.'); +INSERT INTO immutable (id, message) VALUES (6, 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen'); +INSERT INTO immutable (id, message) VALUES (7, 'Any program that runs right is obsolete.'); +INSERT INTO immutable (id, message) VALUES (8, 'A list is only as strong as its weakest link. — Donald Knuth'); +INSERT INTO immutable (id, message) VALUES (9, 'Feature: A bug with seniority.'); +INSERT INTO immutable (id, message) VALUES (10, 'Computers make very fast, very accurate mistakes.'); +INSERT INTO immutable (id, message) VALUES (11, ''); +INSERT INTO immutable (id, message) VALUES (12, 'フレームワークのベンチマーク'); + +-- mutable for insert,update,delete query testing -- +-- used by TCK +DROP TABLE IF EXISTS mutable; +CREATE TABLE mutable +( + id Int32, + val varchar(2048) +) engine = Memory(); + +-- basic data type table -- +-- used by TCK +DROP TABLE IF EXISTS basicdatatype; +CREATE TABLE basicdatatype +( + id Int16, + test_int_2 Nullable(Int16), + test_int_4 Nullable(Int32), + test_int_8 Nullable(Int64), + test_float_4 Nullable(Float32), + test_float_8 Nullable(Float64), + test_numeric Nullable(DECIMAL64(2)), + test_decimal Nullable(DECIMAL64(0)), + test_boolean Nullable(BOOLEAN), + test_char Nullable(FixedString(8)), + test_varchar Nullable(String(20)), + test_date Nullable(DATE) +) engine = Memory(); +INSERT INTO basicdatatype(id, test_int_2, test_int_4, test_int_8, + test_float_4, test_float_8, test_numeric, test_decimal, + test_boolean, test_char, test_varchar, + test_date) +VALUES (1, 32767, 2147483647, 9223372036854775807, + 3.40282E38, 1.7976931348623157E308, 999.99, 12345, + true, 'testchar', 'testvarchar', + '2019-01-01'); +INSERT INTO basicdatatype(id, test_int_2, test_int_4, test_int_8, + test_float_4, test_float_8, test_numeric, test_decimal, + test_boolean, test_char, test_varchar, + test_date) +VALUES (2, 32767, 2147483647, 9223372036854775807, + 3.40282E38, 1.7976931348623157E308, 999.99, 12345, + true, 'testchar', 'testvarchar', + '2019-01-01'); +INSERT INTO basicdatatype(id, test_int_2, test_int_4, test_int_8, + test_float_4, test_float_8, test_numeric, test_decimal, + test_boolean, test_char, test_varchar, test_date) +VALUES (3, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + +-- Collector API testing -- +-- used by TCK +DROP TABLE IF EXISTS collector_test; +CREATE TABLE collector_test +( + id Int16, + test_int_2 Int16, + test_int_4 Int32, + test_int_8 Int64, + test_float Float32, + test_double Float64, + test_varchar VARCHAR(20) +) engine = Memory(); +INSERT INTO collector_test VALUES (1, 32767, 2147483647, 9223372036854775807, 123.456, 1.234567, 'HELLO,WORLD'); +INSERT INTO collector_test VALUES (2, 32767, 2147483647, 9223372036854775807, 123.456, 1.234567, 'hello,world'); + +DROP TABLE IF EXISTS vertx_cl_test_table; +CREATE TABLE vertx_cl_test_table +( + `name` String, + `value` UInt32 +) +ENGINE = GenerateRandom(1, 5, 3); + +-- Fortune table +DROP TABLE IF EXISTS Fortune; +CREATE TABLE Fortune +( + id Int32, + message String +) engine = Memory(); + +INSERT INTO Fortune (id, message) +VALUES (1, 'fortune: No such file or directory'); +INSERT INTO Fortune (id, message) +VALUES (2, 'A computer scientist is someone who fixes things that aren''t broken.'); +INSERT INTO Fortune (id, message) +VALUES (3, 'After enough decimal places, nobody gives a damn.'); +INSERT INTO Fortune (id, message) +VALUES (4, 'A bad random number generator: 1, 1, 1, 1, 1, 4.33e+67, 1, 1, 1'); +INSERT INTO Fortune (id, message) +VALUES (5, 'A computer program does what you tell it to do, not what you want it to do.'); +INSERT INTO Fortune (id, message) +VALUES (6, 'Emacs is a nice operating system, but I prefer UNIX. — Tom Christaensen'); +INSERT INTO Fortune (id, message) +VALUES (7, 'Any program that runs right is obsolete.'); +INSERT INTO Fortune (id, message) +VALUES (8, 'A list is only as strong as its weakest link. — Donald Knuth'); +INSERT INTO Fortune (id, message) +VALUES (9, 'Feature: A bug with seniority.'); +INSERT INTO Fortune (id, message) +VALUES (10, 'Computers make very fast, very accurate mistakes.'); +INSERT INTO Fortune (id, message) +VALUES (11, ''); +INSERT INTO Fortune (id, message) +VALUES (12, 'フレームワークのベンチマーク'); + + + + +--almost all possible supported types tables(maybe except experimental ones) +set allow_suspicious_low_cardinality_types=true; +set allow_experimental_bigint_types=true; +DROP TABLE IF EXISTS vertx_test_boolean; +CREATE TABLE vertx_test_boolean ( + id Int8, + simple_t Boolean, + nullable_t Nullable(Boolean), + array_t Array(Boolean), + array3_t Array(Array(Array(Boolean))), + nullable_array_t Array(Nullable(Boolean)), + nullable_array3_t Array(Array(Array(Nullable(Boolean)))), + simple_lc_t LowCardinality(Boolean), + nullable_lc_t LowCardinality(Nullable(Boolean)), + array_lc_t Array(LowCardinality(Boolean)), + array3_lc_t Array(Array(Array(LowCardinality(Boolean)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Boolean))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Boolean))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_int8; +CREATE TABLE vertx_test_int8 ( + id Int8, + simple_t Int8, + nullable_t Nullable(Int8), + array_t Array(Int8), + array3_t Array(Array(Array(Int8))), + nullable_array_t Array(Nullable(Int8)), + nullable_array3_t Array(Array(Array(Nullable(Int8)))), + simple_lc_t LowCardinality(Int8), + nullable_lc_t LowCardinality(Nullable(Int8)), + array_lc_t Array(LowCardinality(Int8)), + array3_lc_t Array(Array(Array(LowCardinality(Int8)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Int8))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Int8))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_uint8; +CREATE TABLE vertx_test_uint8 ( + id Int8, + simple_t UInt8, + nullable_t Nullable(UInt8), + array_t Array(UInt8), + array3_t Array(Array(Array(UInt8))), + nullable_array_t Array(Nullable(UInt8)), + nullable_array3_t Array(Array(Array(Nullable(UInt8)))), + simple_lc_t LowCardinality(UInt8), + nullable_lc_t LowCardinality(Nullable(UInt8)), + array_lc_t Array(LowCardinality(UInt8)), + array3_lc_t Array(Array(Array(LowCardinality(UInt8)))), + nullable_array_lc_t Array(LowCardinality(Nullable(UInt8))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(UInt8))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_int16; +CREATE TABLE vertx_test_int16 ( + id Int8, + simple_t Int16, + nullable_t Nullable(Int16), + array_t Array(Int16), + array3_t Array(Array(Array(Int16))), + nullable_array_t Array(Nullable(Int16)), + nullable_array3_t Array(Array(Array(Nullable(Int16)))), + simple_lc_t LowCardinality(Int16), + nullable_lc_t LowCardinality(Nullable(Int16)), + array_lc_t Array(LowCardinality(Int16)), + array3_lc_t Array(Array(Array(LowCardinality(Int16)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Int16))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Int16))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_uint16; +CREATE TABLE vertx_test_uint16 ( + id Int8, + simple_t UInt16, + nullable_t Nullable(UInt16), + array_t Array(UInt16), + array3_t Array(Array(Array(UInt16))), + nullable_array_t Array(Nullable(UInt16)), + nullable_array3_t Array(Array(Array(Nullable(UInt16)))), + simple_lc_t LowCardinality(UInt16), + nullable_lc_t LowCardinality(Nullable(UInt16)), + array_lc_t Array(LowCardinality(UInt16)), + array3_lc_t Array(Array(Array(LowCardinality(UInt16)))), + nullable_array_lc_t Array(LowCardinality(Nullable(UInt16))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(UInt16))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_int32; +CREATE TABLE vertx_test_int32 ( + id Int8, + simple_t Int32, + nullable_t Nullable(Int32), + array_t Array(Int32), + array3_t Array(Array(Array(Int32))), + nullable_array_t Array(Nullable(Int32)), + nullable_array3_t Array(Array(Array(Nullable(Int32)))), + simple_lc_t LowCardinality(Int32), + nullable_lc_t LowCardinality(Nullable(Int32)), + array_lc_t Array(LowCardinality(Int32)), + array3_lc_t Array(Array(Array(LowCardinality(Int32)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Int32))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Int32))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_uint32; +CREATE TABLE vertx_test_uint32 ( + id Int8, + simple_t UInt32, + nullable_t Nullable(UInt32), + array_t Array(UInt32), + array3_t Array(Array(Array(UInt32))), + nullable_array_t Array(Nullable(UInt32)), + nullable_array3_t Array(Array(Array(Nullable(UInt32)))), + simple_lc_t LowCardinality(UInt32), + nullable_lc_t LowCardinality(Nullable(UInt32)), + array_lc_t Array(LowCardinality(UInt32)), + array3_lc_t Array(Array(Array(LowCardinality(UInt32)))), + nullable_array_lc_t Array(LowCardinality(Nullable(UInt32))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(UInt32))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_int64; +CREATE TABLE vertx_test_int64 ( + id Int8, + simple_t Int64, + nullable_t Nullable(Int64), + array_t Array(Int64), + array3_t Array(Array(Array(Int64))), + nullable_array_t Array(Nullable(Int64)), + nullable_array3_t Array(Array(Array(Nullable(Int64)))), + simple_lc_t LowCardinality(Int64), + nullable_lc_t LowCardinality(Nullable(Int64)), + array_lc_t Array(LowCardinality(Int64)), + array3_lc_t Array(Array(Array(LowCardinality(Int64)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Int64))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Int64))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_uint64; +CREATE TABLE vertx_test_uint64 ( + id Int8, + simple_t UInt64, + nullable_t Nullable(UInt64), + array_t Array(UInt64), + array3_t Array(Array(Array(UInt64))), + nullable_array_t Array(Nullable(UInt64)), + nullable_array3_t Array(Array(Array(Nullable(UInt64)))), + simple_lc_t LowCardinality(UInt64), + nullable_lc_t LowCardinality(Nullable(UInt64)), + array_lc_t Array(LowCardinality(UInt64)), + array3_lc_t Array(Array(Array(LowCardinality(UInt64)))), + nullable_array_lc_t Array(LowCardinality(Nullable(UInt64))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(UInt64))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_int128; +CREATE TABLE vertx_test_int128 ( + id Int8, + simple_t Int128, + nullable_t Nullable(Int128), + array_t Array(Int128), + array3_t Array(Array(Array(Int128))), + nullable_array_t Array(Nullable(Int128)), + nullable_array3_t Array(Array(Array(Nullable(Int128)))), + simple_lc_t LowCardinality(Int128), + nullable_lc_t LowCardinality(Nullable(Int128)), + array_lc_t Array(LowCardinality(Int128)), + array3_lc_t Array(Array(Array(LowCardinality(Int128)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Int128))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Int128))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_string; +CREATE TABLE vertx_test_string ( + id Int8, + simple_t String, + nullable_t Nullable(String), + array_t Array(String), + array3_t Array(Array(Array(String))), + nullable_array_t Array(Nullable(String)), + nullable_array3_t Array(Array(Array(Nullable(String)))), + simple_lc_t LowCardinality(String), + nullable_lc_t LowCardinality(Nullable(String)), + array_lc_t Array(LowCardinality(String)), + array3_lc_t Array(Array(Array(LowCardinality(String)))), + nullable_array_lc_t Array(LowCardinality(Nullable(String))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(String))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_fixedstring; +CREATE TABLE vertx_test_fixedstring ( + id Int8, + simple_t FixedString(12), + nullable_t Nullable(FixedString(12)), + array_t Array(FixedString(12)), + array3_t Array(Array(Array(FixedString(12)))), + nullable_array_t Array(Nullable(FixedString(12))), + nullable_array3_t Array(Array(Array(Nullable(FixedString(12))))), + simple_lc_t LowCardinality(FixedString(12)), + nullable_lc_t LowCardinality(Nullable(FixedString(12))), + array_lc_t Array(LowCardinality(FixedString(12))), + array3_lc_t Array(Array(Array(LowCardinality(FixedString(12))))), + nullable_array_lc_t Array(LowCardinality(Nullable(FixedString(12)))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(FixedString(12)))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_datetime; +CREATE TABLE vertx_test_datetime ( + id Int8, + simple_t DateTime, + nullable_t Nullable(DateTime), + array_t Array(DateTime), + array3_t Array(Array(Array(DateTime))), + nullable_array_t Array(Nullable(DateTime)), + nullable_array3_t Array(Array(Array(Nullable(DateTime)))), + simple_lc_t LowCardinality(DateTime), + nullable_lc_t LowCardinality(Nullable(DateTime)), + array_lc_t Array(LowCardinality(DateTime)), + array3_lc_t Array(Array(Array(LowCardinality(DateTime)))), + nullable_array_lc_t Array(LowCardinality(Nullable(DateTime))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(DateTime))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_datetime64; +CREATE TABLE vertx_test_datetime64 ( + id Int8, + simple_t DateTime64(3), + nullable_t Nullable(DateTime64(3)), + array_t Array(DateTime64(3)), + array3_t Array(Array(Array(DateTime64(3)))), + nullable_array_t Array(Nullable(DateTime64(3))), + nullable_array3_t Array(Array(Array(Nullable(DateTime64(3))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_date; +CREATE TABLE vertx_test_date ( + id Int8, + simple_t Date, + nullable_t Nullable(Date), + array_t Array(Date), + array3_t Array(Array(Array(Date))), + nullable_array_t Array(Nullable(Date)), + nullable_array3_t Array(Array(Array(Nullable(Date)))), + simple_lc_t LowCardinality(Date), + nullable_lc_t LowCardinality(Nullable(Date)), + array_lc_t Array(LowCardinality(Date)), + array3_lc_t Array(Array(Array(LowCardinality(Date)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Date))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Date))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_uuid; +CREATE TABLE vertx_test_uuid ( + id Int8, + simple_t UUID, + nullable_t Nullable(UUID), + array_t Array(UUID), + array3_t Array(Array(Array(UUID))), + nullable_array_t Array(Nullable(UUID)), + nullable_array3_t Array(Array(Array(Nullable(UUID)))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_decimal32; +CREATE TABLE vertx_test_decimal32 ( + id Int8, + simple_t Decimal32(4), + nullable_t Nullable(Decimal32(4)), + array_t Array(Decimal32(4)), + array3_t Array(Array(Array(Decimal32(4)))), + nullable_array_t Array(Nullable(Decimal32(4))), + nullable_array3_t Array(Array(Array(Nullable(Decimal32(4))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_decimal64; +CREATE TABLE vertx_test_decimal64 ( + id Int8, + simple_t Decimal64(4), + nullable_t Nullable(Decimal64(4)), + array_t Array(Decimal64(4)), + array3_t Array(Array(Array(Decimal64(4)))), + nullable_array_t Array(Nullable(Decimal64(4))), + nullable_array3_t Array(Array(Array(Nullable(Decimal64(4))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_decimal128; +CREATE TABLE vertx_test_decimal128 ( + id Int8, + simple_t Decimal128(4), + nullable_t Nullable(Decimal128(4)), + array_t Array(Decimal128(4)), + array3_t Array(Array(Array(Decimal128(4)))), + nullable_array_t Array(Nullable(Decimal128(4))), + nullable_array3_t Array(Array(Array(Nullable(Decimal128(4))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_decimal256; +CREATE TABLE vertx_test_decimal256 ( + id Int8, + simple_t Decimal256(4), + nullable_t Nullable(Decimal256(4)), + array_t Array(Decimal256(4)), + array3_t Array(Array(Array(Decimal256(4)))), + nullable_array_t Array(Nullable(Decimal256(4))), + nullable_array3_t Array(Array(Array(Nullable(Decimal256(4))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_enum8; +CREATE TABLE vertx_test_enum8 ( + id Int8, + simple_t Enum8('v0' = -128, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 127), + nullable_t Nullable(Enum8('v0' = -128, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 127)), + array_t Array(Enum8('v0' = -128, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 127)), + array3_t Array(Array(Array(Enum8('v0' = -128, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 127)))), + nullable_array_t Array(Nullable(Enum8('v0' = -128, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 127))), + nullable_array3_t Array(Array(Array(Nullable(Enum8('v0' = -128, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 127))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_enum16; +CREATE TABLE vertx_test_enum16 ( + id Int8, + simple_t Enum16('v0' = -32768, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 32767), + nullable_t Nullable(Enum16('v0' = -32768, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 32767)), + array_t Array(Enum16('v0' = -32768, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 32767)), + array3_t Array(Array(Array(Enum16('v0' = -32768, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 32767)))), + nullable_array_t Array(Nullable(Enum16('v0' = -32768, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 32767))), + nullable_array3_t Array(Array(Array(Nullable(Enum16('v0' = -32768, 'v1' = -2,'v2' = -1, 'v3' = 0,'v4' = 1, 'v5' = 2, 'v6' = 32767))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_float32; +CREATE TABLE vertx_test_float32 ( + id Int8, + simple_t Float32, + nullable_t Nullable(Float32), + array_t Array(Float32), + array3_t Array(Array(Array(Float32))), + nullable_array_t Array(Nullable(Float32)), + nullable_array3_t Array(Array(Array(Nullable(Float32)))), + simple_lc_t LowCardinality(Float32), + nullable_lc_t LowCardinality(Nullable(Float32)), + array_lc_t Array(LowCardinality(Float32)), + array3_lc_t Array(Array(Array(LowCardinality(Float32)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Float32))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Float32))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_float64; +CREATE TABLE vertx_test_float64 ( + id Int8, + simple_t Float64, + nullable_t Nullable(Float64), + array_t Array(Float64), + array3_t Array(Array(Array(Float64))), + nullable_array_t Array(Nullable(Float64)), + nullable_array3_t Array(Array(Array(Nullable(Float64)))), + simple_lc_t LowCardinality(Float64), + nullable_lc_t LowCardinality(Nullable(Float64)), + array_lc_t Array(LowCardinality(Float64)), + array3_lc_t Array(Array(Array(LowCardinality(Float64)))), + nullable_array_lc_t Array(LowCardinality(Nullable(Float64))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(Float64))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_ipv6; +CREATE TABLE vertx_test_ipv6 ( + id Int8, + simple_t IPv6, + nullable_t Nullable(IPv6), + array_t Array(IPv6), + array3_t Array(Array(Array(IPv6))), + nullable_array_t Array(Nullable(IPv6)), + nullable_array3_t Array(Array(Array(Nullable(IPv6)))), + simple_lc_t LowCardinality(IPv6), + nullable_lc_t LowCardinality(Nullable(IPv6)), + array_lc_t Array(LowCardinality(IPv6)), + array3_lc_t Array(Array(Array(LowCardinality(IPv6)))), + nullable_array_lc_t Array(LowCardinality(Nullable(IPv6))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(IPv6))))) +) engine = Memory(); +DROP TABLE IF EXISTS vertx_test_ipv4; +CREATE TABLE vertx_test_ipv4 ( + id Int8, + simple_t IPv4, + nullable_t Nullable(IPv4), + array_t Array(IPv4), + array3_t Array(Array(Array(IPv4))), + nullable_array_t Array(Nullable(IPv4)), + nullable_array3_t Array(Array(Array(Nullable(IPv4)))), + simple_lc_t LowCardinality(IPv4), + nullable_lc_t LowCardinality(Nullable(IPv4)), + array_lc_t Array(LowCardinality(IPv4)), + array3_lc_t Array(Array(Array(LowCardinality(IPv4)))), + nullable_array_lc_t Array(LowCardinality(Nullable(IPv4))), + nullable_array3_lc_t Array(Array(Array(LowCardinality(Nullable(IPv4))))) +) engine = Memory(); diff --git a/vertx-clickhouse-binary-client/src/test/resources/insert_prepare_with_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/insert_prepare_with_compression.yaml new file mode 100644 index 000000000..64b86c99a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/insert_prepare_with_compression.yaml @@ -0,0 +1,28 @@ +# Packet 4 +peer0_0: !!binary | + ABhDbGlja0hvdXNlIGp5dGhvbi1kcml2ZXIUCqmpAwdkZWZhdWx0B2RlZmF1bHQHZGVmYXVsdA== +# Packet 6 +peer1_0: !!binary | + AApDbGlja0hvdXNlFQKvqQMNRXVyb3BlL01vc2NvdwZiaG9yc2UF +# Packet 8 +peer0_1: !!binary | + AQABAAAJMC4wLjAuMDowAQh2bGFkaW1pcgZiaG9yc2UYQ2xpY2tIb3VzZSBqeXRob24tZHJpdmVy + FAqpqQMAAg9zZW5kX2xvZ3NfbGV2ZWwBBWRlYnVnAAACAS5JTlNFUlQgSU5UTyBpbnNlcnRfc2Vs + ZWN0X3Rlc3R0YWJsZSAoKikgVkFMVUVTAgCng6xs1Vx6fLWsRr3bhuIUghQAAAAKAAAAoAEAAv// + //8AAAA= +# Packet 10 +peer1_1: !!binary | + CgABAAL/////AAgBCmV2ZW50X3RpbWUIRGF0ZVRpbWXDvkdgF2V2ZW50X3RpbWVfbWljcm9zZWNv + bmRzBlVJbnQzMp5jCAAJaG9zdF9uYW1lBlN0cmluZwZiaG9yc2UIcXVlcnlfaWQGU3RyaW5nJDIz + NmMzNzVmLTQxODMtNDdkNC04ODQ0LTE2YjkyYzc1ZWQ2MQl0aHJlYWRfaWQGVUludDY0kQQAAAAA + AAAIcHJpb3JpdHkESW50OAcGc291cmNlBlN0cmluZwxleGVjdXRlUXVlcnkEdGV4dAZTdHJpbmde + KGZyb20gMTI3LjAuMC4xOjM2MjAyLCB1c2luZyBwcm9kdWN0aW9uIHBhcnNlcikgSU5TRVJUIElO + VE8gaW5zZXJ0X3NlbGVjdF90ZXN0dGFibGUgKCopIFZBTFVFUw== +# Packet 12 +peer1_2: !!binary | + CwBCY29sdW1ucyBmb3JtYXQgdmVyc2lvbjogMQozIGNvbHVtbnM6CmBhYCBJbnQ4CmBiYCBTdHJp + bmcKYGNgIEludDgK +# Packet 14 +peer1_3: !!binary | + AQBIKPIcufqlLRMJXTEAsN65giwAAAAhAAAA8BIBAAL/////AAMAAWEESW50OAFiBlN0cmluZwFj + BEludDg= diff --git a/vertx-clickhouse-binary-client/src/test/resources/log4j2-test.xml b/vertx-clickhouse-binary-client/src/test/resources/log4j2-test.xml new file mode 100644 index 000000000..8338f1a2d --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/log4j2-test.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/vertx-clickhouse-binary-client/src/test/resources/nullable_low_cardinality_with_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/nullable_low_cardinality_with_compression.yaml new file mode 100644 index 000000000..3d33cf844 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/nullable_low_cardinality_with_compression.yaml @@ -0,0 +1,63 @@ +# Packet 4 +peer0_0: !!binary | + ABhDbGlja0hvdXNlIGp5dGhvbi1kcml2ZXIUCqmpAwdkZWZhdWx0B2RlZmF1bHQHZGVmYXVsdA== +# Packet 6 +peer1_0: !!binary | + AApDbGlja0hvdXNlFQOvqQMNRXVyb3BlL01vc2NvdwZiaG9yc2UC +# Packet 8 +peer0_1: !!binary | + AQABAAAJMC4wLjAuMDowAQh2bGFkaW1pcgZiaG9yc2UYQ2xpY2tIb3VzZSBqeXRob24tZHJpdmVy + FAqpqQMAAg9zZW5kX2xvZ3NfbGV2ZWwBBWRlYnVnAAACAagBc2VsZWN0IENBU1QoJ2FhJywgJ0xv + d0NhcmRpbmFsaXR5KE51bGxhYmxlKFN0cmluZykpJykgYXMgbmFtZSwgJ2FhJyBhcyBjb2xfdmFs + IFVOSU9OIEFMTCAgc2VsZWN0IENBU1QoTlVMTCwgJ0xvd0NhcmRpbmFsaXR5KE51bGxhYmxlKFN0 + cmluZykpJykgYXMgbmFtZSwgJ2JiJyBhcyBjb2xfdmFsAgCng6xs1Vx6fLWsRr3bhuIUghQAAAAK + AAAAoAEAAv////8AAAA= +# Packet 10 +peer1_1: !!binary | + CgABAAL/////AAgBCmV2ZW50X3RpbWUIRGF0ZVRpbWXYyktgF2V2ZW50X3RpbWVfbWljcm9zZWNv + bmRzBlVJbnQzMtyXCQAJaG9zdF9uYW1lBlN0cmluZwZiaG9yc2UIcXVlcnlfaWQGU3RyaW5nJDQ3 + MDBhMDMxLTQwOWItNGQ3Mi05ZGNjLWFiYmViMmVjYzQ0YQl0aHJlYWRfaWQGVUludDY0HxUFAAAA + AAAIcHJpb3JpdHkESW50OAcGc291cmNlBlN0cmluZwxleGVjdXRlUXVlcnkEdGV4dAZTdHJpbmfX + AShmcm9tIDEyNy4wLjAuMTo1NDIzMiwgdXNpbmcgcHJvZHVjdGlvbiBwYXJzZXIpIHNlbGVjdCBD + QVNUKCdhYScsICdMb3dDYXJkaW5hbGl0eShOdWxsYWJsZShTdHJpbmcpKScpIGFzIG5hbWUsICdh + YScgYXMgY29sX3ZhbCBVTklPTiBBTEwgc2VsZWN0IENBU1QoTlVMTCwgJ0xvd0NhcmRpbmFsaXR5 + KE51bGxhYmxlKFN0cmluZykpJykgYXMgbmFtZSwgJ2JiJyBhcyBjb2xfdmFs +# Packet 12 +peer1_2: !!binary | + AQDgC4IWJtBHB59qUDBOO5/RgkoAAAA/AAAA8DABAAL/////AAIABG5hbWUgTG93Q2FyZGluYWxp + dHkoTnVsbGFibGUoU3RyaW5nKSkHY29sX3ZhbAZTdHJpbmc= +# Packet 14 +peer1_3: !!binary | + AQBXaThdn+ITMOD5/5OIpQG1gmUAAABoAAAA8yMBAAL/////AAIBBG5hbWUgTG93Q2FyZGluYWxp + dHkoTnVsbGFibGUoU3RyaW5nKSkBAAEAEgYIABIDBwBkAAAAAmFhHQDwBAIHY29sX3ZhbAZTdHJp + bmcCYWE= +# Packet 16 +peer1_4: !!binary | + AQCuFGMBo2LZ43un9vPLkDJpgmEAAABlAAAA8yMBAAL/////AAIBBG5hbWUgTG93Q2FyZGluYWxp + dHkoTnVsbGFibGUoU3RyaW5nKSkBAAEAEgYIABICBwA1AAAAGgDwAwdjb2xfdmFsBlN0cmluZwJi + Yg== +# Packet 18 +peer1_5: !!binary | + BgICoRUAAAE= +# Packet 20 +peer1_6: !!binary | + AwICAAAA +# Packet 22 +peer1_7: !!binary | + AQCng6xs1Vx6fLWsRr3bhuIUghQAAAAKAAAAoAEAAv////8AAAA= +# Packet 24 +peer1_8: !!binary | + AwAAAAAA +# Packet 26 +peer1_9: !!binary | + CgABAAL/////AAgCCmV2ZW50X3RpbWUIRGF0ZVRpbWXYyktg2MpLYBdldmVudF90aW1lX21pY3Jv + c2Vjb25kcwZVSW50MzI3ngkAUp4JAAlob3N0X25hbWUGU3RyaW5nBmJob3JzZQZiaG9yc2UIcXVl + cnlfaWQGU3RyaW5nJDQ3MDBhMDMxLTQwOWItNGQ3Mi05ZGNjLWFiYmViMmVjYzQ0YSQ0NzAwYTAz + MS00MDliLTRkNzItOWRjYy1hYmJlYjJlY2M0NGEJdGhyZWFkX2lkBlVJbnQ2NB8VBQAAAAAAHxUF + AAAAAAAIcHJpb3JpdHkESW50OAYHBnNvdXJjZQZTdHJpbmcMZXhlY3V0ZVF1ZXJ5DU1lbW9yeVRy + YWNrZXIEdGV4dAZTdHJpbmdGUmVhZCAyIHJvd3MsIDIuMDAgQiBpbiAwLjAwMTU3MTQwMyBzZWMu + LCAxMjcyIHJvd3Mvc2VjLiwgMS4yNCBLaUIvc2VjLiZQZWFrIG1lbW9yeSB1c2FnZSAoZm9yIHF1 + ZXJ5KTogMC4wMCBCLg== +# Packet 28 +peer1_10: !!binary | + BQ== diff --git a/vertx-clickhouse-binary-client/src/test/resources/nullable_low_cardinality_without_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/nullable_low_cardinality_without_compression.yaml new file mode 100644 index 000000000..e1e621cde --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/nullable_low_cardinality_without_compression.yaml @@ -0,0 +1,60 @@ +# Packet 4 +peer0_0: !!binary | + ABhDbGlja0hvdXNlIGp5dGhvbi1kcml2ZXIUCqmpAwdkZWZhdWx0B2RlZmF1bHQHZGVmYXVsdA== +# Packet 6 +peer1_0: !!binary | + AApDbGlja0hvdXNlFQOvqQMNRXVyb3BlL01vc2NvdwZiaG9yc2UC +# Packet 8 +peer0_1: !!binary | + AQABAAAJMC4wLjAuMDowAQh2bGFkaW1pcgZiaG9yc2UYQ2xpY2tIb3VzZSBqeXRob24tZHJpdmVy + FAqpqQMAAg9zZW5kX2xvZ3NfbGV2ZWwBBWRlYnVnAAACAKgBc2VsZWN0IENBU1QoJ2FhJywgJ0xv + d0NhcmRpbmFsaXR5KE51bGxhYmxlKFN0cmluZykpJykgYXMgbmFtZSwgJ2FhJyBhcyBjb2xfdmFs + IFVOSU9OIEFMTCAgc2VsZWN0IENBU1QoTlVMTCwgJ0xvd0NhcmRpbmFsaXR5KE51bGxhYmxlKFN0 + cmluZykpJykgYXMgbmFtZSwgJ2JiJyBhcyBjb2xfdmFsAgABAAL/////AAAA +# Packet 10 +peer1_1: !!binary | + CgABAAL/////AAgBCmV2ZW50X3RpbWUIRGF0ZVRpbWWbyktgF2V2ZW50X3RpbWVfbWljcm9zZWNv + bmRzBlVJbnQzMqjvAgAJaG9zdF9uYW1lBlN0cmluZwZiaG9yc2UIcXVlcnlfaWQGU3RyaW5nJDdm + NGRkMTVmLTNhMjctNDgwYS04MTY2LTEzZWI1YzkzMmQzOQl0aHJlYWRfaWQGVUludDY0HxUFAAAA + AAAIcHJpb3JpdHkESW50OAcGc291cmNlBlN0cmluZwxleGVjdXRlUXVlcnkEdGV4dAZTdHJpbmfX + AShmcm9tIDEyNy4wLjAuMTo1NDIxNiwgdXNpbmcgcHJvZHVjdGlvbiBwYXJzZXIpIHNlbGVjdCBD + QVNUKCdhYScsICdMb3dDYXJkaW5hbGl0eShOdWxsYWJsZShTdHJpbmcpKScpIGFzIG5hbWUsICdh + YScgYXMgY29sX3ZhbCBVTklPTiBBTEwgc2VsZWN0IENBU1QoTlVMTCwgJ0xvd0NhcmRpbmFsaXR5 + KE51bGxhYmxlKFN0cmluZykpJykgYXMgbmFtZSwgJ2JiJyBhcyBjb2xfdmFs +# Packet 12 +peer1_2: !!binary | + AQABAAL/////AAIABG5hbWUgTG93Q2FyZGluYWxpdHkoTnVsbGFibGUoU3RyaW5nKSkHY29sX3Zh + bAZTdHJpbmc= +# Packet 14 +peer1_3: !!binary | + AQABAAL/////AAIBBG5hbWUgTG93Q2FyZGluYWxpdHkoTnVsbGFibGUoU3RyaW5nKSkBAAAAAAAA + AAAGAAAAAAAAAwAAAAAAAAAAAAJhYQEAAAAAAAAAAgdjb2xfdmFsBlN0cmluZwJhYQ== +# Packet 16 +peer1_4: !!binary | + AQABAAL/////AAIBBG5hbWUgTG93Q2FyZGluYWxpdHkoTnVsbGFibGUoU3RyaW5nKSkBAAAAAAAA + AAAGAAAAAAAAAgAAAAAAAAAAAAEAAAAAAAAAAAdjb2xfdmFsBlN0cmluZwJiYg== +# Packet 18 +peer1_5: !!binary | + BgICoRUAAAE= +# Packet 20 +peer1_6: !!binary | + AwICAAAA +# Packet 22 +peer1_7: !!binary | + AQABAAL/////AAAA +# Packet 24 +peer1_8: !!binary | + AwAAAAAA +# Packet 26 +peer1_9: !!binary | + CgABAAL/////AAgCCmV2ZW50X3RpbWUIRGF0ZVRpbWWbyktgm8pLYBdldmVudF90aW1lX21pY3Jv + c2Vjb25kcwZVSW50MzLT9AIA6vQCAAlob3N0X25hbWUGU3RyaW5nBmJob3JzZQZiaG9yc2UIcXVl + cnlfaWQGU3RyaW5nJDdmNGRkMTVmLTNhMjctNDgwYS04MTY2LTEzZWI1YzkzMmQzOSQ3ZjRkZDE1 + Zi0zYTI3LTQ4MGEtODE2Ni0xM2ViNWM5MzJkMzkJdGhyZWFkX2lkBlVJbnQ2NB8VBQAAAAAAHxUF + AAAAAAAIcHJpb3JpdHkESW50OAYHBnNvdXJjZQZTdHJpbmcMZXhlY3V0ZVF1ZXJ5DU1lbW9yeVRy + YWNrZXIEdGV4dAZTdHJpbmdGUmVhZCAyIHJvd3MsIDIuMDAgQiBpbiAwLjAwMTI2NDk1NCBzZWMu + LCAxNTgxIHJvd3Mvc2VjLiwgMS41NCBLaUIvc2VjLiZQZWFrIG1lbW9yeSB1c2FnZSAoZm9yIHF1 + ZXJ5KTogMC4wMCBCLg== +# Packet 28 +peer1_10: !!binary | + BQ== diff --git a/vertx-clickhouse-binary-client/src/test/resources/select_array_of_nullable_string_without_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/select_array_of_nullable_string_without_compression.yaml new file mode 100644 index 000000000..dc4e98db5 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/select_array_of_nullable_string_without_compression.yaml @@ -0,0 +1,54 @@ +# Packet 4 +peer0_0: !!binary | + ABhDbGlja0hvdXNlIGp5dGhvbi1kcml2ZXIUCqmpAwdkZWZhdWx0B2RlZmF1bHQHZGVmYXVsdA== +# Packet 6 +peer1_0: !!binary | + AApDbGlja0hvdXNlFQOvqQMNRXVyb3BlL01vc2NvdwZiaG9yc2UC +# Packet 8 +peer0_1: !!binary | + AQABAAAJMC4wLjAuMDowAQh2bGFkaW1pcgZiaG9yc2UYQ2xpY2tIb3VzZSBqeXRob24tZHJpdmVy + FAqpqQMAAg9zZW5kX2xvZ3NfbGV2ZWwBBWRlYnVnAAACAE1TRUxFQ1QgYXJyYXkoYXJyYXkoJ0En + LCAnQicpLCBhcnJheSgnQycsIE5VTEwpKSBBUyBSRVNPVVJDRSwgJ2FhJyBBUyBzdHJfY29sMgIA + AQAC/////wAAAA== +# Packet 10 +peer1_1: !!binary | + CgABAAL/////AAgBCmV2ZW50X3RpbWUIRGF0ZVRpbWWHD01gF2V2ZW50X3RpbWVfbWljcm9zZWNv + bmRzBlVJbnQzMhrUCwAJaG9zdF9uYW1lBlN0cmluZwZiaG9yc2UIcXVlcnlfaWQGU3RyaW5nJGJl + YjVhM2MzLTFmYjYtNDRjMS04OTg1LTZhNTBmYWU5NGE5Ygl0aHJlYWRfaWQGVUludDY0HxUFAAAA + AAAIcHJpb3JpdHkESW50OAcGc291cmNlBlN0cmluZwxleGVjdXRlUXVlcnkEdGV4dAZTdHJpbmd9 + KGZyb20gMTI3LjAuMC4xOjQ1MzkyLCB1c2luZyBwcm9kdWN0aW9uIHBhcnNlcikgU0VMRUNUIGFy + cmF5KGFycmF5KCdBJywgJ0InKSwgYXJyYXkoJ0MnLCBOVUxMKSkgQVMgUkVTT1VSQ0UsICdhYScg + QVMgc3RyX2NvbDI= +# Packet 12 +peer1_2: !!binary | + AQABAAL/////AAIACFJFU09VUkNFHkFycmF5KEFycmF5KE51bGxhYmxlKFN0cmluZykpKQhzdHJf + Y29sMgZTdHJpbmc= +# Packet 14 +peer1_3: !!binary | + AQABAAL/////AAIBCFJFU09VUkNFHkFycmF5KEFycmF5KE51bGxhYmxlKFN0cmluZykpKQIAAAAA + AAAAAgAAAAAAAAAEAAAAAAAAAAAAAAEBQQFCAUMACHN0cl9jb2wyBlN0cmluZwJhYQ== +# Packet 16 +peer1_4: !!binary | + BgEBkCMAAAE= +# Packet 18 +peer1_5: !!binary | + AwEBAAAA +# Packet 20 +peer1_6: !!binary | + AQABAAL/////AAAA +# Packet 22 +peer1_7: !!binary | + AwAAAAAA +# Packet 24 +peer1_8: !!binary | + CgABAAL/////AAgCCmV2ZW50X3RpbWUIRGF0ZVRpbWWHD01ghw9NYBdldmVudF90aW1lX21pY3Jv + c2Vjb25kcwZVSW50MzJF3AsAZNwLAAlob3N0X25hbWUGU3RyaW5nBmJob3JzZQZiaG9yc2UIcXVl + cnlfaWQGU3RyaW5nJGJlYjVhM2MzLTFmYjYtNDRjMS04OTg1LTZhNTBmYWU5NGE5YiRiZWI1YTNj + My0xZmI2LTQ0YzEtODk4NS02YTUwZmFlOTRhOWIJdGhyZWFkX2lkBlVJbnQ2NB8VBQAAAAAAHxUF + AAAAAAAIcHJpb3JpdHkESW50OAYHBnNvdXJjZQZTdHJpbmcMZXhlY3V0ZVF1ZXJ5DU1lbW9yeVRy + YWNrZXIEdGV4dAZTdHJpbmdDUmVhZCAxIHJvd3MsIDEuMDAgQiBpbiAwLjAwMjA0MzMgc2VjLiwg + NDg5IHJvd3Mvc2VjLiwgNDg5LjQwIEIvc2VjLiZQZWFrIG1lbW9yeSB1c2FnZSAoZm9yIHF1ZXJ5 + KTogMC4wMCBCLg== +# Packet 26 +peer1_9: !!binary | + BQ== diff --git a/vertx-clickhouse-binary-client/src/test/resources/select_empty_array_without_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/select_empty_array_without_compression.yaml new file mode 100644 index 000000000..623565af0 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/select_empty_array_without_compression.yaml @@ -0,0 +1,51 @@ +# Packet 4 +peer0_0: !!binary | + ABhDbGlja0hvdXNlIGp5dGhvbi1kcml2ZXIUCqmpAwdkZWZhdWx0B2RlZmF1bHQHZGVmYXVsdA== +# Packet 6 +peer1_0: !!binary | + AApDbGlja0hvdXNlFQOvqQMNRXVyb3BlL01vc2NvdwZiaG9yc2UC +# Packet 8 +peer0_1: !!binary | + AQABAAAJMC4wLjAuMDowAQh2bGFkaW1pcgZiaG9yc2UYQ2xpY2tIb3VzZSBqeXRob24tZHJpdmVy + FAqpqQMAAg9zZW5kX2xvZ3NfbGV2ZWwBBWRlYnVnAAACAChTRUxFQ1QgYXJyYXkoKSBBUyBuYW1l + LCAncjEnIGFzIGNvbF9uYW1lAgABAAL/////AAAA +# Packet 10 +peer1_1: !!binary | + CgABAAL/////AAgBCmV2ZW50X3RpbWUIRGF0ZVRpbWVbQE1gF2V2ZW50X3RpbWVfbWljcm9zZWNv + bmRzBlVJbnQzMpfaCwAJaG9zdF9uYW1lBlN0cmluZwZiaG9yc2UIcXVlcnlfaWQGU3RyaW5nJDNm + MzNlYmI0LWJkYTItNDcwNy04YjhhLTgwMzFiNTBmMzg0YQl0aHJlYWRfaWQGVUludDY0HxUFAAAA + AAAIcHJpb3JpdHkESW50OAcGc291cmNlBlN0cmluZwxleGVjdXRlUXVlcnkEdGV4dAZTdHJpbmdY + KGZyb20gMTI3LjAuMC4xOjM3ODk4LCB1c2luZyBwcm9kdWN0aW9uIHBhcnNlcikgU0VMRUNUIGFy + cmF5KCkgQVMgbmFtZSwgJ3IxJyBhcyBjb2xfbmFtZQ== +# Packet 12 +peer1_2: !!binary | + AQABAAL/////AAIABG5hbWUOQXJyYXkoTm90aGluZykIY29sX25hbWUGU3RyaW5n +# Packet 14 +peer1_3: !!binary | + AQABAAL/////AAIBBG5hbWUOQXJyYXkoTm90aGluZykAAAAAAAAAAAhjb2xfbmFtZQZTdHJpbmcC + cjE= +# Packet 16 +peer1_4: !!binary | + BgEB0EAAAAE= +# Packet 18 +peer1_5: !!binary | + AwEBAAAA +# Packet 20 +peer1_6: !!binary | + AQABAAL/////AAAA +# Packet 22 +peer1_7: !!binary | + AwAAAAAA +# Packet 24 +peer1_8: !!binary | + CgABAAL/////AAgCCmV2ZW50X3RpbWUIRGF0ZVRpbWVbQE1gW0BNYBdldmVudF90aW1lX21pY3Jv + c2Vjb25kcwZVSW50MzIe4AsASuALAAlob3N0X25hbWUGU3RyaW5nBmJob3JzZQZiaG9yc2UIcXVl + cnlfaWQGU3RyaW5nJDNmMzNlYmI0LWJkYTItNDcwNy04YjhhLTgwMzFiNTBmMzg0YSQzZjMzZWJi + NC1iZGEyLTQ3MDctOGI4YS04MDMxYjUwZjM4NGEJdGhyZWFkX2lkBlVJbnQ2NB8VBQAAAAAAHxUF + AAAAAAAIcHJpb3JpdHkESW50OAYHBnNvdXJjZQZTdHJpbmcMZXhlY3V0ZVF1ZXJ5DU1lbW9yeVRy + YWNrZXIEdGV4dAZTdHJpbmdFUmVhZCAxIHJvd3MsIDEuMDAgQiBpbiAwLjAwMTM1ODQwMSBzZWMu + LCA3MzYgcm93cy9zZWMuLCA3MzYuMTYgQi9zZWMuJlBlYWsgbWVtb3J5IHVzYWdlIChmb3IgcXVl + cnkpOiAwLjAwIEIu +# Packet 26 +peer1_9: !!binary | + BQ== diff --git a/vertx-clickhouse-binary-client/src/test/resources/testConnectInvalidDatabase_20.10.2_without_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/testConnectInvalidDatabase_20.10.2_without_compression.yaml new file mode 100644 index 000000000..3f36e8465 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/testConnectInvalidDatabase_20.10.2_without_compression.yaml @@ -0,0 +1,32 @@ +peers: + - peer: 0 + host: 127.0.0.1 + port: 38066 + - peer: 1 + host: 127.0.0.1 + port: 9000 +packets: + - packet: 10 + peer: 0 + index: 0 + timestamp: 1665938677.585407195 + data: !!binary | + AERDbGlja0hvdXNlIENsaWNraG91c2VCaW5hcnlDb25uZWN0aW9uVGVzdC50ZXN0Q29ubmVjdElu + dmFsaWREYXRhYmFzZRQKqakDD2ludmFsaWREYXRhYmFzZQR0ZXN0BHRlc3Q= + - packet: 22 + peer: 1 + index: 0 + timestamp: 1665938677.586282510 + data: !!binary | + AlEAAAANREI6OkV4Y2VwdGlvbjdEQjo6RXhjZXB0aW9uOiBEYXRhYmFzZSBgaW52YWxpZERhdGFi + YXNlYCBkb2Vzbid0IGV4aXN0rgQwLiBEQjo6VENQSGFuZGxlcjo6cnVuSW1wbCgpIEAgMHhlNTY5 + OTcyIGluIC91c3IvYmluL2NsaWNraG91c2UKMS4gREI6OlRDUEhhbmRsZXI6OnJ1bigpIEAgMHhl + NTc3MWI3IGluIC91c3IvYmluL2NsaWNraG91c2UKMi4gUG9jbzo6TmV0OjpUQ1BTZXJ2ZXJDb25u + ZWN0aW9uOjpzdGFydCgpIEAgMHgxMGQ0ZjcxZiBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjMuIFBv + Y286Ok5ldDo6VENQU2VydmVyRGlzcGF0Y2hlcjo6cnVuKCkgQCAweDEwZDUxMTJlIGluIC91c3Iv + YmluL2NsaWNraG91c2UKNC4gUG9jbzo6UG9vbGVkVGhyZWFkOjpydW4oKSBAIDB4MTBlODIzZTkg + aW4gL3Vzci9iaW4vY2xpY2tob3VzZQo1LiBQb2NvOjpUaHJlYWRJbXBsOjpydW5uYWJsZUVudHJ5 + KHZvaWQqKSBAIDB4MTBlN2UzMWEgaW4gL3Vzci9iaW4vY2xpY2tob3VzZQo2LiBzdGFydF90aHJl + YWQgQCAweDk2MDkgaW4gL3Vzci9saWIveDg2XzY0LWxpbnV4LWdudS9saWJwdGhyZWFkLTIuMzEu + c28KNy4gY2xvbmUgQCAweDEyMjI5MyBpbiAvdXNyL2xpYi94ODZfNjQtbGludXgtZ251L2xpYmMt + Mi4zMS5zbwoA diff --git a/vertx-clickhouse-binary-client/src/test/resources/testConnectInvalidDatabase_22.8.6.71_without_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/testConnectInvalidDatabase_22.8.6.71_without_compression.yaml new file mode 100644 index 000000000..6e27cb652 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/testConnectInvalidDatabase_22.8.6.71_without_compression.yaml @@ -0,0 +1,49 @@ +peers: + - peer: 0 + host: 127.0.0.1 + port: 40408 + - peer: 1 + host: 127.0.0.1 + port: 9000 +packets: + - packet: 10 + peer: 0 + index: 0 + timestamp: 1665939249.457106986 + data: !!binary | + AERDbGlja0hvdXNlIENsaWNraG91c2VCaW5hcnlDb25uZWN0aW9uVGVzdC50ZXN0Q29ubmVjdElu + dmFsaWREYXRhYmFzZRQKqakDD2ludmFsaWREYXRhYmFzZQR0ZXN0BHRlc3Q= + - packet: 20 + peer: 1 + index: 0 + timestamp: 1665939249.457535943 + data: !!binary | + AApDbGlja0hvdXNlFgi8qQMDVVRDDDRmMjgxMTZiZjkwMQY= + - packet: 26 + peer: 1 + index: 1 + timestamp: 1665939249.457558245 + data: !!binary | + AlEAAAANREI6OkV4Y2VwdGlvbjVEQjo6RXhjZXB0aW9uOiBEYXRhYmFzZSBpbnZhbGlkRGF0YWJh + c2UgZG9lc24ndCBleGlzdKQJMC4gREI6OkV4Y2VwdGlvbjo6RXhjZXB0aW9uKHN0ZDo6X18xOjpi + YXNpY19zdHJpbmc8Y2hhciwgc3RkOjpfXzE6OmNoYXJfdHJhaXRzPGNoYXI+LCBzdGQ6Ol9fMTo6 + YWxsb2NhdG9yPGNoYXI+ID4gY29uc3QmLCBpbnQsIGJvb2wpIEAgMHhhM2VjNzNhIGluIC91c3Iv + YmluL2NsaWNraG91c2UKMS4gREI6OkRhdGFiYXNlQ2F0YWxvZzo6YXNzZXJ0RGF0YWJhc2VFeGlz + dHNVbmxvY2tlZChzdGQ6Ol9fMTo6YmFzaWNfc3RyaW5nPGNoYXIsIHN0ZDo6X18xOjpjaGFyX3Ry + YWl0czxjaGFyPiwgc3RkOjpfXzE6OmFsbG9jYXRvcjxjaGFyPiA+IGNvbnN0JikgY29uc3QgQCAw + eDE0OGYyOTBkIGluIC91c3IvYmluL2NsaWNraG91c2UKMi4gREI6OkRhdGFiYXNlQ2F0YWxvZzo6 + YXNzZXJ0RGF0YWJhc2VFeGlzdHMoc3RkOjpfXzE6OmJhc2ljX3N0cmluZzxjaGFyLCBzdGQ6Ol9f + MTo6Y2hhcl90cmFpdHM8Y2hhcj4sIHN0ZDo6X18xOjphbGxvY2F0b3I8Y2hhcj4gPiBjb25zdCYp + IGNvbnN0IEAgMHgxNDhmMjdhMiBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjMuIERCOjpDb250ZXh0 + OjpzZXRDdXJyZW50RGF0YWJhc2Uoc3RkOjpfXzE6OmJhc2ljX3N0cmluZzxjaGFyLCBzdGQ6Ol9f + MTo6Y2hhcl90cmFpdHM8Y2hhcj4sIHN0ZDo6X18xOjphbGxvY2F0b3I8Y2hhcj4gPiBjb25zdCYp + IEAgMHgxNDg2MDdhMSBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjQuIERCOjpUQ1BIYW5kbGVyOjpy + dW5JbXBsKCkgQCAweDE1YzBkZjQ3IGluIC91c3IvYmluL2NsaWNraG91c2UKNS4gREI6OlRDUEhh + bmRsZXI6OnJ1bigpIEAgMHgxNWMxZmU5OSBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjYuIFBvY286 + Ok5ldDo6VENQU2VydmVyQ29ubmVjdGlvbjo6c3RhcnQoKSBAIDB4MTg5OGFmNzMgaW4gL3Vzci9i + aW4vY2xpY2tob3VzZQo3LiBQb2NvOjpOZXQ6OlRDUFNlcnZlckRpc3BhdGNoZXI6OnJ1bigpIEAg + MHgxODk4YzJjZCBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjguIFBvY286OlBvb2xlZFRocmVhZDo6 + cnVuKCkgQCAweDE4YjRlYTI5IGluIC91c3IvYmluL2NsaWNraG91c2UKOS4gUG9jbzo6VGhyZWFk + SW1wbDo6cnVubmFibGVFbnRyeSh2b2lkKikgQCAweDE4YjRjMmUyIGluIC91c3IvYmluL2NsaWNr + aG91c2UKMTAuID8gQCAweDdmMDQ3NmI0MjYwOSBpbiA/CjExLiBjbG9uZSBAIDB4N2YwNDc2YTY3 + MTMzIGluID8KAA== diff --git a/vertx-clickhouse-binary-client/src/test/resources/with_max_block_size_and_2_datablocks_with_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/with_max_block_size_and_2_datablocks_with_compression.yaml new file mode 100644 index 000000000..d57e166d6 --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/with_max_block_size_and_2_datablocks_with_compression.yaml @@ -0,0 +1,45 @@ +# Packet 4 +peer0_0: !!binary | + ABhDbGlja0hvdXNlIGp5dGhvbi1kcml2ZXIUCqmpAwdkZWZhdWx0B2RlZmF1bHQHZGVmYXVsdA== +# Packet 6 +peer1_0: !!binary | + AApDbGlja0hvdXNlFQKvqQMNRXVyb3BlL01vc2NvdwZiaG9yc2UF +# Packet 8 +peer0_1: !!binary | + AQABAAAJMC4wLjAuMDowAQh2bGFkaW1pcgZiaG9yc2UYQ2xpY2tIb3VzZSBqeXRob24tZHJpdmVy + FAqpqQMAAg5tYXhfYmxvY2tfc2l6ZQECNTAAAAIBZHNlbGVjdCBuYW1lLCB2YWx1ZSBmcm9tIChT + RUxFQ1QgbmFtZSwgdmFsdWUgZnJvbSB2ZXJ0eF9jbF90ZXN0X3RhYmxlIGxpbWl0IDU1KSB0MSBv + cmRlciBieSBuYW1lIGRlc2MCAKeDrGzVXHp8taxGvduG4hSCFAAAAAoAAACgAQAC/////wAAAA== +# Packet 10 +peer1_1: !!binary | + AQBicwHkjGdcDo5MWkTMRbtOgi4AAAAjAAAA8BQBAAL/////AAIABG5hbWUGU3RyaW5nBXZhbHVl + BlVJbnQzMg== +# Packet 12 +peer1_2: !!binary | + AQCx4PZsr1XBX5U/lPIe9471grQBAACoAQAA8P+aAQAC/////wACMgRuYW1lBlN0cmluZwJ7aQR7 + RnVLBXl7SUA1AXkFeHV5bGgEeEAmbwJzKwJweQFrAmdjA2ZmLAVmI3BiSgFlAWIEYSdQYAJgYgVd + YCtycwVdOjpgLwNaIWkBWgVYRDBaegNXQ0gCVEoCVDICT2sBTwVLY0ZzJAFGBEVVSVoBRQRDckp3 + BUB2cGFTBT5JQkhFAT4BPQQ8aTw/BTtZI1ZZAzlZVgU5N2hxYQE5ATcDM21uBDNORG4DMER2Ay0y + dgEpAidHBCE7aFEAAAV2YWx1ZQZVSW50MzIZau9oH+r3XisCpaD436HtlAmcwpeNsTJr6e1xMFSZ + 7F9egG+ffWSQxNMEOu+NXx47vlJ1AILiTQuVGhuBd0PHYDAjkUxsHDg8IrICpyFLWQ7DTwMYcYFn + 1KFkIHb0q7TIqEEIu1lq/reMAjPrm0d4sigZonzGGasj4Xf8KhgYv/t3resP2ROWE+GUFdtdWUt9 + 5pK8C4fy31H1nvq8YLa8ajedGLw8hP6Nti/Xct1fsJLUdWBG92LSJwsjYHY71dVqQkJqmXsI4w== +# Packet 14 +peer1_3: !!binary | + AQAJ2NHGgowQkuLjsPN8N5logkcAAAA8AAAA8AgBAAL/////AAIFBG5hbWUGU3RyaW5nAAEA8BIF + dmFsdWUGVUludDMybZltXecjidDGXat5idKGXty+Sl8= +# Packet 16 +peer1_4: !!binary | + BjcCgKIBAWQB +# Packet 18 +peer1_5: !!binary | + A8gBrRgAAAA= +# Packet 20 +peer1_6: !!binary | + AQCng6xs1Vx6fLWsRr3bhuIUghQAAAAKAAAAoAEAAv////8AAAA= +# Packet 22 +peer1_7: !!binary | + AwAAAAAA +# Packet 24 +peer1_8: !!binary | + BQ== diff --git a/vertx-clickhouse-binary-client/src/test/resources/wrong_db_connection_without_compression.yaml b/vertx-clickhouse-binary-client/src/test/resources/wrong_db_connection_without_compression.yaml new file mode 100644 index 000000000..c64a50d7a --- /dev/null +++ b/vertx-clickhouse-binary-client/src/test/resources/wrong_db_connection_without_compression.yaml @@ -0,0 +1,34 @@ +# Packet 4 +peer0_0: !!binary | + AE1DbGlja0hvdXNlIENsaWNraG91c2VCaW5hcnlQcmVwYXJlZFF1ZXJ5Q2FjaGVkVGVzdC50ZXN0 + Q29ubmVjdEludmFsaWREYXRhYmFzZRQKqakDD2ludmFsaWREYXRhYmFzZQdkZWZhdWx0B2RlZmF1 + bHQ= +# Packet 6 +peer1_0: !!binary | + AApDbGlja0hvdXNlFQqxqQMNRXVyb3BlL01vc2NvdwZiaG9yc2UC +# Packet 8 +peer1_1: !!binary | + AlEAAAANREI6OkV4Y2VwdGlvbjVEQjo6RXhjZXB0aW9uOiBEYXRhYmFzZSBpbnZhbGlkRGF0YWJh + c2UgZG9lc24ndCBleGlzdOgJMC4gREI6OkV4Y2VwdGlvbjo6RXhjZXB0aW9uKHN0ZDo6X18xOjpi + YXNpY19zdHJpbmc8Y2hhciwgc3RkOjpfXzE6OmNoYXJfdHJhaXRzPGNoYXI+LCBzdGQ6Ol9fMTo6 + YWxsb2NhdG9yPGNoYXI+ID4gY29uc3QmLCBpbnQsIGJvb2wpIEAgMHg5NDRiZGRhIGluIC91c3Iv + YmluL2NsaWNraG91c2UKMS4gREI6OkRhdGFiYXNlQ2F0YWxvZzo6YXNzZXJ0RGF0YWJhc2VFeGlz + dHNVbmxvY2tlZChzdGQ6Ol9fMTo6YmFzaWNfc3RyaW5nPGNoYXIsIHN0ZDo6X18xOjpjaGFyX3Ry + YWl0czxjaGFyPiwgc3RkOjpfXzE6OmFsbG9jYXRvcjxjaGFyPiA+IGNvbnN0JikgY29uc3QgQCAw + eDEwOGM1NjdjIGluIC91c3IvYmluL2NsaWNraG91c2UKMi4gREI6OkRhdGFiYXNlQ2F0YWxvZzo6 + YXNzZXJ0RGF0YWJhc2VFeGlzdHMoc3RkOjpfXzE6OmJhc2ljX3N0cmluZzxjaGFyLCBzdGQ6Ol9f + MTo6Y2hhcl90cmFpdHM8Y2hhcj4sIHN0ZDo6X18xOjphbGxvY2F0b3I8Y2hhcj4gPiBjb25zdCYp + IGNvbnN0IEAgMHgxMDhjNTUwMiBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjMuIERCOjpDb250ZXh0 + OjpzZXRDdXJyZW50RGF0YWJhc2Uoc3RkOjpfXzE6OmJhc2ljX3N0cmluZzxjaGFyLCBzdGQ6Ol9f + MTo6Y2hhcl90cmFpdHM8Y2hhcj4sIHN0ZDo6X18xOjphbGxvY2F0b3I8Y2hhcj4gPiBjb25zdCYp + IEAgMHgxMDg0ZjZlMSBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjQuIERCOjpUQ1BIYW5kbGVyOjpy + dW5JbXBsKCkgQCAweDExOTYwNTkxIGluIC91c3IvYmluL2NsaWNraG91c2UKNS4gREI6OlRDUEhh + bmRsZXI6OnJ1bigpIEAgMHgxMTk3MWIxOSBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjYuIFBvY286 + Ok5ldDo6VENQU2VydmVyQ29ubmVjdGlvbjo6c3RhcnQoKSBAIDB4MTQ1M2JmMmYgaW4gL3Vzci9i + aW4vY2xpY2tob3VzZQo3LiBQb2NvOjpOZXQ6OlRDUFNlcnZlckRpc3BhdGNoZXI6OnJ1bigpIEAg + MHgxNDUzZDliYSBpbiAvdXNyL2Jpbi9jbGlja2hvdXNlCjguIFBvY286OlBvb2xlZFRocmVhZDo6 + cnVuKCkgQCAweDE0NjZmZGY5IGluIC91c3IvYmluL2NsaWNraG91c2UKOS4gUG9jbzo6VGhyZWFk + SW1wbDo6cnVubmFibGVFbnRyeSh2b2lkKikgQCAweDE0NjZjMDhhIGluIC91c3IvYmluL2NsaWNr + aG91c2UKMTAuIHN0YXJ0X3RocmVhZCBAIDB4OGVhZSBpbiAvbGliL3g4Nl82NC1saW51eC1nbnUv + bGlicHRocmVhZC0yLjMyLnNvCjExLiBjbG9uZSBAIDB4ZmRhNWYgaW4gL2xpYi94ODZfNjQtbGlu + dXgtZ251L2xpYmMtMi4zMi5zbwoA diff --git a/vertx-sql-client/src/test/java/io/vertx/sqlclient/ColumnChecker.java b/vertx-sql-client/src/test/java/io/vertx/sqlclient/ColumnChecker.java index c96e35465..8ca7aa27a 100644 --- a/vertx-sql-client/src/test/java/io/vertx/sqlclient/ColumnChecker.java +++ b/vertx-sql-client/src/test/java/io/vertx/sqlclient/ColumnChecker.java @@ -98,12 +98,13 @@ public ColumnChecker returns(SerializableBiFunction byInd blackList.add(byIndexMeth); Method byNameMeth = byNameGetter.method(); blackList.add(byNameMeth); + String nameIndex = name + "/" + index; expects.add(row -> { Object actual = byIndexGetter.apply(row, index); try { check.accept((R) actual); } catch (AssertionError cause) { - AssertionFailedError failure = new AssertionFailedError("Expected that " + byIndexMeth + " would not fail: " + cause.getMessage()); + AssertionFailedError failure = new AssertionFailedError("Expected that " + byIndexMeth + " would not fail for " + nameIndex + ": " + cause.getMessage()); failure.setStackTrace(failure.getStackTrace()); throw failure; } @@ -111,7 +112,7 @@ public ColumnChecker returns(SerializableBiFunction byInd try { check.accept((R) actual); } catch (AssertionError cause) { - AssertionFailedError failure = new AssertionFailedError("Expected that " + byNameMeth + " would not fail: " + cause.getMessage()); + AssertionFailedError failure = new AssertionFailedError("Expected that " + byNameMeth + " would not fail for " + nameIndex + ": " + cause.getMessage()); failure.setStackTrace(failure.getStackTrace()); throw failure; } diff --git a/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/BinaryDataTypeDecodeTestBase.java b/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/BinaryDataTypeDecodeTestBase.java index 362962cf1..504ff3250 100644 --- a/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/BinaryDataTypeDecodeTestBase.java +++ b/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/BinaryDataTypeDecodeTestBase.java @@ -178,8 +178,8 @@ public void testSelectAll(TestContext ctx) { ctx.assertEquals(LocalTime.parse("18:45:02"), row.getValue("test_time")); conn.close(); })); - })); - } + })); + } @Test public void testToJsonObject(TestContext ctx) { diff --git a/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/BinaryDataTypeEncodeTestBase.java b/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/BinaryDataTypeEncodeTestBase.java index 13b770086..b3fa2249e 100644 --- a/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/BinaryDataTypeEncodeTestBase.java +++ b/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/BinaryDataTypeEncodeTestBase.java @@ -131,6 +131,13 @@ public void testNullValues(TestContext ctx) { })); } + protected void maybeSleep() { + } + + protected String encodeGenericUpdateStatement(String columnName, int id) { + return statement("UPDATE basicdatatype SET " + columnName + " = ", " WHERE id = " + id); + } + protected void testEncodeGeneric(TestContext ctx, String columnName, Class clazz, @@ -138,8 +145,9 @@ protected void testEncodeGeneric(TestContext ctx, T expected) { connector.connect(ctx.asyncAssertSuccess(conn -> { conn - .preparedQuery(statement("UPDATE basicdatatype SET " + columnName + " = ", " WHERE id = 2")) + .preparedQuery(encodeGenericUpdateStatement(columnName, 2)) .execute(Tuple.tuple().addValue(expected), ctx.asyncAssertSuccess(updateResult -> { + maybeSleep(); conn .preparedQuery("SELECT " + columnName + " FROM basicdatatype WHERE id = 2") .execute(ctx.asyncAssertSuccess(result -> { diff --git a/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/PreparedBatchTestBase.java b/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/PreparedBatchTestBase.java index 6c59da8cd..4aaca3fc3 100644 --- a/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/PreparedBatchTestBase.java +++ b/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/PreparedBatchTestBase.java @@ -52,6 +52,13 @@ public void tearDown(TestContext ctx) { vertx.close(ctx.asyncAssertSuccess()); } + protected void maybeSleep() { + } + + protected int expectedInsertBatchSize(List batch) { + return 1; + } + @Test public void testInsert(TestContext ctx) { connector.connect(ctx.asyncAssertSuccess(conn -> { @@ -62,7 +69,8 @@ public void testInsert(TestContext ctx) { batch.add(Tuple.wrap(Arrays.asList(79994, "batch four"))); conn.preparedQuery(statement("INSERT INTO mutable (id, val) VALUES (", ", ", ")")).executeBatch(batch, ctx.asyncAssertSuccess(result -> { - ctx.assertEquals(1, result.rowCount()); + maybeSleep(); + ctx.assertEquals(expectedInsertBatchSize(batch), result.rowCount()); conn.preparedQuery(statement("SELECT * FROM mutable WHERE id=", "")).executeBatch(Collections.singletonList(Tuple.of(79991)), ctx.asyncAssertSuccess(ar1 -> { ctx.assertEquals(1, ar1.size()); Row one = ar1.iterator().next(); diff --git a/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/SimpleQueryTestBase.java b/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/SimpleQueryTestBase.java index b871bb23d..a98419d65 100644 --- a/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/SimpleQueryTestBase.java +++ b/vertx-sql-client/src/test/java/io/vertx/sqlclient/tck/SimpleQueryTestBase.java @@ -72,7 +72,7 @@ public void tearDown(TestContext ctx) { public void testQuery(TestContext ctx) { connect(ctx.asyncAssertSuccess(conn -> { conn - .query("SELECT id, message from immutable") + .query("SELECT id, message FROM immutable ORDER BY id") .execute(ctx.asyncAssertSuccess(result -> { //TODO we need to figure how to handle PgResult#rowCount() method in common API, // MySQL returns affected rows as 0 for SELECT query but Postgres returns queried amount