filteredFunctions = new HashSet<>();
+ sut.filterByFunctionNamePattern(StringUtils.EMPTY, ksTestMetadata,
+ (signature, functionMetadata) -> filteredFunctions.add(signature.getName().asInternal()));
+ log.info("Functions matching '': {}", filteredFunctions);
+ assertThat(filteredFunctions, empty());
+
+ filteredFunctions.clear();
+ sut.filterByFunctionNamePattern(null, ksTestMetadata,
+ (signature, functionMetadata) -> filteredFunctions.add(signature.getName().asInternal()));
+ log.info("Functions matching null: {}", filteredFunctions);
+ assertThat(filteredFunctions, hasSize(4));
+ assertThat(filteredFunctions, hasItems("func1", "func2", "another_function", "another_test"));
+
+ filteredFunctions.clear();
+ sut.filterByFunctionNamePattern("func", ksTestMetadata,
+ (signature, functionMetadata) -> filteredFunctions.add(signature.getName().asInternal()));
+ log.info("Functions matching 'func': {}", filteredFunctions);
+ assertThat(filteredFunctions, empty());
+
+ filteredFunctions.clear();
+ sut.filterByFunctionNamePattern("func%", ksTestMetadata,
+ (signature, functionMetadata) -> filteredFunctions.add(signature.getName().asInternal()));
+ log.info("Functions matching 'func%': {}", filteredFunctions);
+ assertThat(filteredFunctions, hasSize(2));
+ assertThat(filteredFunctions, hasItems("func1", "func2"));
+
+ filteredFunctions.clear();
+ sut.filterByFunctionNamePattern("%func%", ksTestMetadata,
+ (signature, functionMetadata) -> filteredFunctions.add(signature.getName().asInternal()));
+ log.info("Functions matching '%func%': {}", filteredFunctions);
+ assertThat(filteredFunctions, hasSize(3));
+ assertThat(filteredFunctions, hasItems("func1", "func2", "another_function"));
+ }
}
From 59d3e7b2dbdcd4467e5c12e482e7adebbac1f6af Mon Sep 17 00:00:00 2001
From: Maxime Wiewiora <48218208+maximevw@users.noreply.github.com>
Date: Sun, 17 Sep 2023 20:23:39 +0200
Subject: [PATCH 15/21] Refactor utility classes
Split Utils class into several specific classes and add Javadoc
on public constants.
---
.../cassandra/jdbc/AbstractConnection.java | 4 +-
.../cassandra/jdbc/AbstractResultSet.java | 4 +-
.../cassandra/jdbc/AbstractStatement.java | 4 +-
.../cassandra/jdbc/CassandraConnection.java | 28 +-
.../cassandra/jdbc/CassandraDataSource.java | 33 +-
.../jdbc/CassandraDatabaseMetaData.java | 8 +-
.../data/cassandra/jdbc/CassandraDriver.java | 12 +-
.../jdbc/CassandraMetadataResultSet.java | 22 +-
.../jdbc/CassandraParameterMetaData.java | 2 +-
.../jdbc/CassandraPreparedStatement.java | 8 +-
.../cassandra/jdbc/CassandraResultSet.java | 26 +-
.../cassandra/jdbc/CassandraStatement.java | 39 +-
.../cassandra/jdbc/ManagedConnection.java | 7 +-
.../jdbc/ManagedPreparedStatement.java | 2 +-
.../jdbc/PooledCassandraDataSource.java | 2 +-
.../data/cassandra/jdbc/SessionHolder.java | 97 +++--
.../cassandra/jdbc/codec/AbstractCodec.java | 2 +-
.../cassandra/jdbc/types/JdbcDecimal.java | 2 +-
.../data/cassandra/jdbc/utils/DriverUtil.java | 114 ++++++
.../cassandra/jdbc/utils/ErrorConstants.java | 230 ++++++++++++
.../utils/{Utils.java => JdbcUrlUtil.java} | 347 +++++++++---------
.../data/cassandra/jdbc/utils/JsonUtil.java | 70 ++++
.../cassandra/jdbc/ConnectionUnitTest.java | 13 +-
.../cassandra/jdbc/DataSourceUnitTest.java | 4 +-
.../data/cassandra/jdbc/UtilsUnitTest.java | 164 +++++----
.../codec/BigintToBigDecimalCodecTest.java | 2 +-
.../jdbc/codec/DecimalToDoubleCodecTest.java | 2 +-
.../jdbc/codec/FloatToDoubleCodecTest.java | 2 +-
.../jdbc/codec/IntToLongCodecTest.java | 2 +-
.../jdbc/codec/LongToIntCodecTest.java | 2 +-
.../jdbc/codec/SmallintToIntCodecTest.java | 2 +-
.../jdbc/codec/TimestampToLongCodecTest.java | 2 +-
.../jdbc/codec/TinyintToIntCodecTest.java | 2 +-
.../jdbc/codec/VarintToIntCodecTest.java | 2 +-
34 files changed, 865 insertions(+), 397 deletions(-)
create mode 100644 src/main/java/com/ing/data/cassandra/jdbc/utils/DriverUtil.java
create mode 100644 src/main/java/com/ing/data/cassandra/jdbc/utils/ErrorConstants.java
rename src/main/java/com/ing/data/cassandra/jdbc/utils/{Utils.java => JdbcUrlUtil.java} (70%)
create mode 100644 src/main/java/com/ing/data/cassandra/jdbc/utils/JsonUtil.java
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/AbstractConnection.java b/src/main/java/com/ing/data/cassandra/jdbc/AbstractConnection.java
index b8c81a6..2222b26 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/AbstractConnection.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/AbstractConnection.java
@@ -30,8 +30,8 @@
import java.util.Map;
import java.util.concurrent.Executor;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_INTERFACE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_INTERFACE;
/**
* Provides a default implementation (returning a {@link SQLFeatureNotSupportedException}) to hold the unimplemented
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/AbstractResultSet.java b/src/main/java/com/ing/data/cassandra/jdbc/AbstractResultSet.java
index f58428d..6ec1be9 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/AbstractResultSet.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/AbstractResultSet.java
@@ -38,8 +38,8 @@
import java.sql.Wrapper;
import java.util.Map;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_INTERFACE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_INTERFACE;
/**
* Provides a default implementation (returning a {@link SQLFeatureNotSupportedException}) to hold the unimplemented
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/AbstractStatement.java b/src/main/java/com/ing/data/cassandra/jdbc/AbstractStatement.java
index f847b4c..eeed400 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/AbstractStatement.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/AbstractStatement.java
@@ -27,8 +27,8 @@
import java.sql.SQLXML;
import java.sql.Wrapper;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_INTERFACE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_INTERFACE;
/**
* Provides a default implementation (returning a {@link SQLFeatureNotSupportedException}) to hold the unimplemented
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java
index a399c1b..de077a5 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java
@@ -66,20 +66,20 @@
import static com.ing.data.cassandra.jdbc.CassandraResultSet.DEFAULT_CONCURRENCY;
import static com.ing.data.cassandra.jdbc.CassandraResultSet.DEFAULT_HOLDABILITY;
import static com.ing.data.cassandra.jdbc.CassandraResultSet.DEFAULT_TYPE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.ALWAYS_AUTOCOMMIT;
-import static com.ing.data.cassandra.jdbc.utils.Utils.BAD_TIMEOUT;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_TRANSACTIONS;
-import static com.ing.data.cassandra.jdbc.utils.Utils.PROTOCOL;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_ACTIVE_CQL_VERSION;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_COMPLIANCE_MODE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_CONSISTENCY_LEVEL;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_CQL_VERSION;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_DATABASE_NAME;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_DEBUG;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_USER;
-import static com.ing.data.cassandra.jdbc.utils.Utils.WAS_CLOSED_CONN;
-import static com.ing.data.cassandra.jdbc.utils.Utils.createSubName;
-import static com.ing.data.cassandra.jdbc.utils.Utils.getDriverProperty;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.getDriverProperty;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.ALWAYS_AUTOCOMMIT;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_TIMEOUT;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_TRANSACTIONS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.WAS_CLOSED_CONN;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.PROTOCOL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_ACTIVE_CQL_VERSION;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_COMPLIANCE_MODE;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CONSISTENCY_LEVEL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CQL_VERSION;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_DATABASE_NAME;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_DEBUG;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_USER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.createSubName;
/**
* Cassandra connection: implementation class for {@link Connection} to create a JDBC connection to a Cassandra
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDataSource.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDataSource.java
index 3cad7e2..f665cf1 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDataSource.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDataSource.java
@@ -17,7 +17,7 @@
import com.datastax.oss.driver.api.core.ConsistencyLevel;
import com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy;
-import com.ing.data.cassandra.jdbc.utils.Utils;
+import com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
@@ -29,19 +29,20 @@
import java.util.Properties;
import java.util.logging.Logger;
-import static com.ing.data.cassandra.jdbc.utils.Utils.HOST_REQUIRED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_INTERFACE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.PROTOCOL;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_CONSISTENCY_LEVEL;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_CQL_VERSION;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_DATABASE_NAME;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_LOCAL_DATACENTER;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_PASSWORD;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_PORT_NUMBER;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_SERVER_NAME;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_USER;
-import static com.ing.data.cassandra.jdbc.utils.Utils.createSubName;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.HOST_REQUIRED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_INTERFACE;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.DEFAULT_PORT;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.PROTOCOL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CONSISTENCY_LEVEL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CQL_VERSION;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_DATABASE_NAME;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_LOCAL_DATACENTER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_PASSWORD;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_PORT_NUMBER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_SERVER_NAME;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_USER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.createSubName;
/**
* Cassandra data source: implementation class for {@link DataSource} and {@link ConnectionPoolDataSource}.
@@ -66,9 +67,9 @@ public class CassandraDataSource implements ConnectionPoolDataSource, DataSource
*/
protected String serverName;
/**
- * The port number of the data source, by default {@value Utils#DEFAULT_PORT}.
+ * The port number of the data source, by default {@value JdbcUrlUtil#DEFAULT_PORT}.
*/
- protected int portNumber = Utils.DEFAULT_PORT;
+ protected int portNumber = DEFAULT_PORT;
/**
* The database name. In case of Cassandra, i.e. the keyspace used as data source.
*/
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
index 28533ae..ca33de8 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
@@ -35,10 +35,10 @@
import java.util.Arrays;
import java.util.List;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_INTERFACE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.getDriverProperty;
-import static com.ing.data.cassandra.jdbc.utils.Utils.parseVersion;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.getDriverProperty;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.parseVersion;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_INTERFACE;
/**
* Cassandra database metadata: implementation class for {@link DatabaseMetaData}.
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDriver.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDriver.java
index 9a3319e..68ac9ae 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDriver.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDriver.java
@@ -32,12 +32,12 @@
import java.util.Map;
import java.util.Properties;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.PROTOCOL;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_PASSWORD;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_USER;
-import static com.ing.data.cassandra.jdbc.utils.Utils.getDriverProperty;
-import static com.ing.data.cassandra.jdbc.utils.Utils.parseVersion;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.getDriverProperty;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.parseVersion;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.PROTOCOL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_PASSWORD;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_USER;
/**
* The Cassandra driver implementation.
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraMetadataResultSet.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraMetadataResultSet.java
index 6046953..564288c 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraMetadataResultSet.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraMetadataResultSet.java
@@ -26,7 +26,6 @@
import com.ing.data.cassandra.jdbc.types.AbstractJdbcType;
import com.ing.data.cassandra.jdbc.types.DataTypeEnum;
import com.ing.data.cassandra.jdbc.types.TypesMap;
-import com.ing.data.cassandra.jdbc.utils.Utils;
import org.apache.commons.lang3.StringUtils;
import java.io.ByteArrayInputStream;
@@ -64,14 +63,15 @@
import static com.ing.data.cassandra.jdbc.types.AbstractJdbcType.DEFAULT_PRECISION;
import static com.ing.data.cassandra.jdbc.types.AbstractJdbcType.DEFAULT_SCALE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.BAD_FETCH_DIR;
-import static com.ing.data.cassandra.jdbc.utils.Utils.BAD_FETCH_SIZE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.FORWARD_ONLY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.MUST_BE_POSITIVE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_INTERFACE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.VALID_LABELS;
-import static com.ing.data.cassandra.jdbc.utils.Utils.WAS_CLOSED_RS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_FETCH_DIR;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_FETCH_SIZE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.FORWARD_ONLY;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.MALFORMED_URL;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.MUST_BE_POSITIVE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_INTERFACE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.VALID_LABELS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.WAS_CLOSED_RS;
/**
* Cassandra metadata result set. This is an implementation of {@link ResultSet} for database metadata.
@@ -937,7 +937,7 @@ public URL getURL(final int columnIndex) throws SQLException {
try {
return new URL(storedUrl);
} catch (final MalformedURLException e) {
- throw new SQLException(String.format(Utils.MALFORMED_URL, storedUrl), e);
+ throw new SQLException(String.format(MALFORMED_URL, storedUrl), e);
}
}
}
@@ -953,7 +953,7 @@ public URL getURL(final String columnLabel) throws SQLException {
try {
return new URL(storedUrl);
} catch (final MalformedURLException e) {
- throw new SQLException(String.format(Utils.MALFORMED_URL, storedUrl), e);
+ throw new SQLException(String.format(MALFORMED_URL, storedUrl), e);
}
}
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraParameterMetaData.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraParameterMetaData.java
index 518ddf2..6748c56 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraParameterMetaData.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraParameterMetaData.java
@@ -23,7 +23,7 @@
import java.sql.ParameterMetaData;
import java.sql.SQLException;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_INTERFACE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_INTERFACE;
/**
* Cassandra parameter metadata: implementation class for {@link ParameterMetaData}.
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraPreparedStatement.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraPreparedStatement.java
index 25cc72b..3f189f7 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraPreparedStatement.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraPreparedStatement.java
@@ -29,7 +29,6 @@
import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ing.data.cassandra.jdbc.types.DataTypeEnum;
-import com.ing.data.cassandra.jdbc.utils.Utils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -69,8 +68,9 @@
import java.util.UUID;
import java.util.concurrent.CompletionStage;
-import static com.ing.data.cassandra.jdbc.utils.Utils.VECTOR_ELEMENTS_NOT_NUMBERS;
-import static com.ing.data.cassandra.jdbc.utils.Utils.getObjectMapper;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_RESULT_SET;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.VECTOR_ELEMENTS_NOT_NUMBERS;
+import static com.ing.data.cassandra.jdbc.utils.JsonUtil.getObjectMapper;
/**
* Cassandra prepared statement: implementation class for {@link PreparedStatement}.
@@ -289,7 +289,7 @@ public ResultSet executeQuery() throws SQLException {
checkNotClosed();
doExecute();
if (this.currentResultSet == null) {
- throw new SQLNonTransientException(Utils.NO_RESULT_SET);
+ throw new SQLNonTransientException(NO_RESULT_SET);
}
return this.currentResultSet;
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSet.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSet.java
index 1da6e33..cff14e6 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSet.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSet.java
@@ -34,7 +34,6 @@
import com.ing.data.cassandra.jdbc.types.AbstractJdbcType;
import com.ing.data.cassandra.jdbc.types.DataTypeEnum;
import com.ing.data.cassandra.jdbc.types.TypesMap;
-import com.ing.data.cassandra.jdbc.utils.Utils;
import org.apache.commons.collections4.IteratorUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -88,16 +87,17 @@
import static com.ing.data.cassandra.jdbc.types.AbstractJdbcType.DEFAULT_SCALE;
import static com.ing.data.cassandra.jdbc.types.DataTypeEnum.fromCqlTypeName;
import static com.ing.data.cassandra.jdbc.types.DataTypeEnum.fromDataType;
-import static com.ing.data.cassandra.jdbc.utils.Utils.BAD_FETCH_DIR;
-import static com.ing.data.cassandra.jdbc.utils.Utils.BAD_FETCH_SIZE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.FORWARD_ONLY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.MUST_BE_POSITIVE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NO_INTERFACE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.VALID_LABELS;
-import static com.ing.data.cassandra.jdbc.utils.Utils.VECTOR_ELEMENTS_NOT_NUMBERS;
-import static com.ing.data.cassandra.jdbc.utils.Utils.WAS_CLOSED_RS;
-import static com.ing.data.cassandra.jdbc.utils.Utils.getObjectMapper;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_FETCH_DIR;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_FETCH_SIZE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.FORWARD_ONLY;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.MALFORMED_URL;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.MUST_BE_POSITIVE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_INTERFACE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.VALID_LABELS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.VECTOR_ELEMENTS_NOT_NUMBERS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.WAS_CLOSED_RS;
+import static com.ing.data.cassandra.jdbc.utils.JsonUtil.getObjectMapper;
/**
* Cassandra result set: implementation class for {@link java.sql.ResultSet}.
@@ -1337,7 +1337,7 @@ public URL getURL(final int columnIndex) throws SQLException {
try {
return new URL(storedUrl);
} catch (final MalformedURLException e) {
- throw new SQLException(String.format(Utils.MALFORMED_URL, storedUrl), e);
+ throw new SQLException(String.format(MALFORMED_URL, storedUrl), e);
}
}
}
@@ -1353,7 +1353,7 @@ public URL getURL(final String columnLabel) throws SQLException {
try {
return new URL(storedUrl);
} catch (final MalformedURLException e) {
- throw new SQLException(String.format(Utils.MALFORMED_URL, storedUrl), e);
+ throw new SQLException(String.format(MALFORMED_URL, storedUrl), e);
}
}
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java
index 236097c..3c8276a 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java
@@ -24,7 +24,6 @@
import com.datastax.oss.driver.internal.core.cql.MultiPageResultSet;
import com.datastax.oss.driver.internal.core.cql.SinglePageResultSet;
import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures;
-import com.ing.data.cassandra.jdbc.utils.Utils;
import edu.umd.cs.findbugs.annotations.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
@@ -49,6 +48,18 @@
import java.util.Objects;
import java.util.concurrent.CompletionStage;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_AUTO_GEN;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_CONCURRENCY_RS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_FETCH_DIR;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_FETCH_SIZE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_HOLD_RS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_KEEP_RS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_TYPE_RS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_GEN_KEYS;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_MULTIPLE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NO_RESULT_SET;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.WAS_CLOSED_STMT;
+
/**
* Cassandra statement: implementation class for {@link Statement}.
*
@@ -216,19 +227,19 @@ public class CassandraStatement extends AbstractStatement
if (!(resultSetType == ResultSet.TYPE_FORWARD_ONLY
|| resultSetType == ResultSet.TYPE_SCROLL_INSENSITIVE
|| resultSetType == ResultSet.TYPE_SCROLL_SENSITIVE)) {
- throw new SQLSyntaxErrorException(String.format(Utils.BAD_TYPE_RS, resultSetType));
+ throw new SQLSyntaxErrorException(String.format(BAD_TYPE_RS, resultSetType));
}
this.resultSetType = resultSetType;
if (!(resultSetConcurrency == ResultSet.CONCUR_READ_ONLY
|| resultSetConcurrency == ResultSet.CONCUR_UPDATABLE)) {
- throw new SQLSyntaxErrorException(String.format(Utils.BAD_CONCURRENCY_RS, resultSetConcurrency));
+ throw new SQLSyntaxErrorException(String.format(BAD_CONCURRENCY_RS, resultSetConcurrency));
}
this.resultSetConcurrency = resultSetConcurrency;
if (!(resultSetHoldability == ResultSet.HOLD_CURSORS_OVER_COMMIT
|| resultSetHoldability == ResultSet.CLOSE_CURSORS_AT_COMMIT)) {
- throw new SQLSyntaxErrorException(String.format(Utils.BAD_HOLD_RS, resultSetHoldability));
+ throw new SQLSyntaxErrorException(String.format(BAD_HOLD_RS, resultSetHoldability));
}
this.resultSetHoldability = resultSetHoldability;
}
@@ -247,7 +258,7 @@ public void addBatch(final String query) throws SQLException {
*/
protected final void checkNotClosed() throws SQLException {
if (isClosed()) {
- throw new SQLRecoverableException(Utils.WAS_CLOSED_STMT);
+ throw new SQLRecoverableException(WAS_CLOSED_STMT);
}
}
@@ -383,10 +394,10 @@ public boolean execute(final String query) throws SQLException {
public boolean execute(final String cql, final int autoGeneratedKeys) throws SQLException {
checkNotClosed();
if (!(autoGeneratedKeys == RETURN_GENERATED_KEYS || autoGeneratedKeys == NO_GENERATED_KEYS)) {
- throw new SQLSyntaxErrorException(Utils.BAD_AUTO_GEN);
+ throw new SQLSyntaxErrorException(String.format(BAD_AUTO_GEN, autoGeneratedKeys));
}
if (autoGeneratedKeys == RETURN_GENERATED_KEYS) {
- throw new SQLFeatureNotSupportedException(Utils.NO_GEN_KEYS);
+ throw new SQLFeatureNotSupportedException(NO_GEN_KEYS);
}
return execute(cql);
}
@@ -428,7 +439,7 @@ public ResultSet executeQuery(final String cql) throws SQLException {
checkNotClosed();
doExecute(cql);
if (this.currentResultSet == null) {
- throw new SQLNonTransientException(Utils.NO_RESULT_SET);
+ throw new SQLNonTransientException(NO_RESULT_SET);
}
return currentResultSet;
}
@@ -456,7 +467,7 @@ public int executeUpdate(final String cql) throws SQLException {
public int executeUpdate(final String cql, final int autoGeneratedKeys) throws SQLException {
checkNotClosed();
if (!(autoGeneratedKeys == RETURN_GENERATED_KEYS || autoGeneratedKeys == NO_GENERATED_KEYS)) {
- throw new SQLFeatureNotSupportedException(Utils.BAD_AUTO_GEN);
+ throw new SQLFeatureNotSupportedException(String.format(BAD_AUTO_GEN, autoGeneratedKeys));
}
return executeUpdate(cql);
}
@@ -500,11 +511,11 @@ public void setFetchDirection(final int direction) throws SQLException {
if (direction == ResultSet.FETCH_FORWARD || direction == ResultSet.FETCH_REVERSE
|| direction == ResultSet.FETCH_UNKNOWN) {
if (getResultSetType() == ResultSet.TYPE_FORWARD_ONLY && direction != ResultSet.FETCH_FORWARD) {
- throw new SQLSyntaxErrorException(String.format(Utils.BAD_FETCH_DIR, direction));
+ throw new SQLSyntaxErrorException(String.format(BAD_FETCH_DIR, direction));
}
this.fetchDirection = direction;
} else {
- throw new SQLSyntaxErrorException(String.format(Utils.BAD_FETCH_DIR, direction));
+ throw new SQLSyntaxErrorException(String.format(BAD_FETCH_DIR, direction));
}
}
@@ -518,7 +529,7 @@ public int getFetchSize() throws SQLException {
public void setFetchSize(final int rows) throws SQLException {
checkNotClosed();
if (rows < 0) {
- throw new SQLSyntaxErrorException(String.format(Utils.BAD_FETCH_SIZE, rows));
+ throw new SQLSyntaxErrorException(String.format(BAD_FETCH_SIZE, rows));
}
this.fetchSize = rows;
}
@@ -584,9 +595,9 @@ public boolean getMoreResults(final int current) throws SQLException {
break;
case CLOSE_ALL_RESULTS:
case KEEP_CURRENT_RESULT:
- throw new SQLFeatureNotSupportedException(Utils.NO_MULTIPLE);
+ throw new SQLFeatureNotSupportedException(NO_MULTIPLE);
default:
- throw new SQLSyntaxErrorException(String.format(Utils.BAD_KEEP_RS, current));
+ throw new SQLSyntaxErrorException(String.format(BAD_KEEP_RS, current));
}
// In the current Cassandra implementation there are never more results.
return false;
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/ManagedConnection.java b/src/main/java/com/ing/data/cassandra/jdbc/ManagedConnection.java
index 3e7f852..2cb9f74 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/ManagedConnection.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/ManagedConnection.java
@@ -15,8 +15,6 @@
package com.ing.data.cassandra.jdbc;
-import com.ing.data.cassandra.jdbc.utils.Utils;
-
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement;
@@ -31,7 +29,8 @@
import java.util.Properties;
import java.util.Set;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.WAS_CLOSED_CONN;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
/**
* Cassandra connection from a pool managed by a {@link PooledCassandraDataSource}.
@@ -54,7 +53,7 @@ class ManagedConnection extends AbstractConnection implements Connection {
private void checkNotClosed() throws SQLNonTransientConnectionException {
if (isClosed()) {
- throw new SQLNonTransientConnectionException(Utils.WAS_CLOSED_CONN);
+ throw new SQLNonTransientConnectionException(WAS_CLOSED_CONN);
}
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/ManagedPreparedStatement.java b/src/main/java/com/ing/data/cassandra/jdbc/ManagedPreparedStatement.java
index 9ae58ee..1f429e8 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/ManagedPreparedStatement.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/ManagedPreparedStatement.java
@@ -37,7 +37,7 @@
import java.sql.Timestamp;
import java.util.Calendar;
-import static com.ing.data.cassandra.jdbc.utils.Utils.WAS_CLOSED_CONN;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.WAS_CLOSED_CONN;
/**
* Cassandra prepared statement executed in the context of a pool of connections managed in a
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/PooledCassandraDataSource.java b/src/main/java/com/ing/data/cassandra/jdbc/PooledCassandraDataSource.java
index ab8bf2f..575fb52 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/PooledCassandraDataSource.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/PooledCassandraDataSource.java
@@ -29,7 +29,7 @@
import java.util.HashSet;
import java.util.Set;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NOT_SUPPORTED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.NOT_SUPPORTED;
/**
* Pooled Cassandra data source: implementation class for {@link DataSource} and {@link ConnectionEventListener}.
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/SessionHolder.java b/src/main/java/com/ing/data/cassandra/jdbc/SessionHolder.java
index 9fb04c9..dbe2e49 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/SessionHolder.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/SessionHolder.java
@@ -40,7 +40,6 @@
import com.ing.data.cassandra.jdbc.codec.TimestampToLongCodec;
import com.ing.data.cassandra.jdbc.codec.TinyintToIntCodec;
import com.ing.data.cassandra.jdbc.codec.VarintToIntCodec;
-import com.ing.data.cassandra.jdbc.utils.Utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
@@ -62,11 +61,33 @@
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
-import static com.ing.data.cassandra.jdbc.utils.Utils.JSSE_KEYSTORE_PASSWORD_PROPERTY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.JSSE_KEYSTORE_PROPERTY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.JSSE_TRUSTSTORE_PASSWORD_PROPERTY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.JSSE_TRUSTSTORE_PROPERTY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.SSL_CONFIG_FAILED;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.JSSE_KEYSTORE_PASSWORD_PROPERTY;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.JSSE_KEYSTORE_PROPERTY;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.JSSE_TRUSTSTORE_PASSWORD_PROPERTY;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.JSSE_TRUSTSTORE_PROPERTY;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.SSL_CONFIG_FAILED;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CLOUD_SECURE_CONNECT_BUNDLE;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CONFIG_FILE;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CONNECT_TIMEOUT;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CONSISTENCY_LEVEL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_DATABASE_NAME;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_DEBUG;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_ENABLE_SSL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_KEEP_ALIVE;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_LOAD_BALANCING_POLICY;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_LOCAL_DATACENTER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_PASSWORD;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_PORT_NUMBER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_RECONNECT_POLICY;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_REQUEST_TIMEOUT;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_RETRY_POLICY;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_SERVER_NAME;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_SSL_ENGINE_FACTORY;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_SSL_HOSTNAME_VERIFICATION;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_TCP_NO_DELAY;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_USER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.parseReconnectionPolicy;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.parseURL;
/**
* Holds a {@link Session} shared among multiple {@link CassandraConnection} objects.
@@ -102,7 +123,7 @@ class SessionHolder {
// Parse the URL into a set of Properties and replace double quote marks (") by simple quotes (') to handle the
// fact that double quotes (") are not valid characters in URIs.
- this.properties = Utils.parseURL(url.replace("\"", "'"));
+ this.properties = parseURL(url.replace("\"", "'"));
// Other properties in parameters come from the initial call to connect(), they take priority.
params.keySet().stream()
@@ -162,23 +183,23 @@ boolean acquire() {
private Session createSession(final Properties properties) throws SQLException {
File configurationFile = null;
- final String configurationFilePath = properties.getProperty(Utils.TAG_CONFIG_FILE, StringUtils.EMPTY);
+ final String configurationFilePath = properties.getProperty(TAG_CONFIG_FILE, StringUtils.EMPTY);
if (StringUtils.isNotBlank(configurationFilePath)) {
configurationFile = new File(configurationFilePath);
if (configurationFile.exists()) {
// We remove some parameters to use the values defined into the specified configuration file
// instead.
- this.properties.remove(Utils.TAG_CONSISTENCY_LEVEL);
- this.properties.remove(Utils.TAG_LOCAL_DATACENTER);
- this.properties.remove(Utils.TAG_USER);
- this.properties.remove(Utils.TAG_PASSWORD);
- this.properties.remove(Utils.TAG_ENABLE_SSL);
- this.properties.remove(Utils.TAG_SSL_ENGINE_FACTORY);
- this.properties.remove(Utils.TAG_SSL_HOSTNAME_VERIFICATION);
- this.properties.remove(Utils.TAG_REQUEST_TIMEOUT);
- this.properties.remove(Utils.TAG_CONNECT_TIMEOUT);
- this.properties.remove(Utils.TAG_KEEP_ALIVE);
- this.properties.remove(Utils.TAG_TCP_NO_DELAY);
+ this.properties.remove(TAG_CONSISTENCY_LEVEL);
+ this.properties.remove(TAG_LOCAL_DATACENTER);
+ this.properties.remove(TAG_USER);
+ this.properties.remove(TAG_PASSWORD);
+ this.properties.remove(TAG_ENABLE_SSL);
+ this.properties.remove(TAG_SSL_ENGINE_FACTORY);
+ this.properties.remove(TAG_SSL_HOSTNAME_VERIFICATION);
+ this.properties.remove(TAG_REQUEST_TIMEOUT);
+ this.properties.remove(TAG_CONNECT_TIMEOUT);
+ this.properties.remove(TAG_KEEP_ALIVE);
+ this.properties.remove(TAG_TCP_NO_DELAY);
LOG.info("The configuration file {} will be used and will override the parameters defined into the "
+ "JDBC URL except contact points and keyspace.", configurationFilePath);
} else {
@@ -186,27 +207,27 @@ private Session createSession(final Properties properties) throws SQLException {
}
}
- final String hosts = properties.getProperty(Utils.TAG_SERVER_NAME);
- final int port = Integer.parseInt(properties.getProperty(Utils.TAG_PORT_NUMBER));
- final String cloudSecureConnectBundle = properties.getProperty(Utils.TAG_CLOUD_SECURE_CONNECT_BUNDLE);
- final String keyspace = properties.getProperty(Utils.TAG_DATABASE_NAME);
- final String username = properties.getProperty(Utils.TAG_USER, StringUtils.EMPTY);
- final String password = properties.getProperty(Utils.TAG_PASSWORD, StringUtils.EMPTY);
- final String loadBalancingPolicy = properties.getProperty(Utils.TAG_LOAD_BALANCING_POLICY, StringUtils.EMPTY);
- final String localDatacenter = properties.getProperty(Utils.TAG_LOCAL_DATACENTER, StringUtils.EMPTY);
- final String retryPolicy = properties.getProperty(Utils.TAG_RETRY_POLICY, StringUtils.EMPTY);
- final String reconnectPolicy = properties.getProperty(Utils.TAG_RECONNECT_POLICY, StringUtils.EMPTY);
- final boolean debugMode = Boolean.TRUE.toString().equals(properties.getProperty(Utils.TAG_DEBUG,
+ final String hosts = properties.getProperty(TAG_SERVER_NAME);
+ final int port = Integer.parseInt(properties.getProperty(TAG_PORT_NUMBER));
+ final String cloudSecureConnectBundle = properties.getProperty(TAG_CLOUD_SECURE_CONNECT_BUNDLE);
+ final String keyspace = properties.getProperty(TAG_DATABASE_NAME);
+ final String username = properties.getProperty(TAG_USER, StringUtils.EMPTY);
+ final String password = properties.getProperty(TAG_PASSWORD, StringUtils.EMPTY);
+ final String loadBalancingPolicy = properties.getProperty(TAG_LOAD_BALANCING_POLICY, StringUtils.EMPTY);
+ final String localDatacenter = properties.getProperty(TAG_LOCAL_DATACENTER, StringUtils.EMPTY);
+ final String retryPolicy = properties.getProperty(TAG_RETRY_POLICY, StringUtils.EMPTY);
+ final String reconnectPolicy = properties.getProperty(TAG_RECONNECT_POLICY, StringUtils.EMPTY);
+ final boolean debugMode = Boolean.TRUE.toString().equals(properties.getProperty(TAG_DEBUG,
StringUtils.EMPTY));
- final String enableSslValue = properties.getProperty(Utils.TAG_ENABLE_SSL);
- final String sslEngineFactoryClassName = properties.getProperty(Utils.TAG_SSL_ENGINE_FACTORY,
+ final String enableSslValue = properties.getProperty(TAG_ENABLE_SSL);
+ final String sslEngineFactoryClassName = properties.getProperty(TAG_SSL_ENGINE_FACTORY,
StringUtils.EMPTY);
final boolean sslEnabled = Boolean.TRUE.toString().equals(enableSslValue)
|| (enableSslValue == null && StringUtils.isNotEmpty(sslEngineFactoryClassName));
- final String enableSslHostnameVerification = properties.getProperty(Utils.TAG_SSL_HOSTNAME_VERIFICATION);
+ final String enableSslHostnameVerification = properties.getProperty(TAG_SSL_HOSTNAME_VERIFICATION);
final boolean sslHostnameVerificationEnabled = Boolean.TRUE.toString().equals(enableSslHostnameVerification)
|| enableSslHostnameVerification == null;
- final String requestTimeoutRawValue = properties.getProperty(Utils.TAG_REQUEST_TIMEOUT);
+ final String requestTimeoutRawValue = properties.getProperty(TAG_REQUEST_TIMEOUT);
Integer requestTimeout = null;
if (NumberUtils.isParsable(requestTimeoutRawValue)) {
requestTimeout = Integer.parseInt(requestTimeoutRawValue);
@@ -277,7 +298,7 @@ private Session createSession(final Properties properties) throws SQLException {
// if reconnection policy has been given in the JDBC URL, parse it and add it to the cluster builder.
try {
final Map parsedPolicy = Optional.ofNullable(
- Utils.parseReconnectionPolicy(reconnectPolicy)).orElse(new HashMap<>());
+ parseReconnectionPolicy(reconnectPolicy)).orElse(new HashMap<>());
driverConfigLoaderBuilder.withString(DefaultDriverOption.RECONNECTION_POLICY_CLASS,
(String) parsedPolicy.get(DefaultDriverOption.RECONNECTION_POLICY_CLASS));
@@ -347,14 +368,14 @@ private Session createSession(final Properties properties) throws SQLException {
void configureSocketOptions(final ProgrammaticDriverConfigLoaderBuilder driverConfigLoaderBuilder,
final Properties properties) {
// Parse options received from JDBC URL
- final String connectTimeoutRawValue = properties.getProperty(Utils.TAG_CONNECT_TIMEOUT);
+ final String connectTimeoutRawValue = properties.getProperty(TAG_CONNECT_TIMEOUT);
Integer connectTimeout = null;
if (NumberUtils.isParsable(connectTimeoutRawValue)) {
connectTimeout = Integer.parseInt(connectTimeoutRawValue);
}
- final String enableTcpNoDelay = properties.getProperty(Utils.TAG_TCP_NO_DELAY);
+ final String enableTcpNoDelay = properties.getProperty(TAG_TCP_NO_DELAY);
final boolean tcpNoDelayEnabled = Boolean.TRUE.toString().equals(enableTcpNoDelay) || enableTcpNoDelay == null;
- final String enableTcpKeepAlive = properties.getProperty(Utils.TAG_KEEP_ALIVE);
+ final String enableTcpKeepAlive = properties.getProperty(TAG_KEEP_ALIVE);
final boolean tcpKeepAliveEnabled = Boolean.TRUE.toString().equals(enableTcpKeepAlive);
// Apply configuration
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/AbstractCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/AbstractCodec.java
index 229184c..dbab784 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/AbstractCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/AbstractCodec.java
@@ -19,7 +19,7 @@
import edu.umd.cs.findbugs.annotations.NonNull;
import org.apache.commons.lang3.StringUtils;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
/**
* Provides a minimal implementation for the methods {@link TypeCodec#parse(String)} and
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcDecimal.java b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcDecimal.java
index 4290355..22599fa 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcDecimal.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcDecimal.java
@@ -19,7 +19,7 @@
import java.nio.ByteBuffer;
import java.sql.Types;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
/**
* JDBC description of {@code DECIMAL} CQL type (corresponding Java type: {@link BigDecimal}).
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/utils/DriverUtil.java b/src/main/java/com/ing/data/cassandra/jdbc/utils/DriverUtil.java
new file mode 100644
index 0000000..1d5cfbb
--- /dev/null
+++ b/src/main/java/com/ing/data/cassandra/jdbc/utils/DriverUtil.java
@@ -0,0 +1,114 @@
+/*
+ *
+ * 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 com.ing.data.cassandra.jdbc.utils;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+/**
+ * A set of static utility methods and constants used by the JDBC driver.
+ */
+public final class DriverUtil {
+
+ /**
+ * Properties file name containing some properties relative to this JDBC wrapper (such as JDBC driver version,
+ * name, etc.).
+ */
+ public static final String JDBC_DRIVER_PROPERTIES_FILE = "jdbc-driver.properties";
+
+ /**
+ * The JSSE property used to retrieve the trust store when SSL is enabled on the database connection using
+ * JSSE properties.
+ */
+ public static final String JSSE_TRUSTSTORE_PROPERTY = "javax.net.ssl.trustStore";
+
+ /**
+ * The JSSE property used to retrieve the trust store password when SSL is enabled on the database connection using
+ * JSSE properties.
+ */
+ public static final String JSSE_TRUSTSTORE_PASSWORD_PROPERTY = "javax.net.ssl.trustStorePassword";
+
+ /**
+ * The JSSE property used to retrieve the key store when SSL is enabled on the database connection using
+ * JSSE properties.
+ */
+ public static final String JSSE_KEYSTORE_PROPERTY = "javax.net.ssl.keyStore";
+
+ /**
+ * The JSSE property used to retrieve the key store password when SSL is enabled on the database connection using
+ * JSSE properties.
+ */
+ public static final String JSSE_KEYSTORE_PASSWORD_PROPERTY = "javax.net.ssl.keyStorePassword";
+
+ /**
+ * {@code NULL} CQL keyword.
+ */
+ public static final String NULL_KEYWORD = "NULL";
+
+ static final Logger LOG = LoggerFactory.getLogger(DriverUtil.class);
+
+ private DriverUtil() {
+ // Private constructor to hide the public one.
+ }
+
+ /**
+ * Gets a property value from the Cassandra JDBC driver properties file.
+ *
+ * @param name The name of the property.
+ * @return The property value or an empty string the value cannot be retrieved.
+ */
+ public static String getDriverProperty(final String name) {
+ try (final InputStream propertiesFile =
+ DriverUtil.class.getClassLoader().getResourceAsStream(JDBC_DRIVER_PROPERTIES_FILE)) {
+ final Properties driverProperties = new Properties();
+ driverProperties.load(propertiesFile);
+ return driverProperties.getProperty(name, StringUtils.EMPTY);
+ } catch (IOException ex) {
+ LOG.error("Unable to get JDBC driver property: {}.", name, ex);
+ return StringUtils.EMPTY;
+ }
+ }
+
+ /**
+ * Gets a part of a version string.
+ *
+ * It uses the dot character as separator to parse the different parts of a version (major, minor, patch).
+ *
+ *
+ * @param version The version string (for example X.Y.Z).
+ * @param part The part of the version to extract (for the semantic versioning, use 0 for the major version, 1 for
+ * the minor and 2 for the patch).
+ * @return The requested part of the version, or 0 if the requested part cannot be parsed correctly.
+ */
+ public static int parseVersion(final String version, final int part) {
+ if (StringUtils.isBlank(version) || StringUtils.countMatches(version, ".") < part || part < 0) {
+ return 0;
+ } else {
+ try {
+ return Integer.parseInt(version.split("\\.")[part]);
+ } catch (final NumberFormatException ex) {
+ LOG.error("Unable to parse version: {}", version);
+ return 0;
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/utils/ErrorConstants.java b/src/main/java/com/ing/data/cassandra/jdbc/utils/ErrorConstants.java
new file mode 100644
index 0000000..084dab3
--- /dev/null
+++ b/src/main/java/com/ing/data/cassandra/jdbc/utils/ErrorConstants.java
@@ -0,0 +1,230 @@
+/*
+ *
+ * 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 com.ing.data.cassandra.jdbc.utils;
+
+import com.ing.data.cassandra.jdbc.CassandraResultSet;
+
+import java.net.URI;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.Statement;
+
+/**
+ * Error messages strings shared across the JDBC wrapper classes.
+ */
+public final class ErrorConstants {
+
+ /**
+ * Error message used in any SQL exception thrown when a method is called on a closed {@link Connection}.
+ */
+ public static final String WAS_CLOSED_CONN = "Method was called on a closed Connection.";
+
+ /**
+ * Error message used in any SQL exception thrown when a method is called on a closed {@link Statement}.
+ */
+ public static final String WAS_CLOSED_STMT = "Method was called on a closed Statement.";
+
+ /**
+ * Error message used in any SQL exception thrown when a method is called on a closed {@link ResultSet}.
+ */
+ public static final String WAS_CLOSED_RS = "Method was called on a closed ResultSet.";
+
+ /**
+ * Error message used in any SQL exception thrown when the method {@code unwrap(Class)} is called with a class
+ * not matching the expected interface. This message is a template expecting the name of the class parameter as
+ * placeholder (example: {@code String.format(NO_INTERFACE, iface.getSimpleName())}).
+ */
+ public static final String NO_INTERFACE = "No object was found that matched the provided interface: %s";
+
+ /**
+ * Error message used in any SQL exception thrown because the called method requires transactions (currently not
+ * implemented in Cassandra).
+ */
+ public static final String NO_TRANSACTIONS = "The Cassandra implementation does not support transactions.";
+
+ /**
+ * Error message used in any SQL exception thrown because the called method requires a non-committed transaction
+ * (but transactions are not currently implemented in Cassandra, so we consider we are always in auto-commit mode).
+ */
+ public static final String ALWAYS_AUTOCOMMIT = "The Cassandra implementation is always in auto-commit mode.";
+
+ /**
+ * Error message used in any SQL exception thrown because the provided timeout is invalid (less than 0).
+ */
+ public static final String BAD_TIMEOUT = "The timeout value was less than zero.";
+
+ /**
+ * Error message used in any SQL exception thrown because the called method requires a feature not currently
+ * supported by Cassandra.
+ */
+ public static final String NOT_SUPPORTED = "The Cassandra implementation does not support this method.";
+
+ /**
+ * Error message used in any SQL exception thrown because the called method requires auto-generated keys (currently
+ * not implemented in Cassandra).
+ */
+ public static final String NO_GEN_KEYS =
+ "The Cassandra implementation does not currently support returning generated keys.";
+
+ /**
+ * Error message used in any SQL exception thrown because the called method requires keeping multiple open result
+ * sets (currently not implemented in Cassandra).
+ */
+ public static final String NO_MULTIPLE =
+ "The Cassandra implementation does not currently support multiple open result sets.";
+
+ /**
+ * Error message used in any SQL exception thrown because a {@code null} result set has been returned by the
+ * DataStax driver when a query is executed.
+ */
+ public static final String NO_RESULT_SET =
+ "No ResultSet returned from the CQL statement passed in an 'executeQuery()' method.";
+
+ /**
+ * Error message used in any SQL exception thrown when the parameter passed to the method
+ * {@code Statement.getMoreResults(int)} is invalid. This message is a template expecting the value of the
+ * invalid parameter as placeholder (example: {@code String.format(BAD_KEEP_RS, 9)}).
+ */
+ public static final String BAD_KEEP_RS =
+ "The argument for keeping the current result set: %d is not a valid value.";
+
+ /**
+ * Error message used in any SQL exception thrown when the expected type of result set for a
+ * {@link Statement} is invalid. This message is a template expecting the value of the
+ * invalid type of result set as placeholder (example: {@code String.format(BAD_TYPE_RS, 1099)}).
+ */
+ public static final String BAD_TYPE_RS = "The argument for result set type: %d is not a valid value.";
+
+ /**
+ * Error message used in any SQL exception thrown when the expected result set concurrency for a
+ * {@link Statement} is invalid. This message is a template expecting the value of the
+ * invalid result set concurrency value as placeholder (example: {@code String.format(BAD_CONCURRENCY_RS, 1099)}).
+ */
+ public static final String BAD_CONCURRENCY_RS =
+ "The argument for result set concurrency: %d is not a valid value.";
+
+ /**
+ * Error message used in any SQL exception thrown when the expected result set holdability for a
+ * {@link Statement} is invalid. This message is a template expecting the value of the
+ * invalid result set holdability value as placeholder (example: {@code String.format(BAD_HOLD_RS, 9)}).
+ */
+ public static final String BAD_HOLD_RS =
+ "The argument for result set holdability: %d is not a valid value.";
+
+ /**
+ * Error message used in any SQL exception thrown when the expected fetching direction for a
+ * {@link Statement} or a {@link ResultSet} is invalid. This message is a template expecting the
+ * value of the invalid fetching direction value as placeholder (example:
+ * {@code String.format(BAD_FETCH_DIR, 1099)}).
+ */
+ public static final String BAD_FETCH_DIR = "Fetch direction value of: %d is illegal.";
+
+ /**
+ * Error message used in any SQL exception thrown when the expected key auto-generation parameter used in a
+ * {@link Statement} is invalid. Note that auto-generated keys are currently not implemented in Cassandra.
+ * This message is a template expecting the value of the invalid parameter as placeholder (example:
+ * {@code String.format(BAD_AUTO_GEN, 9)}).
+ */
+ public static final String BAD_AUTO_GEN = "Auto key generation value of: %d is illegal.";
+
+ /**
+ * Error message used in any SQL exception thrown when the specified fetch size for a
+ * {@link Statement} or a {@link ResultSet} is negative. This message is a template expecting the
+ * value of the invalid fetch size value as placeholder (example: {@code String.format(BAD_FETCH_SIZE, -10)}).
+ */
+ public static final String BAD_FETCH_SIZE = "Fetch size of: %d rows may not be negative.";
+
+ /**
+ * Error message used in any SQL exception thrown when the specified column index in a {@link ResultSet}
+ * is not strictly positive or greater than the number of columns in the result set. This message is a template
+ * expecting the value of the invalid index value as placeholder (example:
+ * {@code String.format(MUST_BE_POSITIVE, 0)}).
+ */
+ public static final String MUST_BE_POSITIVE =
+ "Index must be a positive number less or equal the count of returned columns: %d";
+
+ /**
+ * Error message used in any SQL exception thrown when the specified column name in a {@link ResultSet}
+ * is invalid. This message is a template expecting the value of the invalid column name as placeholder (example:
+ * {@code String.format(VALID_LABELS, "invalid_column")}).
+ */
+ public static final String VALID_LABELS = "Name provided was not in the list of valid column labels: %s";
+
+ /**
+ * Error message used in any SQL exception thrown when the JDBC URL does not specify any host name.
+ */
+ public static final String HOST_IN_URL =
+ "Connection url must specify a host, e.g. jdbc:cassandra://localhost:9042/keyspace";
+
+ /**
+ * Error message used in any SQL exception thrown when a connection cannot be established due to a missing host
+ * name.
+ */
+ public static final String HOST_REQUIRED = "A host name is required to build a connection.";
+
+ /**
+ * Error message used in any SQL exception thrown when the specified keyspace name is invalid. This message is a
+ * template expecting the value of the invalid keyspace name as placeholder (example:
+ * {@code String.format(BAD_KEYSPACE, "invalid_key$pace")}).
+ */
+ public static final String BAD_KEYSPACE =
+ "Keyspace names must be composed of alphanumerics and underscores (parsed: '%s').";
+
+ /**
+ * Error message used in any SQL exception thrown when the provided JDBC URL contains not allowed user information
+ * (see {@link URI#getUserInfo()}).
+ */
+ public static final String URI_IS_SIMPLE =
+ "Connection URL may only include host, port, keyspace, and allowed options, e.g. "
+ + "jdbc:cassandra://localhost:9042/keyspace?consistency=ONE";
+
+ /**
+ * Error message used in any SQL exception thrown when the required parameter {@code secureconnectbundle} is
+ * missing in the JDBC URL.
+ */
+ public static final String SECURECONENCTBUNDLE_REQUIRED = "A 'secureconnectbundle' parameter is required.";
+
+ /**
+ * Error message used in any SQL exception thrown because the {@link ResultSet} type is set to
+ * {@link ResultSet#TYPE_FORWARD_ONLY} (but cursors are currently not implemented in Cassandra).
+ */
+ public static final String FORWARD_ONLY = "Can not position cursor with a type of TYPE_FORWARD_ONLY.";
+
+ /**
+ * Error message used in any SQL exception thrown when the method {@link ResultSet#getURL(int)} or
+ * {@link ResultSet#getURL(String)} is invoked on a column containing an invalid URL. This message is a template
+ * expecting the invalid value as placeholder (example: {@code String.format(MALFORMED_URL, "not_a_valid_url")}).
+ */
+ public static final String MALFORMED_URL = "The string '%s' is not a valid URL.";
+
+ /**
+ * Error message used in any SQL exception thrown when the SSL configuration for the connection fails. This message
+ * is a template expecting the message of the error cause as placeholder (example:
+ * {@code String.format(SSL_CONFIG_FAILED, "Invalid certificate")}).
+ */
+ public static final String SSL_CONFIG_FAILED = "Unable to configure SSL: %s.";
+
+ /**
+ * Error message used in any SQL exception thrown when the method {@link CassandraResultSet#getVector(int)} or
+ * {@link CassandraResultSet#getVector(String)} is invoked on a column containing an invalid CQL vector.
+ */
+ public static final String VECTOR_ELEMENTS_NOT_NUMBERS = "Vector elements are not numbers.";
+
+ private ErrorConstants() {
+ // Private constructor to hide the public one.
+ }
+
+}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/utils/Utils.java b/src/main/java/com/ing/data/cassandra/jdbc/utils/JdbcUrlUtil.java
similarity index 70%
rename from src/main/java/com/ing/data/cassandra/jdbc/utils/Utils.java
rename to src/main/java/com/ing/data/cassandra/jdbc/utils/JdbcUrlUtil.java
index 77db68c..c67577b 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/utils/Utils.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/utils/JdbcUrlUtil.java
@@ -18,269 +18,301 @@
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
import com.datastax.oss.driver.api.core.config.DriverOption;
import com.datastax.oss.driver.api.core.ssl.SslEngineFactory;
-import com.fasterxml.jackson.databind.DeserializationFeature;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.SerializationFeature;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
-import com.ing.data.cassandra.jdbc.json.CassandraBlobDeserializer;
-import com.ing.data.cassandra.jdbc.json.CassandraBlobSerializer;
-import com.ing.data.cassandra.jdbc.json.CassandraDateDeserializer;
-import com.ing.data.cassandra.jdbc.json.CassandraDateTimeDeserializer;
-import com.ing.data.cassandra.jdbc.json.CassandraTimeDeserializer;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.IOException;
-import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLDecoder;
-import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.sql.SQLException;
import java.sql.SQLNonTransientConnectionException;
import java.sql.SQLSyntaxErrorException;
import java.time.Duration;
-import java.time.LocalDate;
-import java.time.LocalTime;
-import java.time.OffsetDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_KEYSPACE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.HOST_IN_URL;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.HOST_REQUIRED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.SECURECONENCTBUNDLE_REQUIRED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.URI_IS_SIMPLE;
+
/**
- * A set of static utility methods and constants used by the JDBC wrapper, various default values and error message
- * strings that can be shared across classes.
+ * A set of static utility methods and constants used to parse the JDBC URL used to establish a connection to a
+ * Cassandra database.
*/
-public final class Utils {
+public final class JdbcUrlUtil {
+
+ /**
+ * Default Cassandra cluster port.
+ */
+ public static final int DEFAULT_PORT = 9042;
+
/**
* JDBC protocol for Cassandra connection.
*/
public static final String PROTOCOL = "jdbc:cassandra:";
+
/**
* JDBC protocol for Cassandra DBaaS connection.
*/
public static final String PROTOCOL_DBAAS = "jdbc:cassandra:dbaas:";
+
/**
- * Default Cassandra cluster port.
+ * JDBC URL parameter key for the CQL version.
*/
- public static final int DEFAULT_PORT = 9042;
+ public static final String KEY_VERSION = "version";
+
/**
- * Properties file name containing some properties relative to this JDBC wrapper (such as JDBC driver version,
- * name, etc.).
+ * Property name used to retrieve the active CQL version when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code version} or from the default value defined in the
+ * property {@code database.defaultCqlVersion} of the resource file 'jdbc-driver.properties'.
*/
- public static final String JDBC_DRIVER_PROPERTIES_FILE = "jdbc-driver.properties";
+ public static final String TAG_ACTIVE_CQL_VERSION = "activeCqlVersion";
/**
- * JDBC URL parameter key for the database version.
+ * Property name used to retrieve the active CQL version when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code version}.
*/
- public static final String KEY_VERSION = "version";
+ public static final String TAG_CQL_VERSION = "cqlVersion";
+
/**
* JDBC URL parameter key for the consistency.
*/
public static final String KEY_CONSISTENCY = "consistency";
+
+ /**
+ * Property name used to retrieve the consistency when the connection to Cassandra is established. This property
+ * is mapped from the JDBC URL parameter {@code consistency}.
+ */
+ public static final String TAG_CONSISTENCY_LEVEL = "consistencyLevel";
+
/**
* JDBC URL parameter key for the connection number of retries.
*/
public static final String KEY_CONNECTION_RETRIES = "retries";
+
+ /**
+ * Property name used to retrieve the number of retries when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code retries}.
+ */
+ public static final String TAG_CONNECTION_RETRIES = "retries";
+
/**
* JDBC URL parameter key for the load balancing policy.
*/
public static final String KEY_LOAD_BALANCING_POLICY = "loadbalancing";
+
+ /**
+ * Property name used to retrieve the load balancing policy when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code loadbalancing}.
+ */
+ public static final String TAG_LOAD_BALANCING_POLICY = "loadBalancing";
+
/**
* JDBC URL parameter key for the local data center.
*/
public static final String KEY_LOCAL_DATACENTER = "localdatacenter";
+
+ /**
+ * Property name used to retrieve the local data center when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code localdatacenter}.
+ */
+ public static final String TAG_LOCAL_DATACENTER = "localDatacenter";
+
/**
* JDBC URL parameter key for the retry policy.
*/
public static final String KEY_RETRY_POLICY = "retry";
+
+ /**
+ * Property name used to retrieve the retry policy when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code retry}.
+ */
+ public static final String TAG_RETRY_POLICY = "retry";
+
/**
* JDBC URL parameter key for the reconnection policy.
*/
public static final String KEY_RECONNECT_POLICY = "reconnection";
+
+ /**
+ * Property name used to retrieve the reconnection policy when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code reconnection}.
+ */
+ public static final String TAG_RECONNECT_POLICY = "reconnection";
+
/**
* JDBC URL parameter key for the debug mode.
*/
public static final String KEY_DEBUG = "debug";
+
+ /**
+ * Property name used to retrieve the debug mode value when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code debug}.
+ */
+ public static final String TAG_DEBUG = "debug";
+
/**
* JDBC URL parameter key for SSL enabling.
*/
public static final String KEY_ENABLE_SSL = "enablessl";
+
+ /**
+ * Property name used to retrieve the SSL enabling value when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code enablessl}.
+ */
+ public static final String TAG_ENABLE_SSL = "enableSsl";
+
/**
* JDBC URL parameter key for the custom SSL engine factory ({@link SslEngineFactory}).
*/
public static final String KEY_SSL_ENGINE_FACTORY = "sslenginefactory";
+
+ /**
+ * Property name used to retrieve the custom SSL engine factory when the connection to Cassandra is established.
+ * This property is mapped from the JDBC URL parameter {@code sslenginefactory}.
+ */
+ public static final String TAG_SSL_ENGINE_FACTORY = "sslEngineFactory";
+
/**
* JDBC URL parameter key for SSL hostname verification disabling.
*/
public static final String KEY_SSL_HOSTNAME_VERIFICATION = "hostnameverification";
+
+ /**
+ * Property name used to retrieve the SSL hostname verification enabling when the connection to Cassandra is
+ * established. This property is mapped from the JDBC URL parameter {@code hostnameverification}.
+ */
+ public static final String TAG_SSL_HOSTNAME_VERIFICATION = "hostnameVerification";
+
/**
* JDBC URL parameter key for the cloud secure connect bundle.
*/
public static final String KEY_CLOUD_SECURE_CONNECT_BUNDLE = "secureconnectbundle";
+
+ /**
+ * Property name used to retrieve the secure connect Bundle when the connection to Cassandra DBaaS is established.
+ * This property is mapped from the JDBC URL parameter {@code secureconnectbundle}.
+ */
+ public static final String TAG_CLOUD_SECURE_CONNECT_BUNDLE = "secureConnectBundle";
+
/**
* JDBC URL parameter key for the username.
*/
public static final String KEY_USER = "user";
+
+ /**
+ * Property name used to retrieve the username when the connection to Cassandra is established. This property
+ * is mapped from the JDBC URL parameter {@code user}.
+ */
+ public static final String TAG_USER = "user";
+
/**
* JDBC URL parameter key for the user password.
*/
public static final String KEY_PASSWORD = "password";
+
+ /**
+ * Property name used to retrieve the user password when the connection to Cassandra is established. This property
+ * is mapped from the JDBC URL parameter {@code password}.
+ */
+ public static final String TAG_PASSWORD = "password";
+
/**
* JDBC URL parameter key for the request timeout.
*/
public static final String KEY_REQUEST_TIMEOUT = "requesttimeout";
+
+ /**
+ * Property name used to retrieve the request timeout when the connection to Cassandra is established. This property
+ * is mapped from the JDBC URL parameter {@code requesttimeout}.
+ */
+ public static final String TAG_REQUEST_TIMEOUT = "requestTimeout";
+
/**
* JDBC URL parameter key for the connection timeout.
*/
public static final String KEY_CONNECT_TIMEOUT = "connecttimeout";
+
+ /**
+ * Property name used to retrieve the connection timeout when the connection to Cassandra is established. This
+ * property is mapped from the JDBC URL parameter {@code connecttimeout}.
+ */
+ public static final String TAG_CONNECT_TIMEOUT = "connectTimeout";
+
/**
* JDBC URL parameter key for the Nagle's algorithm enabling.
*/
public static final String KEY_TCP_NO_DELAY = "tcpnodelay";
+
+ /**
+ * Property name used to retrieve the Nagle's algorithm enabling when the connection to Cassandra is established.
+ * This property is mapped from the JDBC URL parameter {@code tcpnodelay}.
+ */
+ public static final String TAG_TCP_NO_DELAY = "tcpNoDelay";
+
/**
* JDBC URL parameter key for the TCP keep-alive enabling.
*/
public static final String KEY_KEEP_ALIVE = "keepalive";
+
+ /**
+ * Property name used to retrieve the TCP keep-alive enabling when the connection to Cassandra is established.
+ * This property is mapped from the JDBC URL parameter {@code keepalive}.
+ */
+ public static final String TAG_KEEP_ALIVE = "keepAlive";
+
/**
* JDBC URL parameter key for the configuration file.
*/
public static final String KEY_CONFIG_FILE = "configfile";
+
+ /**
+ * Property name used to retrieve the configuration file when the connection to Cassandra is established.
+ * This property is mapped from the JDBC URL parameter {@code configfile}.
+ */
+ public static final String TAG_CONFIG_FILE = "configFile";
+
/**
* JDBC URL parameter key for the compliance mode.
*/
public static final String KEY_COMPLIANCE_MODE = "compliancemode";
- public static final String TAG_USER = "user";
- public static final String TAG_PASSWORD = "password";
- public static final String TAG_DATABASE_NAME = "databaseName";
- public static final String TAG_SERVER_NAME = "serverName";
- public static final String TAG_PORT_NUMBER = "portNumber";
- public static final String TAG_ACTIVE_CQL_VERSION = "activeCqlVersion";
- public static final String TAG_CQL_VERSION = "cqlVersion";
- public static final String TAG_CONSISTENCY_LEVEL = "consistencyLevel";
- public static final String TAG_LOAD_BALANCING_POLICY = "loadBalancing";
- public static final String TAG_LOCAL_DATACENTER = "localDatacenter";
- public static final String TAG_RETRY_POLICY = "retry";
- public static final String TAG_RECONNECT_POLICY = "reconnection";
- public static final String TAG_DEBUG = "debug";
- public static final String TAG_CONNECTION_RETRIES = "retries";
- public static final String TAG_ENABLE_SSL = "enableSsl";
- public static final String TAG_SSL_ENGINE_FACTORY = "sslEngineFactory";
- public static final String TAG_SSL_HOSTNAME_VERIFICATION = "hostnameVerification";
- public static final String TAG_CLOUD_SECURE_CONNECT_BUNDLE = "secureConnectBundle";
- public static final String TAG_CONFIG_FILE = "configFile";
- public static final String TAG_REQUEST_TIMEOUT = "requestTimeout";
- public static final String TAG_CONNECT_TIMEOUT = "connectTimeout";
- public static final String TAG_TCP_NO_DELAY = "tcpNoDelay";
- public static final String TAG_KEEP_ALIVE = "keepAlive";
+ /**
+ * Property name used to retrieve the compliance mode to use when the connection to Cassandra is established.
+ * This property is mapped from the JDBC URL parameter {@code compliancemode}.
+ */
public static final String TAG_COMPLIANCE_MODE = "complianceMode";
- public static final String JSSE_TRUSTSTORE_PROPERTY = "javax.net.ssl.trustStore";
- public static final String JSSE_TRUSTSTORE_PASSWORD_PROPERTY = "javax.net.ssl.trustStorePassword";
- public static final String JSSE_KEYSTORE_PROPERTY = "javax.net.ssl.keyStore";
- public static final String JSSE_KEYSTORE_PASSWORD_PROPERTY = "javax.net.ssl.keyStorePassword";
-
- /**
- * {@code NULL} CQL keyword.
- */
- public static final String NULL_KEYWORD = "NULL";
-
- public static final String WAS_CLOSED_CONN = "Method was called on a closed Connection.";
- public static final String WAS_CLOSED_STMT = "Method was called on a closed Statement.";
- public static final String WAS_CLOSED_RS = "Method was called on a closed ResultSet.";
- public static final String NO_INTERFACE = "No object was found that matched the provided interface: %s";
- public static final String NO_TRANSACTIONS = "The Cassandra implementation does not support transactions.";
- public static final String ALWAYS_AUTOCOMMIT = "The Cassandra implementation is always in auto-commit mode.";
- public static final String BAD_TIMEOUT = "The timeout value was less than zero.";
- public static final String NOT_SUPPORTED = "The Cassandra implementation does not support this method.";
- public static final String NO_GEN_KEYS =
- "The Cassandra implementation does not currently support returning generated keys.";
- public static final String NO_MULTIPLE =
- "The Cassandra implementation does not currently support multiple open Result Sets.";
- public static final String NO_RESULT_SET =
- "No ResultSet returned from the CQL statement passed in an 'executeQuery()' method.";
- public static final String BAD_KEEP_RS =
- "The argument for keeping the current result set: %s is not a valid value.";
- public static final String BAD_TYPE_RS = "The argument for result set type: %s is not a valid value.";
- public static final String BAD_CONCURRENCY_RS =
- "The argument for result set concurrency: %s is not a valid value.";
- public static final String BAD_HOLD_RS =
- "The argument for result set holdability: %s is not a valid value.";
- public static final String BAD_FETCH_DIR = "Fetch direction value of: %s is illegal.";
- public static final String BAD_AUTO_GEN = "Auto key generation value of: %s is illegal.";
- public static final String BAD_FETCH_SIZE = "Fetch size of: %s rows may not be negative.";
- public static final String MUST_BE_POSITIVE =
- "Index must be a positive number less or equal the count of returned columns: %d";
- public static final String VALID_LABELS = "Name provided was not in the list of valid column labels: %s";
- public static final String HOST_IN_URL =
- "Connection url must specify a host, e.g. jdbc:cassandra://localhost:9042/keyspace";
- public static final String HOST_REQUIRED = "A 'host' name is required to build a Connection.";
- public static final String BAD_KEYSPACE =
- "Keyspace names must be composed of alphanumerics and underscores (parsed: '%s').";
- public static final String URI_IS_SIMPLE =
- "Connection url may only include host, port, and keyspace, consistency and version option, e.g. "
- + "jdbc:cassandra://localhost:9042/keyspace?version=3.0.0&consistency=ONE";
- public static final String SECURECONENCTBUNDLE_REQUIRED = "A 'secureconnectbundle' parameter is required.";
- public static final String FORWARD_ONLY = "Can not position cursor with a type of TYPE_FORWARD_ONLY.";
- public static final String MALFORMED_URL = "The string '%s' is not a valid URL.";
- public static final String SSL_CONFIG_FAILED = "Unable to configure SSL: %s.";
- public static final String VECTOR_ELEMENTS_NOT_NUMBERS = "Vector elements are not numbers.";
-
- static final Logger LOG = LoggerFactory.getLogger(Utils.class);
-
- static ObjectMapper objectMapperInstance = null;
-
- private Utils() {
- // Private constructor to hide the public one.
- }
+ /**
+ * Property name used to retrieve the keyspace name when the connection to Cassandra is established. This property
+ * is mapped from the JDBC URL keyspace path parameter.
+ */
+ public static final String TAG_DATABASE_NAME = "databaseName";
/**
- * Gets a property value from the Cassandra JDBC driver properties file.
- *
- * @param name The name of the property.
- * @return The property value or an empty string the value cannot be retrieved.
- */
- public static String getDriverProperty(final String name) {
- try (final InputStream propertiesFile =
- Utils.class.getClassLoader().getResourceAsStream(JDBC_DRIVER_PROPERTIES_FILE)) {
- final Properties driverProperties = new Properties();
- driverProperties.load(propertiesFile);
- return driverProperties.getProperty(name, StringUtils.EMPTY);
- } catch (IOException ex) {
- LOG.error("Unable to get JDBC driver property: {}.", name, ex);
- return StringUtils.EMPTY;
- }
- }
+ * Property name used to retrieve the contact points when the connection to Cassandra is established. This property
+ * is mapped from the JDBC URL host.
+ */
+ public static final String TAG_SERVER_NAME = "serverName";
/**
- * Gets a part of a version string.
- *
- * It uses the dot character as separator to parse the different parts of a version (major, minor, patch).
- *
- *
- * @param version The version string (for example X.Y.Z).
- * @param part The part of the version to extract (for the semantic versioning, use 0 for the major version, 1 for
- * the minor and 2 for the patch).
- * @return The requested part of the version, or 0 if the requested part cannot be parsed correctly.
- */
- public static int parseVersion(final String version, final int part) {
- if (StringUtils.isBlank(version) || StringUtils.countMatches(version, ".") < part || part < 0) {
- return 0;
- } else {
- try {
- return Integer.parseInt(version.split("\\.")[part]);
- } catch (final NumberFormatException ex) {
- LOG.error("Unable to parse version: {}", version);
- return 0;
- }
- }
+ * Property name used to retrieve the port used when the connection to Cassandra is established. This property
+ * is mapped from the JDBC URL port.
+ */
+ public static final String TAG_PORT_NUMBER = "portNumber";
+
+ static final Logger LOG = LoggerFactory.getLogger(JdbcUrlUtil.class);
+
+ private JdbcUrlUtil() {
+ // Private constructor to hide the public one.
}
/**
@@ -551,7 +583,7 @@ private static Map getReconnectionPolicy(final String prim
policyParametersMap.put(DefaultDriverOption.RECONNECTION_POLICY_CLASS, primaryReconnectionPolicyClass);
// Parameters have been specified
- if (parameters.length() > 0) {
+ if (!parameters.isEmpty()) {
final String paramsRegex = "([^,]+\\(.+?\\))|([^,]+)";
final Pattern paramsPattern = Pattern.compile(paramsRegex);
final Matcher paramsMatcher = paramsPattern.matcher(parameters);
@@ -584,29 +616,4 @@ private static Map getReconnectionPolicy(final String prim
return policyParametersMap;
}
- /**
- * Gets a pre-configured {@link ObjectMapper} for JSON support.
- *
- * @return A pre-configured {@link ObjectMapper} for JSON support.
- */
- public static ObjectMapper getObjectMapper() {
- if (objectMapperInstance != null) {
- return objectMapperInstance;
- } else {
- final ObjectMapper objectMapper = new ObjectMapper();
- objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
- objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
- objectMapper.registerModule(new JavaTimeModule());
- final SimpleModule cassandraExtensionsModule = new SimpleModule();
- cassandraExtensionsModule.addDeserializer(ByteBuffer.class, new CassandraBlobDeserializer());
- cassandraExtensionsModule.addDeserializer(LocalDate.class, new CassandraDateDeserializer());
- cassandraExtensionsModule.addDeserializer(LocalTime.class, new CassandraTimeDeserializer());
- cassandraExtensionsModule.addDeserializer(OffsetDateTime.class, new CassandraDateTimeDeserializer());
- cassandraExtensionsModule.addSerializer(ByteBuffer.class, new CassandraBlobSerializer());
- objectMapper.registerModule(cassandraExtensionsModule);
- objectMapperInstance = objectMapper;
- return objectMapper;
- }
- }
-
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/utils/JsonUtil.java b/src/main/java/com/ing/data/cassandra/jdbc/utils/JsonUtil.java
new file mode 100644
index 0000000..869d8d0
--- /dev/null
+++ b/src/main/java/com/ing/data/cassandra/jdbc/utils/JsonUtil.java
@@ -0,0 +1,70 @@
+/*
+ *
+ * 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 com.ing.data.cassandra.jdbc.utils;
+
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.ing.data.cassandra.jdbc.json.CassandraBlobDeserializer;
+import com.ing.data.cassandra.jdbc.json.CassandraBlobSerializer;
+import com.ing.data.cassandra.jdbc.json.CassandraDateDeserializer;
+import com.ing.data.cassandra.jdbc.json.CassandraDateTimeDeserializer;
+import com.ing.data.cassandra.jdbc.json.CassandraTimeDeserializer;
+
+import java.nio.ByteBuffer;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+
+/**
+ * Utility methods used for JSON-type handling.
+ */
+public final class JsonUtil {
+
+ static ObjectMapper objectMapperInstance = null;
+
+ private JsonUtil() {
+ // Private constructor to hide the public one.
+ }
+
+ /**
+ * Gets a pre-configured {@link ObjectMapper} for JSON support.
+ *
+ * @return A pre-configured {@link ObjectMapper} for JSON support.
+ */
+ public static ObjectMapper getObjectMapper() {
+ if (objectMapperInstance != null) {
+ return objectMapperInstance;
+ } else {
+ final ObjectMapper objectMapper = new ObjectMapper();
+ objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+ objectMapper.registerModule(new JavaTimeModule());
+ final SimpleModule cassandraExtensionsModule = new SimpleModule();
+ cassandraExtensionsModule.addDeserializer(ByteBuffer.class, new CassandraBlobDeserializer());
+ cassandraExtensionsModule.addDeserializer(LocalDate.class, new CassandraDateDeserializer());
+ cassandraExtensionsModule.addDeserializer(LocalTime.class, new CassandraTimeDeserializer());
+ cassandraExtensionsModule.addDeserializer(OffsetDateTime.class, new CassandraDateTimeDeserializer());
+ cassandraExtensionsModule.addSerializer(ByteBuffer.class, new CassandraBlobSerializer());
+ objectMapper.registerModule(cassandraExtensionsModule);
+ objectMapperInstance = objectMapper;
+ return objectMapper;
+ }
+ }
+
+}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java b/src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java
index 1e84d0a..e11a959 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java
@@ -56,19 +56,18 @@
import java.util.Optional;
import static com.ing.data.cassandra.jdbc.SessionHolder.URL_KEY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.BAD_TIMEOUT;
-import static com.ing.data.cassandra.jdbc.utils.Utils.JSSE_KEYSTORE_PASSWORD_PROPERTY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.JSSE_KEYSTORE_PROPERTY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.JSSE_TRUSTSTORE_PASSWORD_PROPERTY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.JSSE_TRUSTSTORE_PROPERTY;
-import static com.ing.data.cassandra.jdbc.utils.Utils.SSL_CONFIG_FAILED;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.JSSE_KEYSTORE_PASSWORD_PROPERTY;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.JSSE_KEYSTORE_PROPERTY;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.JSSE_TRUSTSTORE_PASSWORD_PROPERTY;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.JSSE_TRUSTSTORE_PROPERTY;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_TIMEOUT;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.SSL_CONFIG_FAILED;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.instanceOf;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/DataSourceUnitTest.java b/src/test/java/com/ing/data/cassandra/jdbc/DataSourceUnitTest.java
index f6c5472..aeabe3c 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/DataSourceUnitTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/DataSourceUnitTest.java
@@ -13,12 +13,12 @@
*/
package com.ing.data.cassandra.jdbc;
-import com.ing.data.cassandra.jdbc.utils.Utils;
import org.junit.jupiter.api.Test;
import javax.sql.DataSource;
import java.sql.SQLException;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CQL_VERSION;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -58,7 +58,7 @@ void givenParameters_whenConstructDataSource_returnCassandraDataSource() throws
cnx = ds.getConnection();
assertFalse(cnx.isClosed());
ds.setLoginTimeout(5);
- assertEquals(VERSION, ((CassandraConnection) cnx).getConnectionProperties().get(Utils.TAG_CQL_VERSION));
+ assertEquals(VERSION, ((CassandraConnection) cnx).getConnectionProperties().get(TAG_CQL_VERSION));
assertEquals(5, ds.getLoginTimeout());
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/UtilsUnitTest.java b/src/test/java/com/ing/data/cassandra/jdbc/UtilsUnitTest.java
index 4fe096b..aec67aa 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/UtilsUnitTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/UtilsUnitTest.java
@@ -15,7 +15,6 @@
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
import com.datastax.oss.driver.api.core.config.DriverOption;
-import com.ing.data.cassandra.jdbc.utils.Utils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
@@ -32,16 +31,33 @@
import java.util.Properties;
import java.util.stream.Stream;
-import static com.ing.data.cassandra.jdbc.utils.Utils.BAD_KEYSPACE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.DEFAULT_PORT;
-import static com.ing.data.cassandra.jdbc.utils.Utils.HOST_IN_URL;
-import static com.ing.data.cassandra.jdbc.utils.Utils.HOST_REQUIRED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.SECURECONENCTBUNDLE_REQUIRED;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_PORT_NUMBER;
-import static com.ing.data.cassandra.jdbc.utils.Utils.TAG_SERVER_NAME;
-import static com.ing.data.cassandra.jdbc.utils.Utils.URI_IS_SIMPLE;
-import static com.ing.data.cassandra.jdbc.utils.Utils.getDriverProperty;
-import static com.ing.data.cassandra.jdbc.utils.Utils.parseVersion;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.getDriverProperty;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.parseVersion;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.BAD_KEYSPACE;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.HOST_IN_URL;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.HOST_REQUIRED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.SECURECONENCTBUNDLE_REQUIRED;
+import static com.ing.data.cassandra.jdbc.utils.ErrorConstants.URI_IS_SIMPLE;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.DEFAULT_PORT;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.PROTOCOL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CLOUD_SECURE_CONNECT_BUNDLE;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CONNECTION_RETRIES;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CONSISTENCY_LEVEL;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_CQL_VERSION;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_DATABASE_NAME;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_DEBUG;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_LOAD_BALANCING_POLICY;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_LOCAL_DATACENTER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_PASSWORD;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_PORT_NUMBER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_RECONNECT_POLICY;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_REQUEST_TIMEOUT;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_RETRY_POLICY;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_SERVER_NAME;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.TAG_USER;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.createSubName;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.parseReconnectionPolicy;
+import static com.ing.data.cassandra.jdbc.utils.JdbcUrlUtil.parseURL;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
@@ -52,75 +68,75 @@ static Stream buildUrlParsingTestCases() {
return Stream.of(
Arguments.of("jdbc:cassandra://localhost:9042/astra?secureconnectbundle=/path/to/location/filename.extn&user=user1&password=password1",
new HashMap() {{
- put(Utils.TAG_SERVER_NAME, "localhost");
- put(Utils.TAG_PORT_NUMBER, "9042");
- put(Utils.TAG_DATABASE_NAME, "astra");
- put(Utils.TAG_CLOUD_SECURE_CONNECT_BUNDLE, "/path/to/location/filename.extn");
- put(Utils.TAG_USER, "user1");
- put(Utils.TAG_PASSWORD, "password1");
+ put(TAG_SERVER_NAME, "localhost");
+ put(TAG_PORT_NUMBER, "9042");
+ put(TAG_DATABASE_NAME, "astra");
+ put(TAG_CLOUD_SECURE_CONNECT_BUNDLE, "/path/to/location/filename.extn");
+ put(TAG_USER, "user1");
+ put(TAG_PASSWORD, "password1");
}}),
Arguments.of("jdbc:cassandra:dbaas:///astra?secureconnectbundle=/path/to/location/filename.extn&user=user1&password=password1",
new HashMap() {{
- put(Utils.TAG_SERVER_NAME, null);
- put(Utils.TAG_PORT_NUMBER, String.valueOf(DEFAULT_PORT));
- put(Utils.TAG_DATABASE_NAME, "astra");
- put(Utils.TAG_CLOUD_SECURE_CONNECT_BUNDLE, "/path/to/location/filename.extn");
- put(Utils.TAG_USER, "user1");
- put(Utils.TAG_PASSWORD, "password1");
+ put(TAG_SERVER_NAME, null);
+ put(TAG_PORT_NUMBER, String.valueOf(DEFAULT_PORT));
+ put(TAG_DATABASE_NAME, "astra");
+ put(TAG_CLOUD_SECURE_CONNECT_BUNDLE, "/path/to/location/filename.extn");
+ put(TAG_USER, "user1");
+ put(TAG_PASSWORD, "password1");
}}),
Arguments.of("jdbc:cassandra://localhost:9042/Keyspace1?version=3.0.0&consistency=QUORUM",
new HashMap() {{
- put(Utils.TAG_SERVER_NAME, "localhost");
- put(Utils.TAG_PORT_NUMBER, "9042");
- put(Utils.TAG_DATABASE_NAME, "Keyspace1");
- put(Utils.TAG_CQL_VERSION, "3.0.0");
- put(Utils.TAG_CONSISTENCY_LEVEL, "QUORUM");
+ put(TAG_SERVER_NAME, "localhost");
+ put(TAG_PORT_NUMBER, "9042");
+ put(TAG_DATABASE_NAME, "Keyspace1");
+ put(TAG_CQL_VERSION, "3.0.0");
+ put(TAG_CONSISTENCY_LEVEL, "QUORUM");
}}),
Arguments.of("jdbc:cassandra://localhost/Keyspace1?consistency=QUORUM",
new HashMap() {{
- put(Utils.TAG_SERVER_NAME, "localhost");
- put(Utils.TAG_PORT_NUMBER, "9042");
- put(Utils.TAG_DATABASE_NAME, "Keyspace1");
- put(Utils.TAG_CQL_VERSION, null);
- put(Utils.TAG_CONSISTENCY_LEVEL, "QUORUM");
+ put(TAG_SERVER_NAME, "localhost");
+ put(TAG_PORT_NUMBER, "9042");
+ put(TAG_DATABASE_NAME, "Keyspace1");
+ put(TAG_CQL_VERSION, null);
+ put(TAG_CONSISTENCY_LEVEL, "QUORUM");
}}),
Arguments.of("jdbc:cassandra://localhost/Keyspace1?version=2.0.0",
new HashMap() {{
- put(Utils.TAG_SERVER_NAME, "localhost");
- put(Utils.TAG_PORT_NUMBER, "9042");
- put(Utils.TAG_DATABASE_NAME, "Keyspace1");
- put(Utils.TAG_CQL_VERSION, "2.0.0");
- put(Utils.TAG_CONSISTENCY_LEVEL, null);
+ put(TAG_SERVER_NAME, "localhost");
+ put(TAG_PORT_NUMBER, "9042");
+ put(TAG_DATABASE_NAME, "Keyspace1");
+ put(TAG_CQL_VERSION, "2.0.0");
+ put(TAG_CONSISTENCY_LEVEL, null);
}}),
Arguments.of("jdbc:cassandra://localhost",
new HashMap() {{
- put(Utils.TAG_SERVER_NAME, "localhost");
- put(Utils.TAG_PORT_NUMBER, "9042");
- put(Utils.TAG_DATABASE_NAME, null);
- put(Utils.TAG_CQL_VERSION, null);
- put(Utils.TAG_CONSISTENCY_LEVEL, null);
+ put(TAG_SERVER_NAME, "localhost");
+ put(TAG_PORT_NUMBER, "9042");
+ put(TAG_DATABASE_NAME, null);
+ put(TAG_CQL_VERSION, null);
+ put(TAG_CONSISTENCY_LEVEL, null);
}}),
Arguments.of("jdbc:cassandra://localhost/Keyspace1?localdatacenter=DC1",
new HashMap() {{
- put(Utils.TAG_SERVER_NAME, "localhost");
- put(Utils.TAG_PORT_NUMBER, "9042");
- put(Utils.TAG_DATABASE_NAME, "Keyspace1");
- put(Utils.TAG_LOCAL_DATACENTER, "DC1");
+ put(TAG_SERVER_NAME, "localhost");
+ put(TAG_PORT_NUMBER, "9042");
+ put(TAG_DATABASE_NAME, "Keyspace1");
+ put(TAG_LOCAL_DATACENTER, "DC1");
}}),
Arguments.of("jdbc:cassandra://localhost/Keyspace1?localdatacenter=DC1&debug=true"
+ "&retries=5&requesttimeout=3000&loadbalancing=com.company.package.CustomLBPolicy"
+ "&retry=com.company.package.CustomRetryPolicy&reconnection=ConstantReconnectionPolicy()",
new HashMap() {{
- put(Utils.TAG_SERVER_NAME, "localhost");
- put(Utils.TAG_PORT_NUMBER, "9042");
- put(Utils.TAG_DATABASE_NAME, "Keyspace1");
- put(Utils.TAG_LOCAL_DATACENTER, "DC1");
- put(Utils.TAG_DEBUG, "true");
- put(Utils.TAG_CONNECTION_RETRIES, "5");
- put(Utils.TAG_LOAD_BALANCING_POLICY, "com.company.package.CustomLBPolicy");
- put(Utils.TAG_RETRY_POLICY, "com.company.package.CustomRetryPolicy");
- put(Utils.TAG_RECONNECT_POLICY, "ConstantReconnectionPolicy()");
- put(Utils.TAG_REQUEST_TIMEOUT, "3000");
+ put(TAG_SERVER_NAME, "localhost");
+ put(TAG_PORT_NUMBER, "9042");
+ put(TAG_DATABASE_NAME, "Keyspace1");
+ put(TAG_LOCAL_DATACENTER, "DC1");
+ put(TAG_DEBUG, "true");
+ put(TAG_CONNECTION_RETRIES, "5");
+ put(TAG_LOAD_BALANCING_POLICY, "com.company.package.CustomLBPolicy");
+ put(TAG_RETRY_POLICY, "com.company.package.CustomRetryPolicy");
+ put(TAG_RECONNECT_POLICY, "ConstantReconnectionPolicy()");
+ put(TAG_REQUEST_TIMEOUT, "3000");
}})
);
}
@@ -130,7 +146,7 @@ static Stream buildUrlParsingTestCases() {
void givenJdbcUrl_whenParseUrl_returnExpectedProperties(final String jdbcUrl,
final Map expectedProperties)
throws SQLException {
- final Properties result = Utils.parseURL(jdbcUrl);
+ final Properties result = parseURL(jdbcUrl);
expectedProperties.forEach((key, value) -> assertEquals(value, result.getProperty(key)));
}
@@ -171,7 +187,7 @@ static Stream buildReconnectionPolicyParsingTestCases() {
@MethodSource("buildReconnectionPolicyParsingTestCases")
void givenReconnectionPolicyString_whenParsePolicy_returnExpectedOptions(
final String policyString, final Map expectedPolicy) {
- final Map policyOptions = Utils.parseReconnectionPolicy(policyString);
+ final Map policyOptions = parseReconnectionPolicy(policyString);
assertNotNull(policyOptions);
expectedPolicy.forEach((key, value) -> assertEquals(value, policyOptions.get(key)));
}
@@ -179,28 +195,28 @@ void givenReconnectionPolicyString_whenParsePolicy_returnExpectedOptions(
@Test
void testCreateSubName() throws Exception {
final String jdbcUrl = "jdbc:cassandra://localhost:9042/Keyspace1?consistency=QUORUM&version=3.0.0";
- final Properties props = Utils.parseURL(jdbcUrl);
- final String result = Utils.createSubName(props);
- assertEquals(jdbcUrl, Utils.PROTOCOL + result);
+ final Properties props = parseURL(jdbcUrl);
+ final String result = createSubName(props);
+ assertEquals(jdbcUrl, PROTOCOL + result);
}
@Test
void testCreateSubNameWithoutParams() throws Exception {
final String jdbcUrl = "jdbc:cassandra://localhost:9042/Keyspace1";
- final Properties props = Utils.parseURL(jdbcUrl);
- final String result = Utils.createSubName(props);
- assertEquals(jdbcUrl, Utils.PROTOCOL + result);
+ final Properties props = parseURL(jdbcUrl);
+ final String result = createSubName(props);
+ assertEquals(jdbcUrl, PROTOCOL + result);
}
@Test
void testInvalidJdbcUrl() {
- assertThrows(SQLSyntaxErrorException.class, () -> Utils.parseURL("jdbc:cassandra/bad%uri"));
+ assertThrows(SQLSyntaxErrorException.class, () -> parseURL("jdbc:cassandra/bad%uri"));
}
@Test
void testNullHost() {
final SQLNonTransientConnectionException exception = assertThrows(SQLNonTransientConnectionException.class,
- () -> Utils.parseURL("jdbc:cassandra:"));
+ () -> parseURL("jdbc:cassandra:"));
assertEquals(HOST_IN_URL, exception.getMessage());
}
@@ -208,40 +224,40 @@ void testNullHost() {
void testInvalidKeyspaceName() {
final String invalidKeyspaceName = "bad-keyspace";
final SQLNonTransientConnectionException exception = assertThrows(SQLNonTransientConnectionException.class,
- () -> Utils.parseURL("jdbc:cassandra://hostname:9042/" + invalidKeyspaceName));
+ () -> parseURL("jdbc:cassandra://hostname:9042/" + invalidKeyspaceName));
assertEquals(String.format(BAD_KEYSPACE, invalidKeyspaceName), exception.getMessage());
}
@Test
void testNotNullUserInfo() {
final SQLNonTransientConnectionException exception = assertThrows(SQLNonTransientConnectionException.class,
- () -> Utils.parseURL("jdbc:cassandra://john_doe@hostname:9042/validKeyspace"));
+ () -> parseURL("jdbc:cassandra://john_doe@hostname:9042/validKeyspace"));
assertEquals(URI_IS_SIMPLE, exception.getMessage());
}
@Test
void testCreateSubNameWithoutHost() throws Exception {
final String jdbcUrl = "jdbc:cassandra://localhost:9042/Keyspace1";
- final Properties props = Utils.parseURL(jdbcUrl);
+ final Properties props = parseURL(jdbcUrl);
props.remove(TAG_SERVER_NAME);
final SQLNonTransientConnectionException exception = assertThrows(SQLNonTransientConnectionException.class,
- () -> Utils.createSubName(props));
+ () -> createSubName(props));
assertEquals(HOST_REQUIRED, exception.getMessage());
}
@Test
void testCreateSubNameWithInvalidPortNumber() throws Exception {
final String jdbcUrl = "jdbc:cassandra://localhost/Keyspace1";
- final Properties props = Utils.parseURL(jdbcUrl);
+ final Properties props = parseURL(jdbcUrl);
props.put(TAG_PORT_NUMBER, "-9042");
- assertThrows(SQLNonTransientConnectionException.class, () -> Utils.createSubName(props));
+ assertThrows(SQLNonTransientConnectionException.class, () -> createSubName(props));
}
@ParameterizedTest
@ValueSource(strings = {"jdbc:cassandra:dbaas:///astra", "jdbc:cassandra:dbaas:///astra?user=User1"})
void testMissingSecureConnectBundleOnDbaasConenctionString(final String jdbcUrl) {
final SQLNonTransientConnectionException exception = assertThrows(SQLNonTransientConnectionException.class,
- () -> Utils.parseURL(jdbcUrl));
+ () -> parseURL(jdbcUrl));
assertEquals(SECURECONENCTBUNDLE_REQUIRED, exception.getMessage());
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/BigintToBigDecimalCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/BigintToBigDecimalCodecTest.java
index a6df575..be326c5 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/BigintToBigDecimalCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/BigintToBigDecimalCodecTest.java
@@ -28,7 +28,7 @@
import java.nio.ByteBuffer;
import java.util.stream.Stream;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/DecimalToDoubleCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/DecimalToDoubleCodecTest.java
index bdb2bf7..2306a48 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/DecimalToDoubleCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/DecimalToDoubleCodecTest.java
@@ -21,7 +21,7 @@
import java.nio.ByteBuffer;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/FloatToDoubleCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/FloatToDoubleCodecTest.java
index 9eb1a33..dd5b02e 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/FloatToDoubleCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/FloatToDoubleCodecTest.java
@@ -21,7 +21,7 @@
import java.nio.ByteBuffer;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/IntToLongCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/IntToLongCodecTest.java
index 1232caf..0e28c2a 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/IntToLongCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/IntToLongCodecTest.java
@@ -21,7 +21,7 @@
import java.nio.ByteBuffer;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/LongToIntCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/LongToIntCodecTest.java
index 223f23d..ade6eb6 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/LongToIntCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/LongToIntCodecTest.java
@@ -21,7 +21,7 @@
import java.nio.ByteBuffer;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/SmallintToIntCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/SmallintToIntCodecTest.java
index 9ad2610..f3b524e 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/SmallintToIntCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/SmallintToIntCodecTest.java
@@ -21,7 +21,7 @@
import java.nio.ByteBuffer;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/TimestampToLongCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/TimestampToLongCodecTest.java
index 6652589..34b3daf 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/TimestampToLongCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/TimestampToLongCodecTest.java
@@ -22,7 +22,7 @@
import java.nio.ByteBuffer;
import java.time.Instant;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/TinyintToIntCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/TinyintToIntCodecTest.java
index 6a7b0fc..7004117 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/TinyintToIntCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/TinyintToIntCodecTest.java
@@ -21,7 +21,7 @@
import java.nio.ByteBuffer;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/codec/VarintToIntCodecTest.java b/src/test/java/com/ing/data/cassandra/jdbc/codec/VarintToIntCodecTest.java
index 5509125..fb1d530 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/codec/VarintToIntCodecTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/codec/VarintToIntCodecTest.java
@@ -21,7 +21,7 @@
import java.nio.ByteBuffer;
-import static com.ing.data.cassandra.jdbc.utils.Utils.NULL_KEYWORD;
+import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
From c2b8e1c5ab7089bdda8e81fa5d917fee26c05fac Mon Sep 17 00:00:00 2001
From: Maxime Wiewiora <48218208+maximevw@users.noreply.github.com>
Date: Mon, 18 Sep 2023 14:56:23 +0200
Subject: [PATCH 16/21] Refactor connection test with SSL using container
(and add some missing Javadoc on DataTypeEnum values)
---
.../cassandra/jdbc/types/DataTypeEnum.java | 108 ++++++++++++++++++
.../cassandra/jdbc/ConnectionUnitTest.java | 26 +++--
.../jdbc/UsingCassandraContainerTest.java | 7 +-
src/test/resources/cassandra.keystore | Bin 0 -> 2734 bytes
src/test/resources/cassandra.truststore | Bin 0 -> 1254 bytes
.../resources/config_override/cassandra.yaml | 18 +--
src/test/resources/test_keystore.jks | Bin 5071 -> 0 bytes
src/test/resources/test_truststore.jks | Bin 1330 -> 0 bytes
8 files changed, 138 insertions(+), 21 deletions(-)
create mode 100644 src/test/resources/cassandra.keystore
create mode 100644 src/test/resources/cassandra.truststore
delete mode 100644 src/test/resources/test_keystore.jks
delete mode 100644 src/test/resources/test_truststore.jks
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java b/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
index c53097b..d1fe6e3 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
@@ -42,38 +42,146 @@
*/
public enum DataTypeEnum {
+ /**
+ * {@code ascii} CQL type (type {@value DataType#ASCII} in CQL native protocol) mapped to {@link String} Java type.
+ */
ASCII(DataType.ASCII, String.class, cqlName(DataTypes.ASCII)),
+ /**
+ * {@code bigint} CQL type (type {@value DataType#BIGINT} in CQL native protocol) mapped to {@link Long} Java type.
+ */
BIGINT(DataType.BIGINT, Long.class, cqlName(DataTypes.BIGINT)),
+ /**
+ * {@code blob} CQL type (type {@value DataType#BLOB} in CQL native protocol) mapped to {@link ByteBuffer} Java
+ * type.
+ */
BLOB(DataType.BLOB, ByteBuffer.class, cqlName(DataTypes.BLOB)),
+ /**
+ * {@code boolean} CQL type (type {@value DataType#BOOLEAN} in CQL native protocol) mapped to {@link Boolean} Java
+ * type.
+ */
BOOLEAN(DataType.BOOLEAN, Boolean.class, cqlName(DataTypes.BOOLEAN)),
+ /**
+ * {@code counter} CQL type (type {@value DataType#COUNTER} in CQL native protocol) mapped to {@link Long} Java
+ * type.
+ */
COUNTER(DataType.COUNTER, Long.class, cqlName(DataTypes.COUNTER)),
+ /**
+ * {@code custom} CQL type (type {@value DataType#CUSTOM} in CQL native protocol) mapped to {@link ByteBuffer} Java
+ * type.
+ */
CUSTOM(DataType.CUSTOM, ByteBuffer.class, "CUSTOM"),
+ /**
+ * {@code date} CQL type (type {@value DataType#DATE} in CQL native protocol) mapped to {@link Date} Java type.
+ */
DATE(DataType.DATE, Date.class, cqlName(DataTypes.DATE)),
+ /**
+ * {@code decimal} CQL type (type {@value DataType#DECIMAL} in CQL native protocol) mapped to {@link BigDecimal}
+ * Java type.
+ */
DECIMAL(DataType.DECIMAL, BigDecimal.class, cqlName(DataTypes.DECIMAL)),
+ /**
+ * {@code double} CQL type (type {@value DataType#DOUBLE} in CQL native protocol) mapped to {@link Double} Java
+ * type.
+ */
DOUBLE(DataType.DOUBLE, Double.class, cqlName(DataTypes.DOUBLE)),
+ /**
+ * {@code duration} CQL type (type {@value DataType#DURATION} in CQL native protocol) mapped to {@link CqlDuration}
+ * Java type.
+ */
DURATION(DataType.DURATION, CqlDuration.class, cqlName(DataTypes.DURATION)),
+ /**
+ * {@code float} CQL type (type {@value DataType#FLOAT} in CQL native protocol) mapped to {@link Float} Java type.
+ */
FLOAT(DataType.FLOAT, Float.class, cqlName(DataTypes.FLOAT)),
+ /**
+ * {@code inet} CQL type (type {@value DataType#INET} in CQL native protocol) mapped to {@link InetAddress} Java
+ * type.
+ */
INET(DataType.INET, InetAddress.class, cqlName(DataTypes.INET)),
+ /**
+ * {@code int} CQL type (type {@value DataType#INT} in CQL native protocol) mapped to {@link Integer} Java type.
+ */
INT(DataType.INT, Integer.class, cqlName(DataTypes.INT)),
+ /**
+ * {@code list} CQL type (type {@value DataType#LIST} in CQL native protocol) mapped to {@link List} Java type.
+ */
LIST(DataType.LIST, List.class, "list"),
+ /**
+ * {@code map} CQL type (type {@value DataType#MAP} in CQL native protocol) mapped to {@link Map} Java type.
+ */
MAP(DataType.MAP, Map.class, "map"),
+ /**
+ * {@code set} CQL type (type {@value DataType#SET} in CQL native protocol) mapped to {@link Set} Java type.
+ */
SET(DataType.SET, Set.class, "set"),
+ /**
+ * {@code smallint} CQL type (type {@value DataType#SMALLINT} in CQL native protocol) mapped to {@link Short} Java
+ * type.
+ */
SMALLINT(DataType.SMALLINT, Short.class, cqlName(DataTypes.SMALLINT)),
+ /**
+ * {@code text} CQL type (type {@value DataType#VARCHAR} in CQL native protocol) mapped to {@link String} Java type.
+ */
TEXT(DataType.VARCHAR, String.class, cqlName(DataTypes.TEXT)),
+ /**
+ * {@code time} CQL type (type {@value DataType#TIME} in CQL native protocol) mapped to {@link Time} Java type.
+ */
TIME(DataType.TIME, Time.class, cqlName(DataTypes.TIME)),
+ /**
+ * {@code timestamp} CQL type (type {@value DataType#TIMESTAMP} in CQL native protocol) mapped to {@link Timestamp}
+ * Java type.
+ */
TIMESTAMP(DataType.TIMESTAMP, Timestamp.class, cqlName(DataTypes.TIMESTAMP)),
+ /**
+ * {@code timeuuid} CQL type (type {@value DataType#TIMEUUID} in CQL native protocol) mapped to {@link UUID} Java
+ * type.
+ */
TIMEUUID(DataType.TIMEUUID, UUID.class, cqlName(DataTypes.TIMEUUID)),
+ /**
+ * {@code tinyint} CQL type (type {@value DataType#TINYINT} in CQL native protocol) mapped to {@link Byte} Java
+ * type.
+ */
TINYINT(DataType.TINYINT, Byte.class, cqlName(DataTypes.TINYINT)),
+ /**
+ * {@code tuple} CQL type (type {@value DataType#TUPLE} in CQL native protocol) mapped to {@link TupleValue} Java
+ * type.
+ */
TUPLE(DataType.TUPLE, TupleValue.class, "tuple"),
+ /**
+ * {@code udt} CQL type (type {@value DataType#UDT} in CQL native protocol) mapped to {@link UdtValue} Java type.
+ */
UDT(DataType.UDT, UdtValue.class, "UDT"),
+ /**
+ * {@code uuid} CQL type (type {@value DataType#UUID} in CQL native protocol) mapped to {@link UUID} Java type.
+ */
UUID(DataType.UUID, UUID.class, cqlName(DataTypes.UUID)),
+ /**
+ * {@code varchar} CQL type (type {@value DataType#VARCHAR} in CQL native protocol) mapped to {@link String} Java
+ * type.
+ */
VARCHAR(DataType.VARCHAR, String.class, "VARCHAR"),
+ /**
+ * {@code varint} CQL type (type {@value DataType#VARINT} in CQL native protocol) mapped to {@link BigInteger} Java
+ * type.
+ */
VARINT(DataType.VARINT, BigInteger.class, cqlName(DataTypes.VARINT)),
+ /**
+ * {@code vector} CQL type (type {@value DataType#LIST} in CQL native protocol) mapped to {@link CqlVector} Java
+ * type.
+ */
VECTOR(DataType.LIST, CqlVector.class, "vector");
private static final Map CQL_DATATYPE_TO_DATATYPE;
+
+ /**
+ * Gets the Java type corresponding to the enum value.
+ */
public final Class> javaType;
+ /**
+ * Gets the CQL type corresponding to the enum value.
+ */
public final String cqlType;
+
final int protocolId;
static {
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java b/src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java
index e11a959..0d11b2a 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java
@@ -18,7 +18,6 @@
import com.datastax.oss.driver.api.core.CqlSessionBuilder;
import com.datastax.oss.driver.api.core.auth.AuthProvider;
import com.datastax.oss.driver.api.core.config.DefaultDriverOption;
-import com.datastax.oss.driver.api.core.config.DriverConfigLoader;
import com.datastax.oss.driver.api.core.config.DriverExecutionProfile;
import com.datastax.oss.driver.api.core.connection.ReconnectionPolicy;
import com.datastax.oss.driver.api.core.loadbalancing.LoadBalancingPolicy;
@@ -28,7 +27,6 @@
import com.datastax.oss.driver.internal.core.connection.ExponentialReconnectionPolicy;
import com.datastax.oss.driver.internal.core.loadbalancing.DefaultLoadBalancingPolicy;
import com.datastax.oss.driver.internal.core.retry.DefaultRetryPolicy;
-import com.datastax.oss.driver.internal.core.ssl.DefaultSslEngineFactory;
import com.ing.data.cassandra.jdbc.optionset.Liquibase;
import com.ing.data.cassandra.jdbc.utils.AnotherFakeLoadBalancingPolicy;
import com.ing.data.cassandra.jdbc.utils.AnotherFakeRetryPolicy;
@@ -351,7 +349,7 @@ void givenInvalidSslEngineFactory_whenGetConnection_throwsException() {
/*
* IMPORTANT NOTE:
- * The resources 'test_keystore.jks' and 'test_truststore.jks' are provided for testing purpose only. They contain
+ * The resources 'cassandra.keystore' and 'cassandra.truststore' are provided for testing purpose only. They contain
* self-signed certificate to not use in a production context.
*/
@@ -359,18 +357,24 @@ void givenInvalidSslEngineFactory_whenGetConnection_throwsException() {
void givenEnabledSslWithJsse_whenConfigureSsl_addDefaultSslEngineFactoryToSessionBuilder() throws Exception {
final ClassLoader classLoader = this.getClass().getClassLoader();
System.setProperty(JSSE_TRUSTSTORE_PROPERTY,
- Objects.requireNonNull(classLoader.getResource("test_truststore.jks")).getPath());
+ Objects.requireNonNull(classLoader.getResource("cassandra.truststore")).getPath());
System.setProperty(JSSE_TRUSTSTORE_PASSWORD_PROPERTY, "changeit");
System.setProperty(JSSE_KEYSTORE_PROPERTY,
- Objects.requireNonNull(classLoader.getResource("test_keystore.jks")).getPath());
+ Objects.requireNonNull(classLoader.getResource("cassandra.keystore")).getPath());
System.setProperty(JSSE_KEYSTORE_PASSWORD_PROPERTY, "changeit");
- final SessionHolder sessionHolder = new SessionHolder(Collections.singletonMap(URL_KEY,
- buildJdbcUrl(cassandraContainer.getContactPoint().getHostName(),
- cassandraContainer.getContactPoint().getPort(), KEYSPACE)), null);
- final CqlSessionBuilder cqlSessionBuilder = spy(new CqlSessionBuilder());
- sessionHolder.configureDefaultSslEngineFactory(cqlSessionBuilder, DriverConfigLoader.programmaticBuilder());
- verify(cqlSessionBuilder).withSslEngineFactory(any(DefaultSslEngineFactory.class));
+ initConnection(KEYSPACE, "enablessl=true", "localdatacenter=datacenter1");
+ assertNotNull(sqlConnection);
+ assertNotNull(sqlConnection.getSession());
+ assertNotNull(sqlConnection.getSession().getContext());
+ assertTrue(sqlConnection.getSession().getContext().getSslEngineFactory().isPresent());
+
+ final Statement statement = sqlConnection.createStatement();
+ final ResultSet resultSet = statement.executeQuery("SELECT * FROM system.local");
+ assertNotNull(resultSet);
+ resultSet.close();
+ statement.close();
+ sqlConnection.close();
}
@Test
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/UsingCassandraContainerTest.java b/src/test/java/com/ing/data/cassandra/jdbc/UsingCassandraContainerTest.java
index dc3c010..b3cad8b 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/UsingCassandraContainerTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/UsingCassandraContainerTest.java
@@ -19,6 +19,7 @@
import org.testcontainers.containers.CassandraContainer;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.testcontainers.utility.DockerImageName;
+import org.testcontainers.utility.MountableFile;
import java.net.InetSocketAddress;
import java.sql.DriverManager;
@@ -37,6 +38,10 @@ abstract class UsingCassandraContainerTest {
static final CassandraContainer> cassandraContainer = new CassandraContainer<>(CASSANDRA_IMAGE)
.withEnv("CASSANDRA_DC", "datacenter1")
.withEnv("CASSANDRA_CLUSTER_NAME", "embedded_test_cluster")
+ .withCopyFileToContainer(MountableFile.forClasspathResource("cassandra.keystore"),
+ "/security/cassandra.keystore")
+ .withCopyFileToContainer(MountableFile.forClasspathResource("cassandra.truststore"),
+ "/security/cassandra.truststore")
.withConfigurationOverride("config_override")
.withInitScript("initEmbeddedCassandra.cql");
@@ -59,7 +64,7 @@ static void initConnection(final String keyspace, final String... parameters) th
static CassandraConnection newConnection(final String keyspace, final String... parameters) throws Exception {
final InetSocketAddress contactPoint = cassandraContainer.getContactPoint();
- return (CassandraConnection) DriverManager.getConnection(buildJdbcUrl(contactPoint.getHostName(),
+ return (CassandraConnection) DriverManager.getConnection(buildJdbcUrl(contactPoint.getHostName(),
contactPoint.getPort(), keyspace, parameters));
}
diff --git a/src/test/resources/cassandra.keystore b/src/test/resources/cassandra.keystore
new file mode 100644
index 0000000000000000000000000000000000000000..46c4628673d4c1cc03f2e47fee8a71fadf1c7379
GIT binary patch
literal 2734
zcma)8S5y-S7EK_903sbUOOt`2C?rIxK|v(a2P8ygAP}UgG!qDnfD%d=X#%0k0BYz4
z>0QP!lpsQoA{}W$s7eM!KpFPz9%uJ!_v4-W-hJ=h&wCz%!e7P%@NbnMKai(@0ya7#(Fo7)3h*(+
zb%fsEqaZ>ZBtGkryM_XMn^^6Bu1e?qsQFoh?8?LQqc9Ip9w7+f`K5Ks*yYy$;~J~Usn&Ezf&2bQ^0K@<>sw~BPC40Pi7z8=<0Cz%UyRC-j
zMdSL}_Sc7dsf6*wUQCFy#HrfP(2*EB&eenFcX1J>WmUI#bswH=yxrLsj54rBE9-p<
z&E=FlC!DKIF9>w1*g?Czx~yU84~9eMOO4}*x(}X?7y!w+YxHH_s<6$n-}~N%eQ_AK
zbt?8!c7Vtk~#JHWNo
zpQ_athpU0YtCYFvBJVNkc9KF9jb?X?Ki}mQd#70MkS*OZCO8t#lK&=mh&_;UnmD{)
zL7iij2HIAU?nJaz*q7G_b^n?!5VZi~0RJ2@{lPhU+s-pF)$!gRC5x#|X~9A?X45PZ
zPlNy`WgE9C^pef^i})T@d6jR>*@2yShz{
zZO4<`=&u0^Xxse&uXnaG#)rEhD%`oJ8uV1R1^9al2)-b~XTHyYs$U`ZHkp#D^@-%qO3ybm)
zI@zAw)YfJpIi1tDm`g8byu%jgu7HOTd$8Lpf!g|BOBHR
ztxF!=ERbu11@CMtHwAh^i(2~FcTd-d5ROQA-zjgUQ1=|_#FPAFy`ghR#Ct!W5LVNyGj9_7u8!im2YG@OIrsQRef-{
zb;;u5n1XACNDM;ZdtAcAk>awVfZG6nzzqQ52)&OwB7pRtClW|;kSNy2*FzquqpyuX
z>7Ug?ptO((3Mlfs4-`^B0o^&G{CI$XBk=lr1N>iMZ3%afgEj@!3;Eek7|s3Ba&y&o
z{r?H;vSbaz`GM_(K$^Qop~;y2eG2b~E8hH5wWZ+(QZU?zrTe_wJ5G&?LWPLiIdUT-
zBUgQMXGPE}DU)*3wf`CZ`kUiAt6l0&?Z%@F9reBN#hwvVl=Xuqy)NKWs5vYPW1B>nZPi974gib9i;K~OTaGS<^i
z>)yAa;9{cI*JYLsedQBN_rtLl*#U`P6q_soT`r5kWeFZ_R;{P&=J=DJ^Pn18kJeMr
zjN_Z;%~bi(OeVPnEa&GF1T5{&Re$QhS6}0VOWH}G?s4_1II#O!>W%`|FQ$fa${&YxeiZI3##;i67k4ag$dwxAg26+=$iT1bs5_f|t0IY5u
zma`PcwDCLa?`f;4_!Dod1Om4`1=D)oorzdBMUq_7Mk*Gqz-4`ThDxs6-IJ&ER2IhU
zEF=ulbKV;v;hXkAws61by~}aU7e#ty3y<9^p7Ak}XUC1pvBxV$)&CK9Nbu!97|qaW
zgKaHt6g#Gb(6r+t>BSMsFk#&%<)M#@LobI|k@9WMP}T%A7~2e)K3)v_=^6ani7B`Dp;LPCO?guGLHbGlbREz{Ylq(@usq
zt9V~F?c*+|4vn__-rh(Z?hFzI!w7B*4H9NG7Bal)_uC}F)7VsMf9-Sx324PwswcW&AI9l6Di}?ynurE^_B?!RJlXj$>7I
z6U6tT2666Zs_e2=n!Z(bD9zs3f-6Vk^7~#MTHRVNwN9`5%B|uTODCt~zxtbCIVYxIlWw*Gm7G}M$=*Tf?
z`BHn|!s_Q}xqQo_ch-9<>$OfYIbT|(AH&%BGqA$a#@{c!CFW0B;z6{`P;&2_L9|BE
zG=QKpWUvrVzxuO-RE;UG^H&D0BEJqd&}(b&K9yObC#Ll1VM7&LNQU+thDZTr0|Wso1Q6?+pKZ2afLx1J3ONVuy@Y^*1K`Gzie@|>F^6IuE7xDcO_j0s
z{76d7MnUL6QYpFaMxq7)_EeLCznS$b1wZ+}h<5F!gsJ(^?zAc=P~=(B_oI&Gv$-d~s~tM93GmSj
z&>`pIT4ir(R9=L{I5T$Q$~Sim;uKFhTu`QJZ6E
z=oo1`#7^qCPwU6B)62|YbS&fcmJqD&9s&D$sPy2u9K*}?fylbKomE}2K^^Dc0!Ieq
z=poG2@rNC1`@9}_{LYv=T4I%C6xetCexa4VwW|BQEp6C(C2d7s);GIl{|WE!^9~
zwK_=hc4VB63abuK_?JIy9Wm-c<}`%ha9ZZ3^!?rebK#*!Z9vz$E&WC;)!+
zoSZUW%&;D)p-;wvsyARvh?o73cIMTl{fxuxLO`y%njsBxt$!(#(iKthox632f)%y+
z!%iTkquAH(v;H3xQMyy!sdd7i%^v@iXDKpBh9Uh
z!kNttuO!qiiQ4Rh=X2UvmRD0RT3AY%BcldYyitsN1wLWLhtHw5;v+O?Phl9aOy6mo
z+J4B+6Z|OF9AcRDG80s7ond0?m+gMwFdz9IxeD?bG3Jo%gfw?{elil|XQc5$>Vx2s
z6xrJH7g_rEsd)|6pF>D!O*lJzc89g^bJR+C+37#RZI5+(ntiD@#I(cXi2jgdzIoMc
zwv<7=FN%#;^A3%O>b#vd_Mil}K@nk3Mk8DnMFKTx5}|z8wc00Sw=hm0+s$6LlgW&E
zSD;8Ns^*!K%;;E83IS)IUaA(9?TI)4XN9V8#m&1#!Nu921!>4#9tgG8A2v%JC=Ti=
zeD&n^oW*@BeH{+xF@pOS|AB$%-Zb^(h$SB~Njk{j97h4C1nPGQYH3s-jn7fODq5ez
z=rguG8?fr)`G%!~p8GY{P&=>(IwH2!+zt$W7Pf9|cl#A&2R(m1#0(6{ezo6~hy=V_Y)8<990uUz?`z@rY_N6t$8R3<
zK8jL4pLvpPd*gNU;eZMtuCjCEcF49xqw7QD@+l?euLnLAP?lhj!iFzzEll-qofXjk
zl@Bh{8Bd}FXG}NBjY`RYqv6$7l+q|{Bioy?x8wMWw_Er3K>E*aZ}f;<7TEfNGU8ux
z=Rh|Y1I04%Ru$yiKJ?7vGbwmUa138F6XAc{V5zHZpGB{_Mu{*@FflL<1_@w>NC9O7
z1OfpC00ban{TgksqKjUPRK{9vLeCE})>LG9$#j?QHib@`5=~No&kXkyWJ0zA4mjT6TS7E!v;r8p4j^@fzsr**{A$Ojif56sqaH3N0no|0w
z!#~J|Z(b$$+txZ{vsBh1y47Ak4j&bvGX0*S#{HivBBr3TbO}~-8>Qf5m-w`a^qs-Q
z0}S0=9OrIIm`xJ{ZE?;W$w3JER!&eSn$2aMt?!#WCy(OlsuAT6(}$YSAGv2J;lNstt<8VF5&l*t67+sE$3!g|?X
z7tOR0>bU1?j}abYRj&X)8QC
zBQhk7{;ZZpqvB_-Li44DlJIGP{^<9IQ|(TkJGP0wdFCN83x0N;X=MT1;i6$Xf4zSs
z73vK`f2u03?o>di$=z)K(bFH$J?}DO&W3Z?m?9`!5g{pIudcsdKOupUfa#)w%el(2~h8z;5oSZAD)#ToAB5pOx+l}7<%qpP5v;e=OqgG>CiNvoCl
z%XhA(CtklKRL2rX%ZtRR8V3pSN}!U+xhh<-VOyd=hEFP0M(cib%omMj3s4_(Wav
z0$=jkF$>MB_?Qq!5y_x(oq`wWJ>>lvxwnTp!OeV^pHJT{zIs*w5?_``=B$bQ6)yB%By?=cLWTusHBPKro6WHGnv2nU`NT|x^+-{7
zqH0s1zDTG(B|y`wv!ZNaDK5~=UgPcO)Vkec+g*^-2TRkR33;z9XQ3H*i<{+y*K%@F
z@uf_W~yodSd1-+BL0TrSL|-lV6sCBvP1lekIZ+K)gZ*pLoUWW_G(KjM?BAApzyP=OF`JbY~Ho)O63H4cwsAZovi3W9H+>HPPb(!AYu#6kV*I5t9S
z@tCn27ivp2!fn5Xp50#+3v=qYgt5(4H|nV}2?q206RnB;WDpdhzlwD#XMydPX9S=A
z;u{|V8o!b)E-9fhIbKbNAV(UJi$}7*8|pj~DqT?92^Wi7T`SI&PA3OlPJH-TwYn;*
zi8M-*Nfzu$LqB+*+8uUCC=Pfr3RKYRUyk{=|LnC(R2ES%>T+&3tYMcsX&Q)M$eho(
zddEHyX)5hLn3c8vt2RacPIQa0=ikwtC{|urSb2i1^dB(n>60WyiDxy3Ws(89Vcii#RYsO`RTJ#LTtBR*(nTF6hG5xT6iJYeMj&5W)v#$
zblYaEfj`sRk}%*X1QPcZ%)*n-lldcirB}f_yDHAwJD=NX!A&fZBav!jo6JUKn)D#I
zliP!JuEeY?SFB!T)!LF7F{IdJ9)xN)l6LvS)rel?sE~|$)6n{eTkYt#@~ScY1%8#EUpP
zQTQS~C10r$G}u8|g(0YI(@Qt0{z3kz)|JOt`^q|LQ~UOLJ<1NX)5yxg
z@Py98-umJ)r9Nb6V-2)^U|yopCmObeim>eqMaAKQJ9Q59&iSoXt9i(|`A)&tE=D9cg{7wY{EbrS3hn2b^Q--La8}gG{lC9qoydj0s3V0hpYKw54SX9|L@n$j
z+x7Mmo&JI(y%anSD-OSHYL8dSTe$H_GofVp?$Z2=;R*G&C{x=Z;Oo@v-t6TAf`~tN
zsRjEv8ubG$Utj2tk|0xIlY=mH{^Fj`!CiWvKRIQQ6NVgi#EAr?J8q27xfhrOAk3XL
zLS<{+HIC|%0bU1yKfof67Ve&jkSl$3*2b(@!eSZ;aX&c0A|RJ7VO6c12Ulsb^$$fO
zM~u%CHC@e%bBv(Vq6Zl~92m8rIlFO#Yous^C(Jj;~J7=9r*eLx)nSG0ag%kIY7G5~#)h4hBY0PNOGO+$IXt0jhO{TTOTA%}t}u$3
zJA&Fb9LPOGizlN&z3gDuFF76~?=$J7R6JN^dDK)qO7z|$_Uz_KdPaPX_SV20bq+xZ
zQH|>oYDGiPVcoA~j(rFZYIV1a{SULeZsOW2>RJ*VhZ6HYhoE8F&a0wgWm}vep3=v|
za+WXvaofo3K6qpAfhsTf5Ve*ZLGMMk3$SPxRvdNqxV8iZ9#`rz*K<61jo>Io2uaaY
zUtDd7bqfGX#BBI;B+IskUtVS
zfIc@#{H^$;LLC}q0)d?@98aJ?!t%NkHhYXGKF?-~`6lq9;ES4ZotQ@FFj3|;Y3MxUdg#I!Ty
zxNG9X%@ffy-QRP)z)z45JMi0Jb?)%;;_=doE6&`P>ZyI^d2|PHBxt17wHLpmDZLvd
zsUzRp1OII{5~z%#dhxUD=!p^4IQB!MLP_D!nw%T?GFzM}dn)qsZu-1^AUq%7;l=i(?Co3?6G
zme<{j6>K|%f8wIFmn!$oTHDjKfgW}i4EG(1ow#G8c9&~1RuCe^g&TwKNo0~`#^)1_
zzIbe|%gNJ9j{InA2mUQG{>&6W_=9oM$Rg^n?j9(gy@tA()4^hFT%7e
zm{ilH3cIPDrYJZ1R#!KS@cZ0oK=zd)t}*3;0?yC;A?SK517_TnxMJo&^q$?h%OMR0
zAf&QE0*h8?D}SeF<&njTE-gjVnabH_o=rNYR-9p-ERGTG3j=(f_dWH+KE$Srt$C{y
zu*7bl`KIPhGmmFL4f!lO(>GQkc{+2&tsjB|T)4{ugNy%p5BSIynAkLYEB)!w`aSg3
zIKjb``0uR#OB%Ow!oxuyC)`oKp~2bVSC)QS((N4Zl?1hf=tCCl6c_x2Ci8x^clI0U
z^J*KT63Xto9XSM!5eY)SBX7y89acBfURnLcr`2~mMNUo}K^l}iveg;09wB)%EOQlw
z6qilWP+{>jC-odeEHy63*OxlHA>uj+^VNz{eturP79AUC+V(<%j6w)wBPu{jLkQ9m
zcV@Wu9x`_$BFb`*d({$}!1YDm8+Od<#>m8~WW14L1W7}Dxgv_BR$D9=+AAeu6I$Zg
z<^@vAAzpRA@%;*X6v|4r=5W@@$+pX-@zm-!Wv389Lq~l*+_}y4PgtIr{5+@TG18bp
zD*;L^7Y)}{ge+7RP-x_eBrrRzXX3RSiu!Fby2!;H=;ZX-q#!bIr}w>lZji*`-M@PE
zG|BlNe4T!sZNat?zBe)UmBs8gL#^b5Z5$8&E|kmtnGa{w^HYWDH(dyMuJecX^Ll~v
zcS(789bky;1h{ss>|sT*H#`6+sf~
zO0)oCyu|pby(+7N3c}b6M|GPYNbu
zuz)B>#B%rxlDQ!uG7ewRavUVpMKE)v85~Vt#`gmDla9BB-33T4S
zl%|y|T7ew*_#2CLP_=3obv)8j%NhkW5^#R%m%-=E3%4ni?5Gr?dgM!-4UMG?<8d^1
z^(OC1piq60G15-b_Xv&G%khOPQVX8q2KIo95yjsoZE4p+hsj#s>oGyaB!=tc{55>E
z=B7=0lADH9r*$hHP-ClZ2GB6qh0SIMj_3U;X0pIUpX!r5KzJm?BBt9egfr$#IPmpK
zaNCZeh_$S5v8dI+jj-mqnf6_g&PEX{?d2dwR4`2PCOTG9E%nKA#QLYlg1fVtlh`9|
z8N2-I+cvcl+Jq%0on71~WnpRee&(tlCbM~=KE9VQ$C4q>+Is&&A>q^Uw$10=p
zCI!U-(f!dE!VyQ7J@dDgQSB{q0BCkZcj4EoA_I}gY
z@dmV{@6jF+RI00aqc8BCJY;2N$eS}A&WX@apaKRbO8Bm9XqmTmC8)j9S+(#mY1OsJ
zk}H+cBi3cyyTZh--?{s$2{2Z1Djn4s-=2+p^djZy7R=W7D32vLZSe7})Mt(PsGxnV
zpCgW)iR~{FG-0C#>rq?|C0%wuq*Xp@GVU~^snRw4YVMQCE|iP{hC8)vm0^*AntrM@
zqz&CABMH+IHHd9D{lOkm<<~6QN)}OuxmnWPJa-
zZ2sT}OM^jRTr40L5e7Of5P(S`$B?q&s#wa{Ty_q$UW%y}ebez0lj66Kt#J_*bnh1M
T_1?K_(cIPCs~a5yExO=eG*hui
diff --git a/src/test/resources/test_truststore.jks b/src/test/resources/test_truststore.jks
deleted file mode 100644
index faacea8da4d9ab604a12d1ee630b3dce3bf778a9..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 1330
zcmV-21}f(0%D0Ru3C1m^|`Duzgg_YDCD0ic2e*aU(E)G&es&@h4o%mxW6hDe6@
z4FLxRpn?RwFoFcR0s#Opf&{V#2`Yw2hW8Bt2LUiC1_~;MNQU^InZ-Rr_fRRr
zdjQbE)9Mo3D^tcO{^(-Onp5GVdzTi4!3rz6J)NiI29R-TSm%JEf8gZ8Ry@b?WXw5g
zH|_#h7uOFMY@8@(q)>ST0UvtTYa}KiLH#Jz#fZThqshE>QAMy(9fe$^?O1;+-S7qo
zqSi)hrLVO({N(?SJeX-up}E`jCt6|AJrT9^kfb7C{~bTG9YZc}WO-0|3s^R>F78Hq
z?*s!q==wX-@HCYhji9XJ5TS*e7ym^1)jN!mJ~?_%Z`Y1(2lHDu@f3;Z(i@_H>qW
zVw~Q_;djdk
zv5Xu%V&~$9cSKJpLcu*OruTc01@Z#-QaA2PiB8?ODNM|VkTroL%nh3rDV{1g}NHKfv>LTi!YsKtz
z2p&vpJXgJJa8^Z)m*9VP6>y?*;^P;o6q3Y7Nv$7YYBJL3>@9?u=%_?PDw0a_VL;6H
zl`HNktoRV+MAYWk{}ZjYR>yPFC-P;h^y5Vnku#3h#eY9rQr^eB}EF`g3KjX|{GOtvu{T=fEi
z`}S7|ODqBri26@yDJUY?m1osY^^JwE#T0pLwd|%t6$O~Z!`~at0tnVS$}9i@8i`pr
zza8@si>SzA*uhCB0B9bb)jubXw6ojNTATZLD-tAgW|2fWiW(xAeA5BDJIZDsi@tfD
z8C-{3+N$J!omQqX$$js;x%jxn1S_N@128@?AutIB1uG5%0vZJX1QZcyCXeRXcVfVu
oEP
Date: Mon, 18 Sep 2023 15:09:39 +0200
Subject: [PATCH 17/21] Remove org.apache.cassandra2.cql.jdbc package
---
CHANGELOG.md | 3 +++
.../ing/data/cassandra/jdbc/utils/package-info.java} | 12 ++----------
2 files changed, 5 insertions(+), 10 deletions(-)
rename src/main/java/{org/apache/cassandra2/cql/jdbc/CassandraDriver.java => com/ing/data/cassandra/jdbc/utils/package-info.java} (65%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 57ca8f0..d986a50 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Update Apache Commons Lang to version 3.13.0.
- Update Jackson dependencies to version 2.15.2.
- Packages refactoring: utility classes, types and database metadata management have been moved to dedicated packages.
+### Removed
+- Remove the legacy package `org.apache.cassandra2.cql.jdbc`: only `com.ing.data.cassandra.jdbc.CassandraDriver` should
+ be used now as `java.sql.Driver` implementation.
## [4.9.1] - 2023-09-03
### Fixed
diff --git a/src/main/java/org/apache/cassandra2/cql/jdbc/CassandraDriver.java b/src/main/java/com/ing/data/cassandra/jdbc/utils/package-info.java
similarity index 65%
rename from src/main/java/org/apache/cassandra2/cql/jdbc/CassandraDriver.java
rename to src/main/java/com/ing/data/cassandra/jdbc/utils/package-info.java
index c7eaee0..0f858b2 100644
--- a/src/main/java/org/apache/cassandra2/cql/jdbc/CassandraDriver.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/utils/package-info.java
@@ -1,5 +1,4 @@
/*
- * Copyright (C) 2012-2015 DataStax Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,14 +13,7 @@
* limitations under the License.
*/
-package org.apache.cassandra2.cql.jdbc;
-
-import java.sql.Driver;
-
/**
- * The {@code CassandraDriver} class.
- *
- * @see com.ing.data.cassandra.jdbc.CassandraDriver
+ * This package contains utility classes used by the JDBC wrapper.
*/
-public class CassandraDriver extends com.ing.data.cassandra.jdbc.CassandraDriver implements Driver {
-}
+package com.ing.data.cassandra.jdbc.utils;
From 236928ecb478e228ee65804c3a1587a71be7a7d4 Mon Sep 17 00:00:00 2001
From: Maxime Wiewiora <48218208+maximevw@users.noreply.github.com>
Date: Sat, 23 Sep 2023 15:08:31 +0200
Subject: [PATCH 18/21] Implement
CassandraDatabaseMetaData.getBestRowIdentifier()
---
.github/workflows/ci-workflow.yml | 2 +-
.github/workflows/release-workflow.yml | 4 +-
CHANGELOG.md | 2 +
.../jdbc/CassandraDatabaseMetaData.java | 5 +-
.../AbstractMetadataResultSetBuilder.java | 2 +
.../TableMetadataResultSetBuilder.java | 105 ++++++++++++++++++
.../jdbc/MetadataResultSetsUnitTest.java | 51 +++++++--
.../utils/AnotherFakeLoadBalancingPolicy.java | 6 +-
.../jdbc/utils/FakeLoadBalancingPolicy.java | 4 +-
src/test/resources/initEmbeddedCassandra.cql | 7 ++
10 files changed, 168 insertions(+), 20 deletions(-)
diff --git a/.github/workflows/ci-workflow.yml b/.github/workflows/ci-workflow.yml
index 61ab7c1..83b53ee 100644
--- a/.github/workflows/ci-workflow.yml
+++ b/.github/workflows/ci-workflow.yml
@@ -13,7 +13,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 8
uses: actions/setup-java@v3
diff --git a/.github/workflows/release-workflow.yml b/.github/workflows/release-workflow.yml
index 18d9f11..a796de6 100644
--- a/.github/workflows/release-workflow.yml
+++ b/.github/workflows/release-workflow.yml
@@ -11,7 +11,7 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Set up JDK 8
uses: actions/setup-java@v3
@@ -39,7 +39,7 @@ jobs:
run: echo "RELEASE_VERSION=$(mvn help:evaluate -Dexpression=project.version -q -DforceStdout)" >> $GITHUB_ENV
- name: Create GitHub release
- uses: ncipollo/release-action@v1.12.0
+ uses: ncipollo/release-action@v1
with:
artifacts: "target/cassandra-jdbc-wrapper-${{ env.RELEASE_VERSION }}-bundle.jar"
name: "${{ env.RELEASE_VERSION }}"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index d986a50..fadcdaf 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,6 +9,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Add support for new [`vector` CQL type](https://datastax-oss.atlassian.net/browse/JAVA-3060)
defined in [CEP-30](https://cwiki.apache.org/confluence/x/OQ40Dw).
- Implement the method `getWarnings()` in `CassandraResultSet`.
+- Implement the following methods of `CassandraDatabaseMetaData`:
+ `getBestRowIdentifier(String, String, String, int, boolean)` and `getAttributes(String, String, String, String)`.
### Changed
- Update DataStax Java Driver for Apache Cassandra(R) to version 4.17.0.
- Update Apache Commons IO to version 2.13.0.
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
index ca33de8..f31acd0 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
@@ -131,8 +131,11 @@ public ResultSet getAttributes(final String catalog, final String schemaPattern,
@Override
public ResultSet getBestRowIdentifier(final String catalog, final String schema, final String table,
final int scope, final boolean nullable) throws SQLException {
- // TODO: method to implement into TableMetadataResultSetBuilder
checkStatementClosed();
+ // Only null or the current catalog (i.e. cluster) name are supported.
+ if (catalog == null || catalog.equals(this.connection.getCatalog())) {
+ return new TableMetadataResultSetBuilder(this.statement).buildBestRowIdentifier(schema, table, scope);
+ }
return CassandraResultSet.EMPTY_RESULT_SET;
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/metadata/AbstractMetadataResultSetBuilder.java b/src/main/java/com/ing/data/cassandra/jdbc/metadata/AbstractMetadataResultSetBuilder.java
index 6b9ab5f..bfb0c12 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/metadata/AbstractMetadataResultSetBuilder.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/metadata/AbstractMetadataResultSetBuilder.java
@@ -82,10 +82,12 @@ public abstract class AbstractMetadataResultSetBuilder {
static final String PAGES = "PAGES";
static final String PRECISION = "PRECISION";
static final String PRIMARY_KEY_NAME = "PK_NAME";
+ static final String PSEUDO_COLUMN = "PSEUDO_COLUMN";
static final String RADIX = "RADIX";
static final String REF_GENERATION = "REF_GENERATION";
static final String REMARKS = "REMARKS";
static final String SCALE = "SCALE";
+ static final String SCOPE = "SCOPE";
static final String SCOPE_CATALOG = "SCOPE_CATALOG";
static final String SCOPE_SCHEMA = "SCOPE_SCHEMA";
static final String SCOPE_TABLE = "SCOPE_TABLE";
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/metadata/TableMetadataResultSetBuilder.java b/src/main/java/com/ing/data/cassandra/jdbc/metadata/TableMetadataResultSetBuilder.java
index 6a78693..b7346f4 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/metadata/TableMetadataResultSetBuilder.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/metadata/TableMetadataResultSetBuilder.java
@@ -20,18 +20,28 @@
import com.datastax.oss.driver.api.core.metadata.schema.IndexMetadata;
import com.ing.data.cassandra.jdbc.CassandraMetadataResultSet;
import com.ing.data.cassandra.jdbc.CassandraStatement;
+import com.ing.data.cassandra.jdbc.types.AbstractJdbcType;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
+import java.sql.Types;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Map;
+import static com.ing.data.cassandra.jdbc.types.AbstractJdbcType.DEFAULT_PRECISION;
+import static com.ing.data.cassandra.jdbc.types.TypesMap.getTypeForComparator;
+import static java.sql.DatabaseMetaData.bestRowNotPseudo;
+
/**
* Utility class building metadata result sets ({@link CassandraMetadataResultSet} objects) related to tables.
*/
public class TableMetadataResultSetBuilder extends AbstractMetadataResultSetBuilder {
+ private static final Logger LOG = LoggerFactory.getLogger(TableMetadataResultSetBuilder.class);
+
/**
* Constructor.
*
@@ -276,4 +286,99 @@ public CassandraMetadataResultSet buildPrimaryKeys(final String schema, final St
return CassandraMetadataResultSet.buildFrom(statement, new MetadataResultSet().setRows(primaryKeys));
}
+ /**
+ * Builds a valid result set of the description of a table's optimal set of columns that uniquely identifies a row.
+ * This method is used to implement the method
+ * {@link DatabaseMetaData#getBestRowIdentifier(String, String, String, int, boolean)}.
+ *
+ * In Cassandra, all the tables must define a single primary key and the columns defining this primary key
+ * ensure the uniqueness of each row. So, we consider in this implementation that the best row identifier for
+ * a table is always its primary key regardless of the specified scope. Also, the parameter {@code nullable} has
+ * no effect here since Cassandra does not allow null values in primary keys.
+ *
+ *
+ * Only identifiers for tables matching the catalog, schema and table name criteria are returned. They are
+ * ordered by {@code SCOPE}.
+ *
+ *
+ * The columns of this result set are:
+ *
+ * - SCOPE short => actual scope of result:
+ *
+ * - {@link DatabaseMetaData#bestRowTemporary} - very temporary, while using row
+ * - {@link DatabaseMetaData#bestRowTransaction} - valid for remainder of current transaction
+ * - {@link DatabaseMetaData#bestRowSession} - valid for remainder of current session
+ *
Always the input scope value.
+ *
+ * - COLUMN_NAME String => column name.
+ * - DATA_TYPE int => SQL type from {@link Types}.
+ * - TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully
+ * qualified.
+ * - COLUMN_SIZE int => column size.
+ * - BUFFER_LENGTH int => not used: always 0 here.
+ * - DECIMAL_DIGITS int => the number of fractional digits, {@code null} is returned for data
+ * types where it is not applicable. Always {@code null} here.
+ * - PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID:
+ *
+ * - {@link DatabaseMetaData#bestRowUnknown} - may or may not be pseudo column
+ * - {@link DatabaseMetaData#bestRowNotPseudo} - is not a pseudo column
+ * - {@link DatabaseMetaData#bestRowPseudo} - is a pseudo column
+ *
Always {@link DatabaseMetaData#bestRowNotPseudo} here since there is no concept of pseudo
+ * column in Cassandra.
+ *
+ *
+ *
+ *
+ * @param schema A schema name pattern. It must match the schema name as it is stored in the database; {@code ""}
+ * retrieves those without a schema and {@code null} means that the schema name should not be used to
+ * narrow the search. Using {@code ""} as the same effect as {@code null} because here the schema
+ * corresponds to the keyspace and Cassandra tables cannot be defined outside a keyspace.
+ * @param table A table name. It must match the table name as it is stored in the database.
+ * @param scope The scope of interest, using the same values as {@code SCOPE} in the result set.
+ * @return A valid result set for implementation of
+ * {@link DatabaseMetaData#getBestRowIdentifier(String, String, String, int, boolean)}.
+ * @throws SQLException when something went wrong during the creation of the result set.
+ */
+ public CassandraMetadataResultSet buildBestRowIdentifier(final String schema, final String table, final int scope)
+ throws SQLException {
+ final ArrayList bestRowIdentifiers = new ArrayList<>();
+
+ filterBySchemaNamePattern(schema, keyspaceMetadata ->
+ filterByTableNamePattern(table, keyspaceMetadata, tableMetadata -> {
+ for (final ColumnMetadata columnMetadata : tableMetadata.getPrimaryKey()) {
+
+ final AbstractJdbcType> jdbcEquivalentType =
+ getTypeForComparator(columnMetadata.getType().toString());
+
+ // Define value of COLUMN_SIZE.
+ int columnSize = DEFAULT_PRECISION;
+ if (jdbcEquivalentType != null) {
+ columnSize = jdbcEquivalentType.getPrecision(null);
+ }
+
+ // Define value of DATA_TYPE.
+ int jdbcType = Types.OTHER;
+ try {
+ jdbcType = getTypeForComparator(columnMetadata.getType().toString()).getJdbcType();
+ } catch (final Exception e) {
+ LOG.warn("Unable to get JDBC type for comparator [{}]: {}",
+ columnMetadata.getType(), e.getMessage());
+ }
+
+ final MetadataRow row = new MetadataRow()
+ .addEntry(SCOPE, String.valueOf(scope))
+ .addEntry(COLUMN_NAME, columnMetadata.getName().asInternal())
+ .addEntry(DATA_TYPE, String.valueOf(jdbcType))
+ .addEntry(TYPE_NAME, columnMetadata.getType().toString())
+ .addEntry(COLUMN_SIZE, String.valueOf(columnSize))
+ .addEntry(BUFFER_LENGTH, String.valueOf(0))
+ .addEntry(DECIMAL_DIGITS, null)
+ .addEntry(PSEUDO_COLUMN, String.valueOf(bestRowNotPseudo));
+ bestRowIdentifiers.add(row);
+ }
+ }, null), null);
+
+ // All the rows of the result set have the same scope, so there is no need to perform an additional sort.
+ return CassandraMetadataResultSet.buildFrom(statement, new MetadataResultSet().setRows(bestRowIdentifiers));
+ }
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/MetadataResultSetsUnitTest.java b/src/test/java/com/ing/data/cassandra/jdbc/MetadataResultSetsUnitTest.java
index 188353d..22ca4cd 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/MetadataResultSetsUnitTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/MetadataResultSetsUnitTest.java
@@ -26,6 +26,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
@@ -60,7 +61,7 @@ static void finalizeSetUpTests() throws Exception {
*/
@Test
- void givenStatement_whenMakeTableTypes_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildTableTypes_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new TableMetadataResultSetBuilder(statement).buildTableTypes();
assertNotNull(result);
@@ -70,7 +71,7 @@ void givenStatement_whenMakeTableTypes_returnExpectedResultSet() throws SQLExcep
}
@Test
- void givenStatement_whenMakeTables_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildTables_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new TableMetadataResultSetBuilder(statement).buildTables(null, null);
assertNotNull(result);
@@ -135,12 +136,40 @@ void givenStatement_whenMakeTables_returnExpectedResultSet() throws SQLException
assertThat(foundTables, hasItem(is(ANOTHER_KEYSPACE.concat(";cf_test1;TABLE;First table in the keyspace"))));
}
+ @Test
+ void givenStatement_whenBuildBestRowIdentifier_returnExpectedResultSet() throws SQLException {
+ final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
+ final ResultSet result = new TableMetadataResultSetBuilder(statement)
+ .buildBestRowIdentifier(KEYSPACE, "cf_test3", DatabaseMetaData.bestRowTemporary);
+ assertNotNull(result);
+ assertEquals(8, result.getMetaData().getColumnCount());
+ assertEquals("SCOPE", result.getMetaData().getColumnName(1));
+ assertEquals("COLUMN_NAME", result.getMetaData().getColumnName(2));
+ assertEquals("DATA_TYPE", result.getMetaData().getColumnName(3));
+ assertEquals("TYPE_NAME", result.getMetaData().getColumnName(4));
+ assertEquals("COLUMN_SIZE", result.getMetaData().getColumnName(5));
+ assertEquals("BUFFER_LENGTH", result.getMetaData().getColumnName(6));
+ assertEquals("DECIMAL_DIGITS", result.getMetaData().getColumnName(7));
+ assertEquals("PSEUDO_COLUMN", result.getMetaData().getColumnName(8));
+ final List foundColumns = new ArrayList<>();
+ int resultSize = 0;
+ while (result.next()) {
+ ++resultSize;
+ foundColumns.add(String.join(";", result.getString(1), result.getString(2), result.getString(3),
+ result.getString(4), result.getString(5), result.getString(6), result.getString(7),
+ result.getString(8)));
+ }
+ assertEquals(2, resultSize);
+ assertThat(foundColumns, hasItem(is("0;keyname;12;TEXT;2147483647;0;null;1")));
+ assertThat(foundColumns, hasItem(is("0;t3ivalue;4;INT;11;0;null;1")));
+ }
+
/*
* Catalogs metadata
*/
@Test
- void givenStatement_whenMakeCatalogs_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildCatalogs_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new CatalogMetadataResultSetBuilder(statement).buildCatalogs();
assertNotNull(result);
@@ -154,7 +183,7 @@ void givenStatement_whenMakeCatalogs_returnExpectedResultSet() throws SQLExcepti
*/
@Test
- void givenStatement_whenMakeSchemas_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildSchemas_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new SchemaMetadataResultSetBuilder(statement).buildSchemas(null);
assertNotNull(result);
@@ -183,7 +212,7 @@ void givenStatement_whenMakeSchemas_returnExpectedResultSet() throws SQLExceptio
*/
@Test
- void givenStatement_whenMakeColumns_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildColumns_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new ColumnMetadataResultSetBuilder(statement).buildColumns(KEYSPACE, "cf_test1", null);
assertNotNull(result);
@@ -372,7 +401,7 @@ void givenStatement_whenGetMetadataIsSearchable_returnExpectedValues() throws Ex
*/
@Test
- void givenStatement_whenMakeUDTs_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildUDTs_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new TypeMetadataResultSetBuilder(statement).buildUDTs(KEYSPACE, "CustomType1",
new int[]{Types.JAVA_OBJECT});
@@ -405,7 +434,7 @@ void givenStatement_whenMakeUDTs_returnExpectedResultSet() throws SQLException {
}
@Test
- void givenStatement_whenMakeUDTsWithNonJavaObjectTypes_returnEmptyResultSet() throws SQLException {
+ void givenStatement_whenBuildUDTsWithNonJavaObjectTypes_returnEmptyResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new TypeMetadataResultSetBuilder(statement).buildUDTs(KEYSPACE, "CustomType1",
new int[]{Types.STRUCT, Types.DISTINCT});
@@ -414,7 +443,7 @@ void givenStatement_whenMakeUDTsWithNonJavaObjectTypes_returnEmptyResultSet() th
}
@Test
- void givenStatement_whenMakeUDTsNotSpecifyingSchemaPattern_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildUDTsNotSpecifyingSchemaPattern_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new TypeMetadataResultSetBuilder(statement).buildUDTs(null, "type_in_different_ks",
new int[]{Types.JAVA_OBJECT});
@@ -432,7 +461,7 @@ void givenStatement_whenMakeUDTsNotSpecifyingSchemaPattern_returnExpectedResultS
}
@Test
- void givenStatement_whenMakeTypes_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildTypes_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new TypeMetadataResultSetBuilder(statement).buildTypes();
assertNotNull(result);
@@ -527,7 +556,7 @@ void givenStatement_whenMakeTypes_returnExpectedResultSet() throws SQLException
*/
@Test
- void givenStatement_whenMakeFunctions_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildFunctions_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new FunctionMetadataResultSetBuilder(statement)
.buildFunctions(KEYSPACE, "function_test1");
@@ -551,7 +580,7 @@ void givenStatement_whenMakeFunctions_returnExpectedResultSet() throws SQLExcept
}
@Test
- void givenStatement_whenMakeFunctionColumns_returnExpectedResultSet() throws SQLException {
+ void givenStatement_whenBuildFunctionColumns_returnExpectedResultSet() throws SQLException {
final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
final ResultSet result = new FunctionMetadataResultSetBuilder(statement)
.buildFunctionColumns(KEYSPACE, "function_test1", "%");
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeLoadBalancingPolicy.java b/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeLoadBalancingPolicy.java
index 08735b6..dc5e514 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeLoadBalancingPolicy.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeLoadBalancingPolicy.java
@@ -19,9 +19,9 @@
import com.datastax.oss.driver.api.core.session.Request;
import com.datastax.oss.driver.api.core.session.Session;
import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan;
-import edu.umd.cs.findbugs.annotations.NonNull;
-import edu.umd.cs.findbugs.annotations.Nullable;
+import lombok.NonNull;
+import javax.annotation.Nullable;
import java.util.Map;
import java.util.Queue;
import java.util.UUID;
@@ -30,7 +30,7 @@
public class AnotherFakeLoadBalancingPolicy implements LoadBalancingPolicy {
- public AnotherFakeLoadBalancingPolicy(@NonNull final DriverContext context, @NonNull final String profileName) {
+ public AnotherFakeLoadBalancingPolicy(final DriverContext context, final String profileName) {
// Do nothing. For testing purpose only.
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeLoadBalancingPolicy.java b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeLoadBalancingPolicy.java
index 8e61a3a..f23b137 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeLoadBalancingPolicy.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeLoadBalancingPolicy.java
@@ -19,9 +19,9 @@
import com.datastax.oss.driver.api.core.session.Request;
import com.datastax.oss.driver.api.core.session.Session;
import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan;
-import edu.umd.cs.findbugs.annotations.NonNull;
-import edu.umd.cs.findbugs.annotations.Nullable;
+import lombok.NonNull;
+import javax.annotation.Nullable;
import java.util.Map;
import java.util.Queue;
import java.util.UUID;
diff --git a/src/test/resources/initEmbeddedCassandra.cql b/src/test/resources/initEmbeddedCassandra.cql
index d95c9ab..044bc24 100644
--- a/src/test/resources/initEmbeddedCassandra.cql
+++ b/src/test/resources/initEmbeddedCassandra.cql
@@ -18,6 +18,13 @@ t2bValue boolean,
t2iValue int)
WITH comment = 'Second table in the keyspace';
+CREATE COLUMNFAMILY cf_test3 (
+keyname text,
+t3bValue boolean,
+t3iValue int,
+PRIMARY KEY(keyname, t3iValue))
+WITH comment = 'Third table in the keyspace';
+
CREATE TYPE CustomType1 (
key1 int,
value1 text,
From 99ade34fb98fb139089277cf774f47309f4029bc Mon Sep 17 00:00:00 2001
From: Maxime Wiewiora <48218208+maximevw@users.noreply.github.com>
Date: Sat, 23 Sep 2023 17:04:35 +0200
Subject: [PATCH 19/21] Implement CassandraDatabaseMetaData.getAttributes()
Also replace all Findbugs NonNull/Nullable annotations with standard Java
equivalent, and preform some code cleanup.
---
.../cassandra/jdbc/AbstractResultSet.java | 6 +-
.../cassandra/jdbc/CassandraConnection.java | 8 +-
.../jdbc/CassandraDatabaseMetaData.java | 6 +-
.../jdbc/CassandraResultSetJsonSupport.java | 1 +
.../cassandra/jdbc/CassandraStatement.java | 4 +-
.../cassandra/jdbc/codec/AbstractCodec.java | 9 +-
.../jdbc/codec/BigintToBigDecimalCodec.java | 14 +-
.../jdbc/codec/DecimalToDoubleCodec.java | 14 +-
.../jdbc/codec/FloatToDoubleCodec.java | 14 +-
.../cassandra/jdbc/codec/IntToLongCodec.java | 14 +-
.../cassandra/jdbc/codec/LongToIntCodec.java | 14 +-
.../jdbc/codec/SmallintToIntCodec.java | 14 +-
.../jdbc/codec/TimestampToLongCodec.java | 14 +-
.../jdbc/codec/TinyintToIntCodec.java | 14 +-
.../jdbc/codec/VarintToIntCodec.java | 14 +-
.../AbstractMetadataResultSetBuilder.java | 4 +
.../ColumnMetadataResultSetBuilder.java | 8 +-
.../TypeMetadataResultSetBuilder.java | 171 ++++++++++++++++++
.../jdbc/types/AbstractJdbcUUID.java | 5 +-
.../cassandra/jdbc/types/DataTypeEnum.java | 4 +-
.../cassandra/jdbc/types/JdbcLexicalUUID.java | 7 +-
.../cassandra/jdbc/types/JdbcTimeUUID.java | 6 +-
.../data/cassandra/jdbc/types/JdbcTuple.java | 4 +-
.../data/cassandra/jdbc/types/JdbcUUID.java | 5 +-
.../data/cassandra/jdbc/types/JdbcUdt.java | 4 +-
.../jdbc/MetadataResultSetsUnitTest.java | 43 +++++
.../utils/AnotherFakeLoadBalancingPolicy.java | 14 +-
.../jdbc/utils/AnotherFakeRetryPolicy.java | 17 +-
.../jdbc/utils/FakeLoadBalancingPolicy.java | 16 +-
.../jdbc/utils/FakeReconnectionPolicy.java | 9 +-
.../cassandra/jdbc/utils/FakeRetryPolicy.java | 17 +-
.../jdbc/utils/FakeSslEngineFactory.java | 6 +-
32 files changed, 360 insertions(+), 140 deletions(-)
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/AbstractResultSet.java b/src/main/java/com/ing/data/cassandra/jdbc/AbstractResultSet.java
index 6ec1be9..13f81ab 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/AbstractResultSet.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/AbstractResultSet.java
@@ -17,9 +17,9 @@
import com.datastax.oss.driver.api.core.type.DataType;
import com.ing.data.cassandra.jdbc.types.DataTypeEnum;
-import edu.umd.cs.findbugs.annotations.NonNull;
import org.apache.commons.lang3.StringUtils;
+import javax.annotation.Nonnull;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
@@ -56,7 +56,7 @@ abstract class AbstractResultSet implements Wrapper {
* @param type The data type to check.
* @return {@code true} if the column CQL data type is the given one, {@code false} otherwise.
*/
- boolean isCqlType(final int columnIndex, @NonNull final DataTypeEnum type) {
+ boolean isCqlType(final int columnIndex, @Nonnull final DataTypeEnum type) {
final String columnType = StringUtils.substringBefore(DataTypeEnum.cqlName(getCqlDataType(columnIndex)), "<");
return type.cqlType.equalsIgnoreCase(columnType);
}
@@ -68,7 +68,7 @@ boolean isCqlType(final int columnIndex, @NonNull final DataTypeEnum type) {
* @param type The data type to check.
* @return {@code true} if the column CQL data type is the given one, {@code false} otherwise.
*/
- boolean isCqlType(final String columnLabel, @NonNull final DataTypeEnum type) {
+ boolean isCqlType(final String columnLabel, @Nonnull final DataTypeEnum type) {
final String columnType = StringUtils.substringBefore(DataTypeEnum.cqlName(getCqlDataType(columnLabel)), "<");
return type.cqlType.equalsIgnoreCase(columnType);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java
index de077a5..49cc2bf 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraConnection.java
@@ -51,6 +51,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Properties;
import java.util.ServiceLoader;
import java.util.Set;
@@ -160,18 +161,13 @@ public CassandraConnection(final SessionHolder sessionHolder) throws SQLExceptio
this.cSession = sessionHolder.session;
this.metadata = this.cSession.getMetadata();
- // TODO check if this code should be definitely removed.
- // final List l = new ArrayList<>();
- // l.stream().map(s -> s.session).collect(Collectors.toList());
-
LOG.info("Connected to cluster: {}, with session: {}",
- StringUtils.defaultString(getCatalog(), ""), this.cSession.getName());
+ Objects.toString(getCatalog(), ""), this.cSession.getName());
this.metadata.getNodes().forEach(
(uuid, node) -> LOG.info("Datacenter: {}; Host: {}; Rack: {}", node.getDatacenter(),
node.getEndPoint().resolve(), node.getRack())
);
- // TODO this is shared among all Connections, what if they belong to different clusters?
this.metadata.getNodes().entrySet().stream().findFirst().ifPresent(entry -> {
final Version cassandraVersion = entry.getValue().getCassandraVersion();
if (cassandraVersion != null) {
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
index f31acd0..3ca43ca 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
@@ -123,8 +123,12 @@ public boolean generatedKeyAlwaysReturned() {
@Override
public ResultSet getAttributes(final String catalog, final String schemaPattern, final String typeNamePattern,
final String attributeNamePattern) throws SQLException {
- // TODO: method to implement into TypeMetadataResultSetBuilder
checkStatementClosed();
+ // Only null or the current catalog (i.e. cluster) name are supported.
+ if (catalog == null || catalog.equals(this.connection.getCatalog())) {
+ return new TypeMetadataResultSetBuilder(this.statement).buildAttributes(schemaPattern, typeNamePattern,
+ attributeNamePattern);
+ }
return CassandraResultSet.EMPTY_RESULT_SET;
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSetJsonSupport.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSetJsonSupport.java
index da5d193..1046353 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSetJsonSupport.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSetJsonSupport.java
@@ -69,6 +69,7 @@
* uuid | string | {@link UUID} |
* varchar | string | {@link String} |
* varint | integer | {@link Number} |
+ * vector | list | {@link List} |
*
* See:
* CQL reference for JSON support.
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java
index 3c8276a..1bae7d1 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraStatement.java
@@ -24,11 +24,11 @@
import com.datastax.oss.driver.internal.core.cql.MultiPageResultSet;
import com.datastax.oss.driver.internal.core.cql.SinglePageResultSet;
import com.datastax.oss.driver.internal.core.util.concurrent.CompletableFutures;
-import edu.umd.cs.findbugs.annotations.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.Nonnull;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
@@ -282,7 +282,7 @@ public void close() {
}
@Override
- public int compareTo(@NonNull final Object target) {
+ public int compareTo(@Nonnull final Object target) {
if (this.equals(target)) {
return 0;
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/AbstractCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/AbstractCodec.java
index dbab784..89a492e 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/AbstractCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/AbstractCodec.java
@@ -16,9 +16,10 @@
package com.ing.data.cassandra.jdbc.codec;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
-import edu.umd.cs.findbugs.annotations.NonNull;
import org.apache.commons.lang3.StringUtils;
+import javax.annotation.Nonnull;
+
import static com.ing.data.cassandra.jdbc.utils.DriverUtil.NULL_KEYWORD;
/**
@@ -51,7 +52,7 @@ public JavaTypeT parse(final String value) {
* @param value The value to parse.
* @return The parsed value.
*/
- abstract JavaTypeT parseNonNull(@NonNull String value);
+ abstract JavaTypeT parseNonNull(@Nonnull String value);
/**
* Formats the given value as a valid CQL literal according to the CQL type handled by this codec.
@@ -59,7 +60,7 @@ public JavaTypeT parse(final String value) {
* @param value The value to format.
* @return The formatted value or {@code NULL} CQL keyword if the value to format is {@code null}.
*/
- @NonNull
+ @Nonnull
public String format(final JavaTypeT value) {
if (value == null) {
return NULL_KEYWORD;
@@ -73,5 +74,5 @@ public String format(final JavaTypeT value) {
* @param value The value to format.
* @return The formatted value.
*/
- abstract String formatNonNull(@NonNull JavaTypeT value);
+ abstract String formatNonNull(@Nonnull JavaTypeT value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/BigintToBigDecimalCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/BigintToBigDecimalCodec.java
index 423ca93..93b607f 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/BigintToBigDecimalCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/BigintToBigDecimalCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.math.BigDecimal;
import java.nio.ByteBuffer;
@@ -37,20 +37,20 @@ public class BigintToBigDecimalCodec extends AbstractCodec implement
public BigintToBigDecimalCodec() {
}
- @NonNull
+ @Nonnull
@Override
public GenericType getJavaType() {
return GenericType.BIG_DECIMAL;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.BIGINT;
}
@Override
- public ByteBuffer encode(final BigDecimal value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final BigDecimal value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -58,7 +58,7 @@ public ByteBuffer encode(final BigDecimal value, @NonNull final ProtocolVersion
}
@Override
- public BigDecimal decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public BigDecimal decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -68,12 +68,12 @@ public BigDecimal decode(final ByteBuffer bytes, @NonNull final ProtocolVersion
}
@Override
- BigDecimal parseNonNull(@NonNull final String value) {
+ BigDecimal parseNonNull(@Nonnull final String value) {
return BigDecimal.valueOf(Long.parseLong(value));
}
@Override
- String formatNonNull(@NonNull final BigDecimal value) {
+ String formatNonNull(@Nonnull final BigDecimal value) {
return String.valueOf(value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/DecimalToDoubleCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/DecimalToDoubleCodec.java
index 1aa0b46..0cbd766 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/DecimalToDoubleCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/DecimalToDoubleCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
/**
@@ -36,20 +36,20 @@ public class DecimalToDoubleCodec extends AbstractCodec implements TypeC
public DecimalToDoubleCodec() {
}
- @NonNull
+ @Nonnull
@Override
public GenericType getJavaType() {
return GenericType.DOUBLE;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.DECIMAL;
}
@Override
- public ByteBuffer encode(final Double value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final Double value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -57,7 +57,7 @@ public ByteBuffer encode(final Double value, @NonNull final ProtocolVersion prot
}
@Override
- public Double decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public Double decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -66,12 +66,12 @@ public Double decode(final ByteBuffer bytes, @NonNull final ProtocolVersion prot
}
@Override
- Double parseNonNull(@NonNull final String value) {
+ Double parseNonNull(@Nonnull final String value) {
return Double.valueOf(value);
}
@Override
- String formatNonNull(@NonNull final Double value) {
+ String formatNonNull(@Nonnull final Double value) {
return String.valueOf(value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/FloatToDoubleCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/FloatToDoubleCodec.java
index a8298e1..7262414 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/FloatToDoubleCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/FloatToDoubleCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
/**
@@ -36,20 +36,20 @@ public class FloatToDoubleCodec extends AbstractCodec implements TypeCod
public FloatToDoubleCodec() {
}
- @NonNull
+ @Nonnull
@Override
public GenericType getJavaType() {
return GenericType.DOUBLE;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.FLOAT;
}
@Override
- public ByteBuffer encode(final Double value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final Double value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -57,7 +57,7 @@ public ByteBuffer encode(final Double value, @NonNull final ProtocolVersion prot
}
@Override
- public Double decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public Double decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -67,12 +67,12 @@ public Double decode(final ByteBuffer bytes, @NonNull final ProtocolVersion prot
}
@Override
- Double parseNonNull(@NonNull final String value) {
+ Double parseNonNull(@Nonnull final String value) {
return Double.valueOf(value);
}
@Override
- String formatNonNull(@NonNull final Double value) {
+ String formatNonNull(@Nonnull final Double value) {
return String.valueOf(value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/IntToLongCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/IntToLongCodec.java
index 5b56ae2..5d0a33c 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/IntToLongCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/IntToLongCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
/**
@@ -36,20 +36,20 @@ public class IntToLongCodec extends AbstractCodec implements TypeCodec getJavaType() {
return GenericType.LONG;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.INT;
}
@Override
- public ByteBuffer encode(final Long value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final Long value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -57,7 +57,7 @@ public ByteBuffer encode(final Long value, @NonNull final ProtocolVersion protoc
}
@Override
- public Long decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public Long decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -66,12 +66,12 @@ public Long decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protoc
}
@Override
- Long parseNonNull(@NonNull final String value) {
+ Long parseNonNull(@Nonnull final String value) {
return Long.valueOf(value);
}
@Override
- String formatNonNull(@NonNull final Long value) {
+ String formatNonNull(@Nonnull final Long value) {
return String.valueOf(value);
}
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/LongToIntCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/LongToIntCodec.java
index 51b55a8..d835166 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/LongToIntCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/LongToIntCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
/**
@@ -36,20 +36,20 @@ public class LongToIntCodec extends AbstractCodec implements TypeCodec<
public LongToIntCodec() {
}
- @NonNull
+ @Nonnull
@Override
public GenericType getJavaType() {
return GenericType.INTEGER;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.BIGINT;
}
@Override
- public ByteBuffer encode(final Integer value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final Integer value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -57,7 +57,7 @@ public ByteBuffer encode(final Integer value, @NonNull final ProtocolVersion pro
}
@Override
- public Integer decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public Integer decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -67,12 +67,12 @@ public Integer decode(final ByteBuffer bytes, @NonNull final ProtocolVersion pro
}
@Override
- Integer parseNonNull(@NonNull final String value) {
+ Integer parseNonNull(@Nonnull final String value) {
return Integer.valueOf(value);
}
@Override
- String formatNonNull(@NonNull final Integer value) {
+ String formatNonNull(@Nonnull final Integer value) {
return String.valueOf(value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/SmallintToIntCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/SmallintToIntCodec.java
index 7539971..d15e7f0 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/SmallintToIntCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/SmallintToIntCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
/**
@@ -36,20 +36,20 @@ public class SmallintToIntCodec extends AbstractCodec implements TypeCo
public SmallintToIntCodec() {
}
- @NonNull
+ @Nonnull
@Override
public GenericType getJavaType() {
return GenericType.INTEGER;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.SMALLINT;
}
@Override
- public ByteBuffer encode(final Integer value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final Integer value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -57,7 +57,7 @@ public ByteBuffer encode(final Integer value, @NonNull final ProtocolVersion pro
}
@Override
- public Integer decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public Integer decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -67,12 +67,12 @@ public Integer decode(final ByteBuffer bytes, @NonNull final ProtocolVersion pro
}
@Override
- Integer parseNonNull(@NonNull final String value) {
+ Integer parseNonNull(@Nonnull final String value) {
return Integer.valueOf(value);
}
@Override
- String formatNonNull(@NonNull final Integer value) {
+ String formatNonNull(@Nonnull final Integer value) {
return String.valueOf(value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/TimestampToLongCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/TimestampToLongCodec.java
index 18b13e4..06fdeae 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/TimestampToLongCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/TimestampToLongCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
/**
@@ -36,20 +36,20 @@ public class TimestampToLongCodec extends AbstractCodec implements TypeCod
public TimestampToLongCodec() {
}
- @NonNull
+ @Nonnull
@Override
public GenericType getJavaType() {
return GenericType.LONG;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.TIMESTAMP;
}
@Override
- public ByteBuffer encode(final Long value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final Long value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -57,7 +57,7 @@ public ByteBuffer encode(final Long value, @NonNull final ProtocolVersion protoc
}
@Override
- public Long decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public Long decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -66,12 +66,12 @@ public Long decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protoc
}
@Override
- Long parseNonNull(@NonNull final String value) {
+ Long parseNonNull(@Nonnull final String value) {
return Long.valueOf(value);
}
@Override
- String formatNonNull(@NonNull final Long value) {
+ String formatNonNull(@Nonnull final Long value) {
return String.valueOf(value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/TinyintToIntCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/TinyintToIntCodec.java
index e31ad8d..3a09f9d 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/TinyintToIntCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/TinyintToIntCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
/**
@@ -36,20 +36,20 @@ public class TinyintToIntCodec extends AbstractCodec implements TypeCod
public TinyintToIntCodec() {
}
- @NonNull
+ @Nonnull
@Override
public GenericType getJavaType() {
return GenericType.INTEGER;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.TINYINT;
}
@Override
- public ByteBuffer encode(final Integer value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final Integer value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -57,7 +57,7 @@ public ByteBuffer encode(final Integer value, @NonNull final ProtocolVersion pro
}
@Override
- public Integer decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public Integer decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -67,12 +67,12 @@ public Integer decode(final ByteBuffer bytes, @NonNull final ProtocolVersion pro
}
@Override
- Integer parseNonNull(@NonNull final String value) {
+ Integer parseNonNull(@Nonnull final String value) {
return Integer.valueOf(value);
}
@Override
- String formatNonNull(@NonNull final Integer value) {
+ String formatNonNull(@Nonnull final Integer value) {
return String.valueOf(value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/codec/VarintToIntCodec.java b/src/main/java/com/ing/data/cassandra/jdbc/codec/VarintToIntCodec.java
index c89f6a1..79988ad 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/codec/VarintToIntCodec.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/codec/VarintToIntCodec.java
@@ -20,9 +20,9 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.codec.TypeCodec;
import com.datastax.oss.driver.api.core.type.reflect.GenericType;
-import edu.umd.cs.findbugs.annotations.NonNull;
import com.ing.data.cassandra.jdbc.utils.ByteBufferUtil;
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
/**
@@ -36,20 +36,20 @@ public class VarintToIntCodec extends AbstractCodec implements TypeCode
public VarintToIntCodec() {
}
- @NonNull
+ @Nonnull
@Override
public GenericType getJavaType() {
return GenericType.INTEGER;
}
- @NonNull
+ @Nonnull
@Override
public DataType getCqlType() {
return DataTypes.VARINT;
}
@Override
- public ByteBuffer encode(final Integer value, @NonNull final ProtocolVersion protocolVersion) {
+ public ByteBuffer encode(final Integer value, @Nonnull final ProtocolVersion protocolVersion) {
if (value == null) {
return null;
}
@@ -57,7 +57,7 @@ public ByteBuffer encode(final Integer value, @NonNull final ProtocolVersion pro
}
@Override
- public Integer decode(final ByteBuffer bytes, @NonNull final ProtocolVersion protocolVersion) {
+ public Integer decode(final ByteBuffer bytes, @Nonnull final ProtocolVersion protocolVersion) {
if (bytes == null) {
return null;
}
@@ -66,12 +66,12 @@ public Integer decode(final ByteBuffer bytes, @NonNull final ProtocolVersion pro
}
@Override
- Integer parseNonNull(@NonNull final String value) {
+ Integer parseNonNull(@Nonnull final String value) {
return Integer.valueOf(value);
}
@Override
- String formatNonNull(@NonNull final Integer value) {
+ String formatNonNull(@Nonnull final Integer value) {
return String.valueOf(value);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/metadata/AbstractMetadataResultSetBuilder.java b/src/main/java/com/ing/data/cassandra/jdbc/metadata/AbstractMetadataResultSetBuilder.java
index bfb0c12..2bf8bb3 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/metadata/AbstractMetadataResultSetBuilder.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/metadata/AbstractMetadataResultSetBuilder.java
@@ -42,6 +42,10 @@ public abstract class AbstractMetadataResultSetBuilder {
static final String TABLE = "TABLE";
static final String CQL_OPTION_COMMENT = "comment";
static final String ASC_OR_DESC = "ASC_OR_DESC";
+ static final String ATTRIBUTE_DEFAULT = "ATTR_DEF";
+ static final String ATTRIBUTE_NAME = "ATTR_NAME";
+ static final String ATTRIBUTE_SIZE = "ATTR_SIZE";
+ static final String ATTRIBUTE_TYPE_NAME = "ATTR_TYPE_NAME";
static final String AUTO_INCREMENT = "AUTO_INCREMENT";
static final String BASE_TYPE = "BASE_TYPE";
static final String BUFFER_LENGTH = "BUFFER_LENGTH";
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/metadata/ColumnMetadataResultSetBuilder.java b/src/main/java/com/ing/data/cassandra/jdbc/metadata/ColumnMetadataResultSetBuilder.java
index 40f3fc5..3b69f53 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/metadata/ColumnMetadataResultSetBuilder.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/metadata/ColumnMetadataResultSetBuilder.java
@@ -85,15 +85,15 @@ public ColumnMetadataResultSetBuilder(final CassandraStatement statement) throws
* always {@code null} here since comments on columns does not exist in Cassandra.
* COLUMN_DEF String => default value for the column, which should be interpreted as a string
* when the value is enclosed in single quotes, may be {@code null}. Always {@code null} here.
- * SQL_DATA_TYPE int => not used: always {@code null} here.
+ * SQL_DATA_TYPE int => is not used: always {@code null} here.
* SQL_DATETIME_SUB int => is not used: always {@code null} here.
* CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column.
* ORDINAL_POSITION int => index of column in table (starting at 1).
* IS_NULLABLE String => ISO rules are used to determine the nullability for a column:
*
- * - YES - if the parameter can include {@code NULL}s
- * - NO - if the parameter cannot include {@code NULL}s
- * - empty string - if the nullability for the parameter is unknown
+ * - YES - if the column can include {@code NULL}s
+ * - NO - if the column cannot include {@code NULL}s
+ * - empty string - if the nullability for the column is unknown
*
Always empty here.
*
* SCOPE_CATALOG String => catalog of table that is the scope of a reference attribute
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/metadata/TypeMetadataResultSetBuilder.java b/src/main/java/com/ing/data/cassandra/jdbc/metadata/TypeMetadataResultSetBuilder.java
index 0510046..cb8cf6e 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/metadata/TypeMetadataResultSetBuilder.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/metadata/TypeMetadataResultSetBuilder.java
@@ -17,12 +17,15 @@
import com.datastax.oss.driver.api.core.CqlIdentifier;
import com.datastax.oss.driver.api.core.data.UdtValue;
+import com.datastax.oss.driver.api.core.type.DataType;
import com.datastax.oss.driver.api.core.type.UserDefinedType;
import com.ing.data.cassandra.jdbc.CassandraMetadataResultSet;
import com.ing.data.cassandra.jdbc.CassandraStatement;
import com.ing.data.cassandra.jdbc.types.AbstractJdbcType;
import com.ing.data.cassandra.jdbc.types.DataTypeEnum;
import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
@@ -30,9 +33,11 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
+import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
+import static com.ing.data.cassandra.jdbc.types.AbstractJdbcType.DEFAULT_PRECISION;
import static com.ing.data.cassandra.jdbc.types.AbstractJdbcType.DEFAULT_SCALE;
import static com.ing.data.cassandra.jdbc.types.TypesMap.getTypeForComparator;
import static java.sql.DatabaseMetaData.typeNullable;
@@ -44,6 +49,8 @@
*/
public class TypeMetadataResultSetBuilder extends AbstractMetadataResultSetBuilder {
+ private static final Logger LOG = LoggerFactory.getLogger(TypeMetadataResultSetBuilder.class);
+
/**
* Constructor.
*
@@ -208,6 +215,8 @@ public CassandraMetadataResultSet buildTypes() throws SQLException {
if (jdbcType.needsQuotes()) {
literalQuotingSymbol = "'";
}
+ /* FIXME: some values should be adapted for list, set, map, vector, tuple and UDTs (JDBC type OTHER).
+ Special JDBC types similar to JdbcCounterColumn should be used for that. */
final MetadataRow row = new MetadataRow()
.addEntry(TYPE_NAME, dataType.cqlType)
.addEntry(DATA_TYPE, String.valueOf(jdbcType.getJdbcType()))
@@ -235,4 +244,166 @@ public CassandraMetadataResultSet buildTypes() throws SQLException {
return CassandraMetadataResultSet.buildFrom(this.statement, new MetadataResultSet().setRows(types));
}
+ /**
+ * Builds a valid result set of the description of the given attribute of the given type for a user-defined type
+ * (UDT) that is available in the given schema.
+ * This method is used to implement the method
+ * {@link DatabaseMetaData#getAttributes(String, String, String, String)}.
+ *
+ * Only descriptions for attributes of UDTs matching the catalog, schema, type and attribute criteria are returned.
+ * They are ordered by {@code TYPE_CAT}, {@code TYPE_SCHEM} and {@code TYPE_NAME} and {@code ORDINAL_POSITION}.
+ * This description does not contain inherited attributes.
+ * The type name parameter may be a fully-qualified name (it should respect the format
+ * {@code .}). In this case, the {@code catalog} and {@code schemaPattern} parameters are
+ * ignored.
+ *
+ *
+ * The columns of this result set are:
+ *
+ * - TYPE_CAT String => table catalog, may be {@code null}: here is the Cassandra cluster name
+ * (if available).
+ * - TYPE_SCHEM String => table schema, may be {@code null}: here is the keyspace the type is
+ * member of.
+ * - TYPE_NAME String => type name.
+ * - ATTR_NAME String => attribute name.
+ * - DATA_TYPE int => attribute SQL type from {@link Types}.
+ * - ATTR_TYPE_NAME String => the data source dependent type name. For a UDT, the type name is
+ * fully qualified. There is no {@code REF} in Cassandra.
+ * - ATTR_SIZE int => column size.
+ * - DECIMAL_DIGITS int => the number of fractional digits, {@code null} is returned for data
+ * types where it is not applicable. Always {@code null} here.
+ * - NUM_PREC_RADIX int => Radix (typically either 10 or 2).
+ * - NULLABLE int => is {@code NULL} allowed:
+ *
+ * - {@link DatabaseMetaData#attributeNoNulls} - might not allow {@code NULL} values
+ * - {@link DatabaseMetaData#attributeNullable} - definitely allows {@code NULL} values
+ * - {@link DatabaseMetaData#attributeNullableUnknown} - nullability unknown
+ *
Always {@link DatabaseMetaData#attributeNoNulls} here.
+ *
+ * - REMARKS String => comment describing column, may be {@code null}:
+ * always {@code null} here since comments on columns does not exist in Cassandra.
+ * - ATTR_DEF String => attribute default value, always {@code null} since Cassandra does not
+ * support default values.
+ * - SQL_DATA_TYPE int => is not used: always {@code null} here.
+ * - SQL_DATETIME_SUB int => is not used: always {@code null} here.
+ * - CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column.
+ * - ORDINAL_POSITION int => index of attribute in UDT (starting at 1).
+ * - IS_NULLABLE String => ISO rules are used to determine the nullability for an attribute:
+ *
+ * - YES - if the attribute can include {@code NULL}s
+ * - NO - if the attribute cannot include {@code NULL}s
+ * - empty string - if the nullability for the attribute is unknown
+ *
Always empty here.
+ *
+ * - SCOPE_CATALOG String => catalog of table that is the scope of a reference attribute
+ * ({@code null} if {@code DATA_TYPE} isn't REF). Always {@code null} here.
+ * - SCOPE_SCHEMA String => schema of table that is the scope of a reference attribute
+ * ({@code null} if {@code DATA_TYPE} isn't REF). Always {@code null} here.
+ * - SCOPE_TABLE String => table name that is the scope of a reference attribute
+ * ({@code null} if {@code DATA_TYPE} isn't REF). Always {@code null} here.
+ * - SOURCE_DATA_TYPE short => source type of a distinct type or user-generated Ref type, SQL type
+ * from {@link Types} ({@code null} if {@code DATA_TYPE} isn't {@code DISTINCT} or user-generated
+ * {@code REF}). Always {@code null} here.
+ *
+ *
+ *
+ * @param schemaPattern A schema pattern name; must match the schema name as it is stored in the database;
+ * {@code ""} retrieves those without a schema (will always return an empty set);
+ * {@code null} means that the schema name should not be used to narrow the search and
+ * in this case the search is restricted to the current schema (if available).
+ * @param typeNamePattern A type name pattern; must match the type name as it is stored in the database (not
+ * case-sensitive); may be a fully qualified name.
+ * @param attributesNamePattern An attribute name pattern; must match the attribute name as it is declared in the
+ * database (not case-sensitive).
+ * @return A valid result set for implementation of
+ * {@link DatabaseMetaData#getAttributes(String, String, String, String)}.
+ * @throws SQLException when something went wrong during the creation of the result set.
+ */
+ public CassandraMetadataResultSet buildAttributes(final String schemaPattern, final String typeNamePattern,
+ final String attributesNamePattern) throws SQLException {
+ final String catalog = this.connection.getCatalog();
+ final ArrayList attributesRows = new ArrayList<>();
+
+ // Parse the fully-qualified type name, if necessary.
+ String schemaName = schemaPattern;
+ final AtomicReference typeName = new AtomicReference<>(typeNamePattern);
+ if (typeNamePattern.contains(".")) {
+ final String[] fullyQualifiedTypeNameParts = typeNamePattern.split("\\.");
+ schemaName = fullyQualifiedTypeNameParts[0];
+ typeName.set(fullyQualifiedTypeNameParts[1]);
+ }
+
+ filterBySchemaNamePattern(schemaName, keyspaceMetadata -> {
+ final Map udts = keyspaceMetadata.getUserDefinedTypes();
+ udts.entrySet()
+ .stream().filter(udt -> matchesPattern(typeName.get(), udt.getValue().getName().asInternal()))
+ .forEach(udt -> {
+ final UserDefinedType udtMetadata = udt.getValue();
+ final List attrNames = udtMetadata.getFieldNames();
+ final List attrTypes = udtMetadata.getFieldTypes();
+ for (int i = 0; i < attrNames.size(); i++) {
+ final String attrName = attrNames.get(i).asInternal();
+ if (!matchesPattern(attributesNamePattern, attrName)) {
+ continue;
+ }
+
+ final DataType attrType = attrTypes.get(i);
+ final AbstractJdbcType> jdbcEquivalentType = getTypeForComparator(attrType.toString());
+
+ // Define value of ATTR_SIZE.
+ int columnSize = DEFAULT_PRECISION;
+ if (jdbcEquivalentType != null) {
+ columnSize = jdbcEquivalentType.getPrecision(null);
+ }
+
+ // Define value of NUM_PREC_RADIX.
+ int radix = 2;
+ if (jdbcEquivalentType != null && (jdbcEquivalentType.getJdbcType() == Types.DECIMAL
+ || jdbcEquivalentType.getJdbcType() == Types.NUMERIC)) {
+ radix = 10;
+ }
+
+ // Define value of DATA_TYPE.
+ int jdbcType = Types.OTHER;
+ try {
+ jdbcType = getTypeForComparator(attrType.toString()).getJdbcType();
+ } catch (final Exception e) {
+ LOG.warn("Unable to get JDBC type for comparator [{}]: {}", attrType, e.getMessage());
+ }
+
+ final MetadataRow row = new MetadataRow()
+ .addEntry(TYPE_CATALOG, catalog)
+ .addEntry(TYPE_SCHEMA, keyspaceMetadata.getName().asInternal())
+ .addEntry(TYPE_NAME, udtMetadata.getName().asInternal())
+ .addEntry(ATTRIBUTE_NAME, attrName)
+ .addEntry(DATA_TYPE, String.valueOf(jdbcType))
+ .addEntry(ATTRIBUTE_TYPE_NAME, attrType.toString())
+ .addEntry(ATTRIBUTE_SIZE, String.valueOf(columnSize))
+ .addEntry(DECIMAL_DIGITS, null)
+ .addEntry(NUM_PRECISION_RADIX, String.valueOf(radix))
+ .addEntry(NULLABLE, String.valueOf(DatabaseMetaData.attributeNoNulls))
+ .addEntry(REMARKS, null)
+ .addEntry(ATTRIBUTE_DEFAULT, null)
+ .addEntry(SQL_DATA_TYPE, null)
+ .addEntry(SQL_DATETIME_SUB, null)
+ .addEntry(CHAR_OCTET_LENGTH, String.valueOf(Integer.MAX_VALUE))
+ .addEntry(ORDINAL_POSITION, String.valueOf(i + 1))
+ .addEntry(IS_NULLABLE, StringUtils.EMPTY)
+ .addEntry(SCOPE_CATALOG, null)
+ .addEntry(SCOPE_SCHEMA, null)
+ .addEntry(SCOPE_TABLE, null)
+ .addEntry(SOURCE_DATA_TYPE, null);
+ attributesRows.add(row);
+ }
+ });
+
+ }, null);
+
+ // Results should all have the same TYPE_CAT so just sort them by TYPE_SCHEM, TYPE_NAME then ORDINAL_POSITION.
+ attributesRows.sort(Comparator.comparing(row -> ((MetadataRow) row).getString(TYPE_SCHEMA))
+ .thenComparing(row -> ((MetadataRow) row).getString(TYPE_NAME))
+ .thenComparing(row -> ((MetadataRow) row).getString(ORDINAL_POSITION)));
+ return CassandraMetadataResultSet.buildFrom(this.statement, new MetadataResultSet().setRows(attributesRows));
+ }
+
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/AbstractJdbcUUID.java b/src/main/java/com/ing/data/cassandra/jdbc/types/AbstractJdbcUUID.java
index 8261c34..261eb11 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/AbstractJdbcUUID.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/AbstractJdbcUUID.java
@@ -15,8 +15,7 @@
package com.ing.data.cassandra.jdbc.types;
-import edu.umd.cs.findbugs.annotations.NonNull;
-
+import javax.annotation.Nonnull;
import java.sql.Types;
import java.util.UUID;
@@ -29,7 +28,7 @@ public abstract class AbstractJdbcUUID extends AbstractJdbcType {
private static final int DEFAULT_UUID_PRECISION = 36;
@Override
- public String toString(@NonNull final UUID obj) {
+ public String toString(@Nonnull final UUID obj) {
return obj.toString();
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java b/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
index d1fe6e3..1b03f5c 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
@@ -22,8 +22,8 @@
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.UserDefinedType;
import com.datastax.oss.protocol.internal.ProtocolConstants.DataType;
-import edu.umd.cs.findbugs.annotations.NonNull;
+import javax.annotation.Nonnull;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.net.InetAddress;
@@ -324,7 +324,7 @@ public String toString() {
* @param dataType The data type.
* @return The CQL name of the type.
*/
- public static String cqlName(@NonNull final com.datastax.oss.driver.api.core.type.DataType dataType) {
+ public static String cqlName(@Nonnull final com.datastax.oss.driver.api.core.type.DataType dataType) {
return dataType.asCql(false, false);
}
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcLexicalUUID.java b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcLexicalUUID.java
index 8988d46..a165f7e 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcLexicalUUID.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcLexicalUUID.java
@@ -15,8 +15,7 @@
package com.ing.data.cassandra.jdbc.types;
-import edu.umd.cs.findbugs.annotations.NonNull;
-
+import javax.annotation.Nonnull;
import java.util.UUID;
/**
@@ -34,12 +33,12 @@ public class JdbcLexicalUUID extends AbstractJdbcUUID {
}
@Override
- public UUID compose(@NonNull final Object obj) {
+ public UUID compose(@Nonnull final Object obj) {
return UUID.fromString(obj.toString());
}
@Override
- public Object decompose(@NonNull final UUID value) {
+ public Object decompose(@Nonnull final UUID value) {
return value.toString();
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcTimeUUID.java b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcTimeUUID.java
index 0e5dde0..965b0f4 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcTimeUUID.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcTimeUUID.java
@@ -15,8 +15,8 @@
package com.ing.data.cassandra.jdbc.types;
-import edu.umd.cs.findbugs.annotations.NonNull;
+import javax.annotation.Nonnull;
import java.util.UUID;
/**
@@ -34,12 +34,12 @@ public class JdbcTimeUUID extends AbstractJdbcUUID {
}
@Override
- public UUID compose(@NonNull final Object obj) {
+ public UUID compose(@Nonnull final Object obj) {
return UUID.fromString(obj.toString());
}
@Override
- public Object decompose(@NonNull final UUID value) {
+ public Object decompose(@Nonnull final UUID value) {
return value.toString();
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcTuple.java b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcTuple.java
index cfe5ec2..0b2cde9 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcTuple.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcTuple.java
@@ -16,8 +16,8 @@
package com.ing.data.cassandra.jdbc.types;
import com.datastax.oss.driver.api.core.data.TupleValue;
-import edu.umd.cs.findbugs.annotations.NonNull;
+import javax.annotation.Nonnull;
import java.sql.Types;
/**
@@ -50,7 +50,7 @@ public boolean isSigned() {
}
@Override
- public String toString(@NonNull final TupleValue obj) {
+ public String toString(@Nonnull final TupleValue obj) {
return getString(obj);
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcUUID.java b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcUUID.java
index 94aa5dc..1485739 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcUUID.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcUUID.java
@@ -15,8 +15,7 @@
package com.ing.data.cassandra.jdbc.types;
-import edu.umd.cs.findbugs.annotations.NonNull;
-
+import javax.annotation.Nonnull;
import java.nio.ByteBuffer;
import java.util.UUID;
@@ -52,7 +51,7 @@ public UUID compose(final ByteBuffer bytes) {
}
@Override
- public UUID compose(@NonNull final Object obj) {
+ public UUID compose(@Nonnull final Object obj) {
return UUID.fromString(obj.toString());
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcUdt.java b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcUdt.java
index 3540a17..f19a29f 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcUdt.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/JdbcUdt.java
@@ -16,8 +16,8 @@
package com.ing.data.cassandra.jdbc.types;
import com.datastax.oss.driver.api.core.data.UdtValue;
-import edu.umd.cs.findbugs.annotations.NonNull;
+import javax.annotation.Nonnull;
import java.sql.Types;
/**
@@ -49,7 +49,7 @@ public boolean isSigned() {
}
@Override
- public String toString(@NonNull final UdtValue obj) {
+ public String toString(@Nonnull final UdtValue obj) {
return getString(obj);
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/MetadataResultSetsUnitTest.java b/src/test/java/com/ing/data/cassandra/jdbc/MetadataResultSetsUnitTest.java
index 22ca4cd..a2812ab 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/MetadataResultSetsUnitTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/MetadataResultSetsUnitTest.java
@@ -34,6 +34,7 @@
import java.util.ArrayList;
import java.util.List;
+import static com.ing.data.cassandra.jdbc.types.DataTypeEnum.VECTOR;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.core.IsIterableContaining.hasItem;
@@ -549,6 +550,48 @@ void givenStatement_whenBuildTypes_returnExpectedResultSet() throws SQLException
foundColumns.get(25));
assertEquals("uuid;1111;36;null;null;null;1;false;2;true;true;false;null;0;0;null;null;36",
foundColumns.get(26));
+ assertEquals(VECTOR.cqlType.concat(";1111;-1;';';null;1;true;2;true;true;false;null;0;0;null;null;-1"),
+ foundColumns.get(27));
+ }
+
+ @Test
+ void givenStatement_whenBuildAttributes_returnExpectedResultSet() throws SQLException {
+ final CassandraStatement statement = (CassandraStatement) sqlConnection.createStatement();
+ final ResultSet result = new TypeMetadataResultSetBuilder(statement)
+ .buildAttributes(KEYSPACE, "type_in_different_ks", "t_%");
+ assertNotNull(result);
+ assertEquals(21, result.getMetaData().getColumnCount());
+ assertEquals("TYPE_CAT", result.getMetaData().getColumnName(1));
+ assertEquals("TYPE_SCHEM", result.getMetaData().getColumnName(2));
+ assertEquals("TYPE_NAME", result.getMetaData().getColumnName(3));
+ assertEquals("ATTR_NAME", result.getMetaData().getColumnName(4));
+ assertEquals("DATA_TYPE", result.getMetaData().getColumnName(5));
+ assertEquals("ATTR_TYPE_NAME", result.getMetaData().getColumnName(6));
+ assertEquals("ATTR_SIZE", result.getMetaData().getColumnName(7));
+ assertEquals("DECIMAL_DIGITS", result.getMetaData().getColumnName(8));
+ assertEquals("NUM_PREC_RADIX", result.getMetaData().getColumnName(9));
+ assertEquals("NULLABLE", result.getMetaData().getColumnName(10));
+ assertEquals("REMARKS", result.getMetaData().getColumnName(11));
+ assertEquals("ATTR_DEF", result.getMetaData().getColumnName(12));
+ assertEquals("SQL_DATA_TYPE", result.getMetaData().getColumnName(13));
+ assertEquals("SQL_DATETIME_SUB", result.getMetaData().getColumnName(14));
+ assertEquals("CHAR_OCTET_LENGTH", result.getMetaData().getColumnName(15));
+ assertEquals("ORDINAL_POSITION", result.getMetaData().getColumnName(16));
+ assertEquals("IS_NULLABLE", result.getMetaData().getColumnName(17));
+ assertEquals("SCOPE_CATALOG", result.getMetaData().getColumnName(18));
+ assertEquals("SCOPE_SCHEMA", result.getMetaData().getColumnName(19));
+ assertEquals("SCOPE_TABLE", result.getMetaData().getColumnName(20));
+ assertEquals("SOURCE_DATA_TYPE", result.getMetaData().getColumnName(21));
+ final List foundAttrs = new ArrayList<>();
+ int resultSize = 0;
+ while (result.next()) {
+ ++resultSize;
+ foundAttrs.add(String.join(";", result.getString(2), result.getString(3), result.getString(4),
+ result.getString(6), result.getString(16)));
+ }
+ assertEquals(2, resultSize);
+ assertThat(foundAttrs, hasItem(is(KEYSPACE.concat(";type_in_different_ks;t_key;INT;1"))));
+ assertThat(foundAttrs, hasItem(is(KEYSPACE.concat(";type_in_different_ks;t_value;TEXT;2"))));
}
/*
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeLoadBalancingPolicy.java b/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeLoadBalancingPolicy.java
index dc5e514..bebdd8a 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeLoadBalancingPolicy.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeLoadBalancingPolicy.java
@@ -19,8 +19,8 @@
import com.datastax.oss.driver.api.core.session.Request;
import com.datastax.oss.driver.api.core.session.Session;
import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan;
-import lombok.NonNull;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Queue;
@@ -35,11 +35,11 @@ public AnotherFakeLoadBalancingPolicy(final DriverContext context, final String
}
@Override
- public void init(@NonNull final Map nodes, @NonNull final DistanceReporter distanceReporter) {
+ public void init(@Nonnull final Map nodes, @Nonnull final DistanceReporter distanceReporter) {
// Do nothing. For testing purpose only.
}
- @NonNull
+ @Nonnull
@Override
public Queue newQueryPlan(@Nullable final Request request, @Nullable final Session session) {
// Do nothing. For testing purpose only.
@@ -47,22 +47,22 @@ public Queue newQueryPlan(@Nullable final Request request, @Nullable final
}
@Override
- public void onAdd(@NonNull final Node node) {
+ public void onAdd(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
}
@Override
- public void onUp(@NonNull final Node node) {
+ public void onUp(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
}
@Override
- public void onDown(@NonNull final Node node) {
+ public void onDown(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
}
@Override
- public void onRemove(@NonNull final Node node) {
+ public void onRemove(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeRetryPolicy.java b/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeRetryPolicy.java
index 1a18d49..ef5eb46 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeRetryPolicy.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/utils/AnotherFakeRetryPolicy.java
@@ -20,16 +20,17 @@
import com.datastax.oss.driver.api.core.servererrors.CoordinatorException;
import com.datastax.oss.driver.api.core.servererrors.WriteType;
import com.datastax.oss.driver.api.core.session.Request;
-import edu.umd.cs.findbugs.annotations.NonNull;
+
+import javax.annotation.Nonnull;
public class AnotherFakeRetryPolicy implements RetryPolicy {
- public AnotherFakeRetryPolicy(@NonNull final DriverContext context, @NonNull final String profileName) {
+ public AnotherFakeRetryPolicy(final DriverContext context, final String profileName) {
// Do nothing. For testing purpose only.
}
@Override
- public RetryDecision onReadTimeout(@NonNull final Request request, @NonNull final ConsistencyLevel cl,
+ public RetryDecision onReadTimeout(@Nonnull final Request request, @Nonnull final ConsistencyLevel cl,
final int blockFor, final int received, final boolean dataPresent,
final int retryCount) {
// Do nothing. For testing purpose only.
@@ -37,29 +38,29 @@ public RetryDecision onReadTimeout(@NonNull final Request request, @NonNull fina
}
@Override
- public RetryDecision onWriteTimeout(@NonNull final Request request, @NonNull final ConsistencyLevel cl,
- @NonNull final WriteType writeType, final int blockFor, final int received,
+ public RetryDecision onWriteTimeout(@Nonnull final Request request, @Nonnull final ConsistencyLevel cl,
+ @Nonnull final WriteType writeType, final int blockFor, final int received,
final int retryCount) {
// Do nothing. For testing purpose only.
return null;
}
@Override
- public RetryDecision onUnavailable(@NonNull final Request request, @NonNull final ConsistencyLevel cl,
+ public RetryDecision onUnavailable(@Nonnull final Request request, @Nonnull final ConsistencyLevel cl,
final int required, final int alive, final int retryCount) {
// Do nothing. For testing purpose only.
return null;
}
@Override
- public RetryDecision onRequestAborted(@NonNull final Request request, @NonNull final Throwable error,
+ public RetryDecision onRequestAborted(@Nonnull final Request request, @Nonnull final Throwable error,
final int retryCount) {
// Do nothing. For testing purpose only.
return null;
}
@Override
- public RetryDecision onErrorResponse(@NonNull final Request request, @NonNull final CoordinatorException error,
+ public RetryDecision onErrorResponse(@Nonnull final Request request, @Nonnull final CoordinatorException error,
final int retryCount) {
// Do nothing. For testing purpose only.
return null;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeLoadBalancingPolicy.java b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeLoadBalancingPolicy.java
index f23b137..544badf 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeLoadBalancingPolicy.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeLoadBalancingPolicy.java
@@ -19,8 +19,8 @@
import com.datastax.oss.driver.api.core.session.Request;
import com.datastax.oss.driver.api.core.session.Session;
import com.datastax.oss.driver.internal.core.util.collection.SimpleQueryPlan;
-import lombok.NonNull;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.Map;
import java.util.Queue;
@@ -30,16 +30,16 @@
public class FakeLoadBalancingPolicy implements LoadBalancingPolicy {
- public FakeLoadBalancingPolicy(@NonNull final DriverContext context, @NonNull final String profileName) {
+ public FakeLoadBalancingPolicy(@Nonnull final DriverContext context, @Nonnull final String profileName) {
// Do nothing. For testing purpose only.
}
@Override
- public void init(@NonNull final Map nodes, @NonNull final DistanceReporter distanceReporter) {
+ public void init(@Nonnull final Map nodes, @Nonnull final DistanceReporter distanceReporter) {
// Do nothing. For testing purpose only.
}
- @NonNull
+ @Nonnull
@Override
public Queue newQueryPlan(@Nullable final Request request, @Nullable final Session session) {
// Do nothing. For testing purpose only.
@@ -47,22 +47,22 @@ public Queue newQueryPlan(@Nullable final Request request, @Nullable final
}
@Override
- public void onAdd(@NonNull final Node node) {
+ public void onAdd(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
}
@Override
- public void onUp(@NonNull final Node node) {
+ public void onUp(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
}
@Override
- public void onDown(@NonNull final Node node) {
+ public void onDown(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
}
@Override
- public void onRemove(@NonNull final Node node) {
+ public void onRemove(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeReconnectionPolicy.java b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeReconnectionPolicy.java
index 5589413..7457d44 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeReconnectionPolicy.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeReconnectionPolicy.java
@@ -16,7 +16,8 @@
import com.datastax.oss.driver.api.core.connection.ReconnectionPolicy;
import com.datastax.oss.driver.api.core.context.DriverContext;
import com.datastax.oss.driver.api.core.metadata.Node;
-import edu.umd.cs.findbugs.annotations.NonNull;
+
+import javax.annotation.Nonnull;
import static org.mockito.Mockito.mock;
@@ -26,14 +27,14 @@ public FakeReconnectionPolicy(final DriverContext context) {
// Do nothing. For testing purpose only.
}
- @NonNull
+ @Nonnull
@Override
- public ReconnectionSchedule newNodeSchedule(@NonNull final Node node) {
+ public ReconnectionSchedule newNodeSchedule(@Nonnull final Node node) {
// Do nothing. For testing purpose only.
return mock(ReconnectionSchedule.class);
}
- @NonNull
+ @Nonnull
@Override
public ReconnectionSchedule newControlConnectionSchedule(final boolean isInitialConnection) {
// Do nothing. For testing purpose only.
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeRetryPolicy.java b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeRetryPolicy.java
index 762ae8c..cf3b659 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeRetryPolicy.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeRetryPolicy.java
@@ -20,16 +20,17 @@
import com.datastax.oss.driver.api.core.servererrors.CoordinatorException;
import com.datastax.oss.driver.api.core.servererrors.WriteType;
import com.datastax.oss.driver.api.core.session.Request;
-import edu.umd.cs.findbugs.annotations.NonNull;
+
+import javax.annotation.Nonnull;
public class FakeRetryPolicy implements RetryPolicy {
- public FakeRetryPolicy(@NonNull final DriverContext context, @NonNull final String profileName) {
+ public FakeRetryPolicy(final DriverContext context, final String profileName) {
// Do nothing. For testing purpose only.
}
@Override
- public RetryDecision onReadTimeout(@NonNull final Request request, @NonNull final ConsistencyLevel cl,
+ public RetryDecision onReadTimeout(@Nonnull final Request request, @Nonnull final ConsistencyLevel cl,
final int blockFor, final int received, final boolean dataPresent,
final int retryCount) {
// Do nothing. For testing purpose only.
@@ -37,29 +38,29 @@ public RetryDecision onReadTimeout(@NonNull final Request request, @NonNull fina
}
@Override
- public RetryDecision onWriteTimeout(@NonNull final Request request, @NonNull final ConsistencyLevel cl,
- @NonNull final WriteType writeType, final int blockFor, final int received,
+ public RetryDecision onWriteTimeout(@Nonnull final Request request, @Nonnull final ConsistencyLevel cl,
+ @Nonnull final WriteType writeType, final int blockFor, final int received,
final int retryCount) {
// Do nothing. For testing purpose only.
return null;
}
@Override
- public RetryDecision onUnavailable(@NonNull final Request request, @NonNull final ConsistencyLevel cl,
+ public RetryDecision onUnavailable(@Nonnull final Request request, @Nonnull final ConsistencyLevel cl,
final int required, final int alive, final int retryCount) {
// Do nothing. For testing purpose only.
return null;
}
@Override
- public RetryDecision onRequestAborted(@NonNull final Request request, @NonNull final Throwable error,
+ public RetryDecision onRequestAborted(@Nonnull final Request request, @Nonnull final Throwable error,
final int retryCount) {
// Do nothing. For testing purpose only.
return null;
}
@Override
- public RetryDecision onErrorResponse(@NonNull final Request request, @NonNull final CoordinatorException error,
+ public RetryDecision onErrorResponse(@Nonnull final Request request, @Nonnull final CoordinatorException error,
final int retryCount) {
// Do nothing. For testing purpose only.
return null;
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeSslEngineFactory.java b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeSslEngineFactory.java
index ba52e19..aafa229 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeSslEngineFactory.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/utils/FakeSslEngineFactory.java
@@ -15,8 +15,8 @@
import com.datastax.oss.driver.api.core.metadata.EndPoint;
import com.datastax.oss.driver.api.core.ssl.SslEngineFactory;
-import edu.umd.cs.findbugs.annotations.NonNull;
+import javax.annotation.Nonnull;
import javax.net.ssl.SSLEngine;
public class FakeSslEngineFactory implements SslEngineFactory {
@@ -25,9 +25,9 @@ public FakeSslEngineFactory() {
// Do nothing. For testing purpose only.
}
- @NonNull
+ @Nonnull
@Override
- public SSLEngine newSslEngine(@NonNull EndPoint remoteEndpoint) {
+ public SSLEngine newSslEngine(@Nonnull EndPoint remoteEndpoint) {
// Do nothing. For testing purpose only.
return null;
}
From 7b4c5b8c110c391a0bd2eb7dcf5ce7faabee0799 Mon Sep 17 00:00:00 2001
From: Cedrick Lunven
Date: Tue, 26 Sep 2023 08:48:53 +0200
Subject: [PATCH 20/21] Fix Vector Support and add Samples for DBaas and Dse
(#27)
---
pom.xml | 22 ++
.../cassandra/jdbc/CassandraResultSet.java | 3 +
.../cassandra/jdbc/types/DataTypeEnum.java | 16 +-
.../jdbc/DbaasAstraIntegrationTest.java | 218 ++++++++++++++++++
.../cassandra/jdbc/UsingDseContainerTest.java | 74 ++++++
.../jdbc/VectorsDseContainerTest.java | 56 +++++
src/test/resources/initEmbeddedDse.cql | 33 +++
7 files changed, 420 insertions(+), 2 deletions(-)
create mode 100644 src/test/java/com/ing/data/cassandra/jdbc/DbaasAstraIntegrationTest.java
create mode 100644 src/test/java/com/ing/data/cassandra/jdbc/UsingDseContainerTest.java
create mode 100644 src/test/java/com/ing/data/cassandra/jdbc/VectorsDseContainerTest.java
create mode 100644 src/test/resources/initEmbeddedDse.cql
diff --git a/pom.xml b/pom.xml
index 917f2d0..36ee2e8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,6 +67,13 @@
developer
+
+ Cedrick Lunven
+ https://github.com/clun
+
+ developer
+
+
@@ -106,6 +113,7 @@
3.12.4
1.7.36
1.18.3
+ 0.6.11
3.3.0
3.3.1
@@ -233,6 +241,20 @@
${testcontainers.version}
test
+
+
+ com.datastax.astra
+ astra-sdk-devops
+ ${astra-sdk.version}
+ test
+
+
+
+ com.datastax.oss
+ java-driver-query-builder
+ ${datastax.java.driver.version}
+ test
+
org.slf4j
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSet.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSet.java
index cff14e6..07edc07 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSet.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraResultSet.java
@@ -1593,6 +1593,9 @@ public String getColumnTypeName(final int column) {
} else {
dataType = driverResultSet.getColumnDefinitions().get(column - 1).getType();
}
+ if (dataType.toString().contains(DataTypeEnum.VECTOR.cqlType)) {
+ return DataTypeEnum.VECTOR.cqlType;
+ }
return dataType.toString();
}
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java b/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
index 1b03f5c..a1fe3db 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
@@ -21,6 +21,7 @@
import com.datastax.oss.driver.api.core.data.UdtValue;
import com.datastax.oss.driver.api.core.type.DataTypes;
import com.datastax.oss.driver.api.core.type.UserDefinedType;
+import com.datastax.oss.driver.api.core.type.VectorType;
import com.datastax.oss.protocol.internal.ProtocolConstants.DataType;
import javax.annotation.Nonnull;
@@ -169,7 +170,7 @@ public enum DataTypeEnum {
* {@code vector} CQL type (type {@value DataType#LIST} in CQL native protocol) mapped to {@link CqlVector} Java
* type.
*/
- VECTOR(DataType.LIST, CqlVector.class, "vector");
+ VECTOR(DataType.LIST, CqlVector.class, "Vector");
private static final Map CQL_DATATYPE_TO_DATATYPE;
@@ -184,6 +185,8 @@ public enum DataTypeEnum {
final int protocolId;
+ static final String VECTOR_CLASSNAME = "org.apache.cassandra.db.marshal.VectorType";
+
static {
CQL_DATATYPE_TO_DATATYPE = new HashMap<>();
for (final DataTypeEnum dataType : DataTypeEnum.values()) {
@@ -217,6 +220,9 @@ public static DataTypeEnum fromCqlTypeName(final String cqlTypeName) {
if (cqlTypeName.startsWith(UDT.cqlType)) {
return UDT;
}
+ if (cqlTypeName.contains(VECTOR_CLASSNAME)) {
+ return VECTOR;
+ }
// Manage collection types (e.g. "list")
final int collectionTypeCharPos = cqlTypeName.indexOf("<");
String cqlDataType = cqlTypeName;
@@ -236,6 +242,9 @@ public static DataTypeEnum fromDataType(final com.datastax.oss.driver.api.core.t
if (dataType instanceof UserDefinedType) {
return UDT;
}
+ if (dataType instanceof VectorType) {
+ return VECTOR;
+ }
return fromCqlTypeName(dataType.asCql(false, false));
}
@@ -320,12 +329,15 @@ public String toString() {
/**
* Gets the CQL name from a given {@link com.datastax.oss.driver.api.core.type.DataType} instance.
+ * For vectors, dataType.asCql returns looks like 'org.apache.cassandra.db.marshal.VectorType(n)' where n is
+ * the dimension of the vector. In this specific case, return a common name not including the dimension.
*
* @param dataType The data type.
* @return The CQL name of the type.
*/
public static String cqlName(@Nonnull final com.datastax.oss.driver.api.core.type.DataType dataType) {
- return dataType.asCql(false, false);
+ final String rawCql = dataType.asCql(false, false);
+ return rawCql.contains(VECTOR_CLASSNAME) ? VECTOR.cqlType : rawCql;
}
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/DbaasAstraIntegrationTest.java b/src/test/java/com/ing/data/cassandra/jdbc/DbaasAstraIntegrationTest.java
new file mode 100644
index 0000000..c674a9c
--- /dev/null
+++ b/src/test/java/com/ing/data/cassandra/jdbc/DbaasAstraIntegrationTest.java
@@ -0,0 +1,218 @@
+/*
+ * 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 com.ing.data.cassandra.jdbc;
+
+import com.datastax.oss.driver.api.core.type.DataTypes;
+import com.datastax.oss.driver.api.querybuilder.SchemaBuilder;
+import com.dtsx.astra.sdk.db.AstraDbClient;
+import com.dtsx.astra.sdk.db.domain.DatabaseStatusType;
+import com.dtsx.astra.sdk.utils.TestUtils;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * Test JDBC Driver against DbAAS Astra.
+ * To run this test define environment variable ASTRA_DB_APPLICATION_TOKEN
+ * but not having any token does not block the build.
+ */
+@TestMethodOrder(org.junit.jupiter.api.MethodOrderer.OrderAnnotation.class)
+class DbaasAstraIntegrationTest {
+
+ private static final Logger log = LoggerFactory.getLogger(DbaasAstraIntegrationTest.class);
+ private static final String DATABASE_NAME = "test_cassandra_jdbc";
+ private static final String KEYSPACE_NAME = "test";
+ static CassandraConnection sqlConnection = null;
+
+ @BeforeAll
+ static void setupAstra() throws Exception {
+ if (System.getenv("ASTRA_DB_APPLICATION_TOKEN") != null) {
+ log.debug("ASTRA_DB_APPLICATION_TOKEN is provided, Astra Test is executed");
+
+
+ /*
+ * Devops API Client (create database, resume, delete)
+ */
+ AstraDbClient astraDbClient = new AstraDbClient(TestUtils.getAstraToken());
+ log.debug("Connected the dbaas API");
+
+ /*
+ * Set up a Database in Astra : create if not exist, resume if needed
+ * Vector Database is Cassandra DB with vector support enabled.
+ * It can take up to 1 min to create the database if not exists
+ */
+ String dbId = TestUtils.setupVectorDatabase(DATABASE_NAME, KEYSPACE_NAME);
+ Assertions.assertTrue(astraDbClient.findById(dbId).isPresent());
+ Assertions.assertEquals(DatabaseStatusType.ACTIVE, astraDbClient.findById(dbId).get().getStatus());
+ log.debug("Database ready");
+
+ /*
+ * Download cloud secure bundle to connect to the database.
+ * - Saved in /tmp
+ * - Single region = we can use default region
+ */
+ astraDbClient
+ .database(dbId)
+ .downloadDefaultSecureConnectBundle("/tmp/" + DATABASE_NAME + "_scb.zip");
+ log.debug("Connection bundle downloaded.");
+
+ /*
+ * Building jdbcUrl and sqlConnection.
+ * Note: Astra can be access with only a token (username='token')
+ */
+ sqlConnection = (CassandraConnection) DriverManager.getConnection(
+ "jdbc:cassandra://dbaas/" + KEYSPACE_NAME +
+ "?user=" + "token" +
+ "&password=" + TestUtils.getAstraToken() + // env var ASTRA_DB_APPLICATION_TOKEN
+ "&consistency=" + "LOCAL_QUORUM" +
+ "&secureconnectbundle=/tmp/" + DATABASE_NAME + "_scb.zip");
+ } else {
+ log.debug("ASTRA_DB_APPLICATION_TOKEN is not defined, skipping ASTRA test");
+ }
+ }
+
+ @Test
+ @Order(1)
+ @EnabledIfEnvironmentVariable(named = "ASTRA_DB_APPLICATION_TOKEN", matches = "Astra.*")
+ void givenConnection_whenCreateTable_shouldTableExist() throws SQLException {
+ // Given
+ Assertions.assertNotNull(sqlConnection);
+ // When
+ sqlConnection.createStatement().execute(SchemaBuilder
+ .createTable("simple_table")
+ .ifNotExists()
+ .withPartitionKey("email", DataTypes.TEXT)
+ .withColumn("firstname", DataTypes.TEXT)
+ .withColumn("lastname", DataTypes.TEXT)
+ .build().getQuery());
+ // Then
+ Assertions.assertTrue(tableExist("simple_table"));
+ }
+
+ @Test
+ @Order(2)
+ @EnabledIfEnvironmentVariable(named = "ASTRA_DB_APPLICATION_TOKEN", matches = "Astra.*")
+ void givenTable_whenInsert_shouldRetrieveData() throws Exception {
+ // Given
+ Assertions.assertTrue(tableExist("simple_table"));
+ // When
+ String insertSimpleCQL = "INSERT INTO simple_table (email, firstname, lastname) VALUES(?,?,?)";
+ final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement(insertSimpleCQL);
+ prepStatement.setString(1, "pierre.feuille@foo.com");
+ prepStatement.setString(2, "pierre");
+ prepStatement.setString(2, "feuille");
+ prepStatement.execute();
+ // Then (warning on Cassandra expected)
+ Assertions.assertEquals(1, countRecords("simple_table"));
+ }
+
+ @Test
+ @Order(3)
+ @EnabledIfEnvironmentVariable(named = "ASTRA_DB_APPLICATION_TOKEN", matches = "Astra.*")
+ void givenConnection_whenCreateTableVector_shouldTableExist() throws Exception {
+ // When
+ sqlConnection.createStatement().execute("" +
+ "CREATE TABLE IF NOT EXISTS pet_supply_vectors (" +
+ " product_id TEXT PRIMARY KEY," +
+ " product_name TEXT," +
+ " product_vector vector)");
+ // Then
+ Assertions.assertTrue(tableExist("pet_supply_vectors"));
+ sqlConnection.createStatement().execute("" +
+ "CREATE CUSTOM INDEX IF NOT EXISTS idx_vector " +
+ "ON pet_supply_vectors(product_vector) " +
+ "USING 'StorageAttachedIndex'");
+ // When
+ sqlConnection.createStatement().execute("" +
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
+ "VALUES ('pf1843','HealthyFresh - Chicken raw dog food',[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])");
+ sqlConnection.createStatement().execute("" +
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
+ "VALUES ('pf1844','HealthyFresh - Beef raw dog food',[1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0])");
+ sqlConnection.createStatement().execute("" +
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
+ "VALUES ('pt0021','Dog Tennis Ball Toy',[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0])");
+ sqlConnection.createStatement().execute("" +
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
+ "VALUES ('pt0041','Dog Ring Chew Toy',[0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])");
+ sqlConnection.createStatement().execute("" +
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
+ "VALUES ('pf7043','PupperSausage Bacon dog Treats',[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1])");
+ sqlConnection.createStatement().execute("" +
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
+ "VALUES ('pf7044','PupperSausage Beef dog Treats',[0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0])");
+ // Then (warning on Cassandra expected)
+ Assertions.assertEquals(6, countRecords("pet_supply_vectors"));
+ }
+
+ @Test
+ @Order(4)
+ @EnabledIfEnvironmentVariable(named = "ASTRA_DB_APPLICATION_TOKEN", matches = "Astra.*")
+ void givenVectorTable_whenSimilaritySearch_shouldReturnResults() throws Exception {
+ // Given
+ Assertions.assertTrue(tableExist("pet_supply_vectors"));
+ Assertions.assertEquals(6, countRecords("pet_supply_vectors"));
+ // When
+ final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement("" +
+ "SELECT\n" +
+ " product_id, product_vector,\n" +
+ " similarity_dot_product(product_vector,[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) as similarity\n" +
+ "FROM pet_supply_vectors\n" +
+ "ORDER BY product_vector\n" +
+ "ANN OF [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n" +
+ "LIMIT 2;");
+ java.sql.ResultSet rs = prepStatement.executeQuery();
+ // A result has been found
+ Assertions.assertTrue(rs.next());
+ // Parsing Results
+ Assertions.assertNotNull(rs.getObject("product_vector"));
+ Assertions.assertEquals(3.0d, rs.getDouble("similarity"));
+ }
+
+ private boolean tableExist(String tableName) throws SQLException {
+ String existTableCql = "select table_name,keyspace_name from system_schema.tables where keyspace_name=? and table_name=?";
+ final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement(existTableCql);
+ prepStatement.setString(1, KEYSPACE_NAME);
+ prepStatement.setString(2, tableName);
+ return prepStatement.executeQuery().next();
+ }
+
+ private int countRecords(String tablename) throws SQLException {
+ String countRecordsCql = "select count(*) from " + tablename;
+ final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement(countRecordsCql);
+ final ResultSet resultSet = prepStatement.executeQuery();
+ resultSet.next();
+ return resultSet.getInt(1);
+ }
+
+ @AfterAll
+ static void closeSql() throws SQLException {
+ if (sqlConnection != null) {
+ sqlConnection.close();
+ }
+ }
+
+}
+
+
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/UsingDseContainerTest.java b/src/test/java/com/ing/data/cassandra/jdbc/UsingDseContainerTest.java
new file mode 100644
index 0000000..1a34631
--- /dev/null
+++ b/src/test/java/com/ing/data/cassandra/jdbc/UsingDseContainerTest.java
@@ -0,0 +1,74 @@
+/*
+ * 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 com.ing.data.cassandra.jdbc;
+
+import org.apache.commons.lang3.StringUtils;
+import org.junit.jupiter.api.AfterAll;
+import org.testcontainers.containers.CassandraContainer;
+import org.testcontainers.junit.jupiter.Testcontainers;
+import org.testcontainers.utility.DockerImageName;
+
+import java.net.InetSocketAddress;
+import java.sql.DriverManager;
+
+@Testcontainers
+abstract class UsingDseContainerTest {
+
+ static CassandraConnection sqlConnection = null;
+
+ // Using @Container annotation restarts a new container for each test of the class, so as it takes ~20/30 sec. to
+ // start a Cassandra container, we just want to have one container instance for all the tests of the class. See:
+ // https://www.testcontainers.org/test_framework_integration/manual_lifecycle_control/#singleton-containers
+ static CassandraContainer> cassandraContainer;
+
+ protected static void initializeContainer(String version) {
+ DockerImageName dockerImageName = DockerImageName
+ .parse("datastax/dse-server:"+ version)
+ .asCompatibleSubstituteFor("cassandra");
+ cassandraContainer = new CassandraContainer<>(dockerImageName)
+ .withEnv("DS_LICENSE", "accept")
+ .withEnv("CLUSTER_NAME", "embedded_test_cluster")
+ .withEnv("DC", "datacenter1")
+ .withInitScript("initEmbeddedDse.cql");
+ cassandraContainer.start();
+ }
+
+ @AfterAll
+ static void afterTests() throws Exception {
+ if (sqlConnection != null) {
+ sqlConnection.close();
+ }
+ cassandraContainer.stop();
+ }
+
+ static void initConnection(final String keyspace, final String... parameters) throws Exception {
+ sqlConnection = newConnection(keyspace, parameters);
+ }
+
+ static CassandraConnection newConnection(final String keyspace, final String... parameters) throws Exception {
+ final InetSocketAddress contactPoint = cassandraContainer.getContactPoint();
+ return (CassandraConnection) DriverManager.getConnection(buildJdbcUrl(contactPoint.getHostName(),
+ contactPoint.getPort(), keyspace, parameters));
+ }
+
+ static String buildJdbcUrl(final String host, final int port, final String keyspace, final String... parameters) {
+ String joinedParameters = String.join("&", parameters);
+ if (StringUtils.isNotBlank(joinedParameters)) {
+ joinedParameters = StringUtils.prependIfMissing(joinedParameters, "?");
+ }
+
+ return String.format("jdbc:cassandra://%s:%d/%s%s", host, port, keyspace, joinedParameters);
+ }
+
+}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/VectorsDseContainerTest.java b/src/test/java/com/ing/data/cassandra/jdbc/VectorsDseContainerTest.java
new file mode 100644
index 0000000..a123924
--- /dev/null
+++ b/src/test/java/com/ing/data/cassandra/jdbc/VectorsDseContainerTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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 com.ing.data.cassandra.jdbc;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * Test CQL Vector data type
+ */
+class VectorsDseContainerTest extends UsingDseContainerTest {
+
+ private static final String KEYSPACE = "test_keyspace_vect";
+
+ @BeforeAll
+ static void setup() throws Exception {
+ initializeContainer("7.0.0-a");
+ initConnection(KEYSPACE, "version=3.0.0", "localdatacenter=datacenter1");
+ }
+
+ @Test
+ void givenVectorTable_whenSimilaritySearch_shouldReturnResults() throws Exception {
+ // When
+ final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement("" +
+ "SELECT\n" +
+ " product_id, product_vector,\n" +
+ " similarity_dot_product(product_vector,[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) as similarity\n" +
+ "FROM pet_supply_vectors\n" +
+ "ORDER BY product_vector\n" +
+ "ANN OF [1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]\n" +
+ "LIMIT 2;");
+ java.sql.ResultSet rs = prepStatement.executeQuery();
+ // A result has been found
+ Assertions.assertTrue(rs.next());
+ // Parsing Results
+ Assertions.assertNotNull(rs.getObject("product_vector"));
+ Assertions.assertEquals(3.0d, rs.getDouble("similarity"));
+ }
+
+}
diff --git a/src/test/resources/initEmbeddedDse.cql b/src/test/resources/initEmbeddedDse.cql
new file mode 100644
index 0000000..c5b41cd
--- /dev/null
+++ b/src/test/resources/initEmbeddedDse.cql
@@ -0,0 +1,33 @@
+/* Init keyspace and tables for VectorsUnitTest */
+DROP KEYSPACE IF EXISTS test_keyspace_vect;
+CREATE KEYSPACE "test_keyspace_vect" WITH replication = {'class': 'SimpleStrategy', 'replication_factor': 1};
+
+USE test_keyspace_vect;
+
+CREATE TABLE IF NOT EXISTS pet_supply_vectors (
+ product_id TEXT PRIMARY KEY,
+ product_name TEXT,
+ product_vector vector
+);
+
+/* Ni similarity search without the SAI INDEX. */
+CREATE CUSTOM INDEX IF NOT EXISTS idx_vector
+ON pet_supply_vectors(product_vector)
+USING 'StorageAttachedIndex';
+
+INSERT INTO pet_supply_vectors (product_id, product_name, product_vector)
+VALUES ('pf1843','HealthyFresh - Chicken raw dog food',[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
+
+INSERT INTO pet_supply_vectors (product_id, product_name, product_vector)
+VALUES ('pf1844','HealthyFresh - Beef raw dog food',[1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
+INSERT INTO pet_supply_vectors (product_id, product_name, product_vector)
+VALUES ('pt0021','Dog Tennis Ball Toy',[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0]);
+
+INSERT INTO pet_supply_vectors (product_id, product_name, product_vector)
+VALUES ('pt0041','Dog Ring Chew Toy',[0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0]);
+
+INSERT INTO pet_supply_vectors (product_id, product_name, product_vector)
+VALUES ('pf7043','PupperSausage Bacon dog Treats',[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1]);
+
+INSERT INTO pet_supply_vectors (product_id, product_name, product_vector)
+VALUES ('pf7044','PupperSausage Beef dog Treats',[0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0]);
From 20a22642ee02e2b1ef7036e0eb84e48b2a7880ac Mon Sep 17 00:00:00 2001
From: Maxime Wiewiora <48218208+maximevw@users.noreply.github.com>
Date: Sat, 30 Sep 2023 13:36:37 +0200
Subject: [PATCH 21/21] Prepare version 4.10.0
- Add vectors similarity functions from CEP-30 into the numeric functions
listed into the DatabaseMetadata.
- Allow disabling DSE tests using Maven profile.
---
CHANGELOG.md | 5 +-
README.md | 33 +++++--
pom.xml | 29 +++++-
.../jdbc/CassandraDatabaseMetaData.java | 7 +-
.../TableMetadataResultSetBuilder.java | 4 +-
.../cassandra/jdbc/types/DataTypeEnum.java | 10 +-
.../jdbc/DbaasAstraIntegrationTest.java | 93 ++++++++++---------
.../cassandra/jdbc/UsingDseContainerTest.java | 8 +-
.../jdbc/VectorsDseContainerTest.java | 12 +--
src/test/resources/initEmbeddedDse.cql | 1 +
10 files changed, 123 insertions(+), 79 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fadcdaf..28de2a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,10 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [4.10.0] - Unreleased
+## [4.10.0] - 2023-09-30
### Added
- Add support for new [`vector` CQL type](https://datastax-oss.atlassian.net/browse/JAVA-3060)
- defined in [CEP-30](https://cwiki.apache.org/confluence/x/OQ40Dw).
+ defined in [CEP-30](https://cwiki.apache.org/confluence/x/OQ40Dw)
+ Also see PR [#27](https://github.com/ing-bank/cassandra-jdbc-wrapper/pull/27).
- Implement the method `getWarnings()` in `CassandraResultSet`.
- Implement the following methods of `CassandraDatabaseMetaData`:
`getBestRowIdentifier(String, String, String, int, boolean)` and `getAttributes(String, String, String, String)`.
diff --git a/README.md b/README.md
index b864742..3924a0a 100644
--- a/README.md
+++ b/README.md
@@ -49,6 +49,17 @@ To compile and run tests, execute the following Maven command:
```bash
mvn clean package
```
+
+#### Some considerations about running tests
+
+If for some reason the tests using DataStax Enterprise server (`*DseContainerTest`) fail in your local environment, you
+might disable them using the Maven profile `disableDseTests`:
+```bash
+mvn clean package -PdisableDseTests
+```
+
+The test suite also includes integration tests with AstraDB (`DbaasAstraIntegrationTest`). These tests require an
+AstraDB token configured in the environment variable `ASTRA_DB_APPLICATION_TOKEN`, otherwise they are skipped.
### Integration in Maven projects
@@ -265,8 +276,11 @@ For further information about custom implementations of `SslEngineFactory`, see
### Connecting to DBaaS
-In order to connect to the cloud [Cassandra-based DBaaS AstraDB](https://www.datastax.com/astra) cluster, one would
-need to specify:
+An alternative JDBC driver based on this one exists to ease the connection to the cloud
+[Cassandra-based DBaaS AstraDB](https://www.datastax.com/astra) cluster:
+[Astra JDBC driver](https://github.com/DataStax-Examples/astra-jdbc-connector/tree/main). Do not hesitate to use it if you are in this specific situation.
+
+It's still possible to connect to AstraDB using this JDBC wrapper, so one would need to specify:
* `secureconnectbundle`: the fully qualified path of the cloud secure connect bundle file
* `keyspace`: the keyspace to connect to
* `user`: the username
@@ -352,7 +366,8 @@ CREATE TABLE example_table (
varint_col varint,
string_set_col set,
string_list_col list,
- string_map_col map
+ string_map_col map,
+ vector_col vector
);
```
@@ -360,6 +375,7 @@ To insert a record into `example_table` using a prepared statement:
```java
import com.datastax.oss.driver.api.core.data.CqlDuration;
+import com.datastax.oss.driver.api.core.data.CqlVector;
import java.io.ByteArrayInputStream;
import java.sql.Date;
@@ -370,8 +386,8 @@ public class HelloCassandra {
final String insertCql = "INSERT INTO example_table (bigint_col, ascii_col, blob_col, boolean_col, decimal_col, "
+ "double_col, float_col, inet_col, int_col, smallint_col, text_col, timestamp_col, time_col, date_col, "
+ "tinyint_col, duration_col, uuid_col, timeuuid_col, varchar_col, varint_col, string_set_col, "
- + "string_list_col, string_map_col) "
- + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, now(), ?, ?, ?, ?, ?);";
+ + "string_list_col, string_map_col, vector_col) "
+ + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, now(), ?, ?, ?, ?, ?, ?);";
final PreparedStatement preparedStatement = connection.prepareStatement(insertCql);
preparedStatement.setObject(1, 1L); // bigint
preparedStatement.setObject(2, "test"); // ascii
@@ -401,14 +417,16 @@ public class HelloCassandra {
sampleSet.add("test1");
sampleSet.add("test2");
preparedStatement.setObject(20, sampleSet); // set
- ArrayList sampleList = new ArrayList();
+ final ArrayList sampleList = new ArrayList();
sampleList.add("test1");
sampleList.add("test2");
preparedStatement.setObject(21, sampleList); // list
- HashMap sampleMap = new HashMap();
+ final HashMap sampleMap = new HashMap();
sampleMap.put("1", "test1");
sampleMap.put("2", "test2");
preparedStatement.setObject(22, sampleMap); // map
+ final CqlVector sampleVector = CqlVector.newInstance(1.0f, 0.0f, 1.0f, 0.5f, 0.2f);
+ preparedStatement.setObject(23, sampleVector); // vector
// Execute the prepare statement.
preparedStatement.execute();
}
@@ -696,6 +714,7 @@ We use [SemVer](http://semver.org/) for versioning.
* Madhavan Sridharan - **[@msmygit](https://github.com/msmygit)**
* Marius Jokubauskas - **[@mjok](https://github.com/mjok)**
* Sualeh Fatehi - **[@sualeh](https://github.com/sualeh)**
+* Cedrick Lunven - **[@clun](https://github.com/clun)**
And special thanks to the developer of the original project on which is based this one:
* Alexander Dejanovski - **[@adejanovski](https://github.com/adejanovski)**
diff --git a/pom.xml b/pom.xml
index 36ee2e8..f79a208 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
com.ing.data
cassandra-jdbc-wrapper
- 4.9.1
+ 4.10.0
jar
Cassandra JDBC Wrapper
@@ -109,10 +109,10 @@
2.2
5.10.0
1.10.0
- 1.18.28
+ 1.18.30
3.12.4
1.7.36
- 1.18.3
+ 1.19.0
0.6.11
3.3.0
@@ -241,14 +241,14 @@
${testcontainers.version}
test
-
+
com.datastax.astra
astra-sdk-devops
${astra-sdk.version}
test
-
+
com.datastax.oss
java-driver-query-builder
@@ -461,5 +461,24 @@
+
+
+
+ disableDseTests
+
+
+
+ maven-surefire-plugin
+ ${maven-surefire-plugin.version}
+
+
+ *DseContainerTest.java
+
+
+
+
+
+
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
index 3ca43ca..8c7bce8 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/CassandraDatabaseMetaData.java
@@ -511,8 +511,9 @@ public int getMaxUserNameLength() {
@Override
public String getNumericFunctions() throws SQLException {
checkStatementClosed();
- // Cassandra does not implement natively numeric functions.
- return StringUtils.EMPTY;
+ // We consider here the vectors similarity functions introduced by CEP-30 as numeric functions (see
+ // https://issues.apache.org/jira/browse/CASSANDRA-18640).
+ return "similarity_cosine,similarity_euclidean,similarity_dot_product";
}
@Override
@@ -779,7 +780,7 @@ public String getTimeDateFunctions() throws SQLException {
checkStatementClosed();
// See: https://cassandra.apache.org/doc/latest/cassandra/cql/functions.html
return "dateOf,now,minTimeuuid,maxTimeuuid,unixTimestampOf,toDate,toTimestamp,toUnixTimestamp,currentTimestamp,"
- + "currentDate,currentTime,currentTimeUUID,";
+ + "currentDate,currentTime,currentTimeUUID";
}
@Override
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/metadata/TableMetadataResultSetBuilder.java b/src/main/java/com/ing/data/cassandra/jdbc/metadata/TableMetadataResultSetBuilder.java
index b7346f4..b458deb 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/metadata/TableMetadataResultSetBuilder.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/metadata/TableMetadataResultSetBuilder.java
@@ -330,8 +330,8 @@ public CassandraMetadataResultSet buildPrimaryKeys(final String schema, final St
*
*
* @param schema A schema name pattern. It must match the schema name as it is stored in the database; {@code ""}
- * retrieves those without a schema and {@code null} means that the schema name should not be used to
- * narrow the search. Using {@code ""} as the same effect as {@code null} because here the schema
+ * retrieves those without a schema and {@code null} means that the schema name should not be used
+ * to narrow the search. Using {@code ""} as the same effect as {@code null} because here the schema
* corresponds to the keyspace and Cassandra tables cannot be defined outside a keyspace.
* @param table A table name. It must match the table name as it is stored in the database.
* @param scope The scope of interest, using the same values as {@code SCOPE} in the result set.
diff --git a/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java b/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
index a1fe3db..ff34159 100644
--- a/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
+++ b/src/main/java/com/ing/data/cassandra/jdbc/types/DataTypeEnum.java
@@ -172,6 +172,8 @@ public enum DataTypeEnum {
*/
VECTOR(DataType.LIST, CqlVector.class, "Vector");
+ static final String VECTOR_CLASSNAME = "org.apache.cassandra.db.marshal.VectorType";
+
private static final Map CQL_DATATYPE_TO_DATATYPE;
/**
@@ -185,8 +187,6 @@ public enum DataTypeEnum {
final int protocolId;
- static final String VECTOR_CLASSNAME = "org.apache.cassandra.db.marshal.VectorType";
-
static {
CQL_DATATYPE_TO_DATATYPE = new HashMap<>();
for (final DataTypeEnum dataType : DataTypeEnum.values()) {
@@ -220,6 +220,7 @@ public static DataTypeEnum fromCqlTypeName(final String cqlTypeName) {
if (cqlTypeName.startsWith(UDT.cqlType)) {
return UDT;
}
+ // Manage vector type
if (cqlTypeName.contains(VECTOR_CLASSNAME)) {
return VECTOR;
}
@@ -337,7 +338,10 @@ public String toString() {
*/
public static String cqlName(@Nonnull final com.datastax.oss.driver.api.core.type.DataType dataType) {
final String rawCql = dataType.asCql(false, false);
- return rawCql.contains(VECTOR_CLASSNAME) ? VECTOR.cqlType : rawCql;
+ if (rawCql.contains(VECTOR_CLASSNAME)) {
+ return VECTOR.cqlType;
+ }
+ return rawCql;
}
}
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/DbaasAstraIntegrationTest.java b/src/test/java/com/ing/data/cassandra/jdbc/DbaasAstraIntegrationTest.java
index c674a9c..27252f0 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/DbaasAstraIntegrationTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/DbaasAstraIntegrationTest.java
@@ -33,39 +33,41 @@
import java.sql.SQLException;
/**
- * Test JDBC Driver against DbAAS Astra.
- * To run this test define environment variable ASTRA_DB_APPLICATION_TOKEN
+ * Test JDBC Driver against DBaaS Astra.
+ * To run this test class, define an environment variable ASTRA_DB_APPLICATION_TOKEN containing the AstraDB token,
* but not having any token does not block the build.
*/
@TestMethodOrder(org.junit.jupiter.api.MethodOrderer.OrderAnnotation.class)
class DbaasAstraIntegrationTest {
private static final Logger log = LoggerFactory.getLogger(DbaasAstraIntegrationTest.class);
+ private static final String ASTRA_DB_TOKEN_ENV_VARIABLE = "ASTRA_DB_APPLICATION_TOKEN";
+ private static final String ASTRA_DB_TOKEN_PATTERN = "Astra.*";
private static final String DATABASE_NAME = "test_cassandra_jdbc";
private static final String KEYSPACE_NAME = "test";
+
static CassandraConnection sqlConnection = null;
@BeforeAll
static void setupAstra() throws Exception {
- if (System.getenv("ASTRA_DB_APPLICATION_TOKEN") != null) {
- log.debug("ASTRA_DB_APPLICATION_TOKEN is provided, Astra Test is executed");
-
+ if (System.getenv(ASTRA_DB_TOKEN_ENV_VARIABLE) != null) {
+ log.debug("ASTRA_DB_APPLICATION_TOKEN is provided, AstraDB tests are executed.");
/*
* Devops API Client (create database, resume, delete)
*/
- AstraDbClient astraDbClient = new AstraDbClient(TestUtils.getAstraToken());
- log.debug("Connected the dbaas API");
+ final AstraDbClient astraDbClient = new AstraDbClient(TestUtils.getAstraToken());
+ log.debug("Connected the DBaaS API.");
/*
- * Set up a Database in Astra : create if not exist, resume if needed
+ * Set up a Database in Astra: create if not exist, resume if needed.
* Vector Database is Cassandra DB with vector support enabled.
- * It can take up to 1 min to create the database if not exists
+ * It can take up to 1 min to create the database if not exists.
*/
String dbId = TestUtils.setupVectorDatabase(DATABASE_NAME, KEYSPACE_NAME);
Assertions.assertTrue(astraDbClient.findById(dbId).isPresent());
Assertions.assertEquals(DatabaseStatusType.ACTIVE, astraDbClient.findById(dbId).get().getStatus());
- log.debug("Database ready");
+ log.debug("Database ready.");
/*
* Download cloud secure bundle to connect to the database.
@@ -79,7 +81,7 @@ static void setupAstra() throws Exception {
/*
* Building jdbcUrl and sqlConnection.
- * Note: Astra can be access with only a token (username='token')
+ * Note: Astra can be accessed with only a token (username='token').
*/
sqlConnection = (CassandraConnection) DriverManager.getConnection(
"jdbc:cassandra://dbaas/" + KEYSPACE_NAME +
@@ -88,13 +90,13 @@ static void setupAstra() throws Exception {
"&consistency=" + "LOCAL_QUORUM" +
"&secureconnectbundle=/tmp/" + DATABASE_NAME + "_scb.zip");
} else {
- log.debug("ASTRA_DB_APPLICATION_TOKEN is not defined, skipping ASTRA test");
+ log.debug("ASTRA_DB_APPLICATION_TOKEN is not defined, skipping AstraDB tests.");
}
}
@Test
@Order(1)
- @EnabledIfEnvironmentVariable(named = "ASTRA_DB_APPLICATION_TOKEN", matches = "Astra.*")
+ @EnabledIfEnvironmentVariable(named = ASTRA_DB_TOKEN_ENV_VARIABLE, matches = ASTRA_DB_TOKEN_PATTERN)
void givenConnection_whenCreateTable_shouldTableExist() throws SQLException {
// Given
Assertions.assertNotNull(sqlConnection);
@@ -107,15 +109,15 @@ void givenConnection_whenCreateTable_shouldTableExist() throws SQLException {
.withColumn("lastname", DataTypes.TEXT)
.build().getQuery());
// Then
- Assertions.assertTrue(tableExist("simple_table"));
+ Assertions.assertTrue(tableExists("simple_table"));
}
@Test
@Order(2)
- @EnabledIfEnvironmentVariable(named = "ASTRA_DB_APPLICATION_TOKEN", matches = "Astra.*")
+ @EnabledIfEnvironmentVariable(named = ASTRA_DB_TOKEN_ENV_VARIABLE, matches = ASTRA_DB_TOKEN_PATTERN)
void givenTable_whenInsert_shouldRetrieveData() throws Exception {
// Given
- Assertions.assertTrue(tableExist("simple_table"));
+ Assertions.assertTrue(tableExists("simple_table"));
// When
String insertSimpleCQL = "INSERT INTO simple_table (email, firstname, lastname) VALUES(?,?,?)";
final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement(insertSimpleCQL);
@@ -129,52 +131,52 @@ void givenTable_whenInsert_shouldRetrieveData() throws Exception {
@Test
@Order(3)
- @EnabledIfEnvironmentVariable(named = "ASTRA_DB_APPLICATION_TOKEN", matches = "Astra.*")
+ @EnabledIfEnvironmentVariable(named = ASTRA_DB_TOKEN_ENV_VARIABLE, matches = ASTRA_DB_TOKEN_PATTERN)
void givenConnection_whenCreateTableVector_shouldTableExist() throws Exception {
// When
- sqlConnection.createStatement().execute("" +
+ sqlConnection.createStatement().execute(
"CREATE TABLE IF NOT EXISTS pet_supply_vectors (" +
" product_id TEXT PRIMARY KEY," +
" product_name TEXT," +
" product_vector vector)");
// Then
- Assertions.assertTrue(tableExist("pet_supply_vectors"));
- sqlConnection.createStatement().execute("" +
+ Assertions.assertTrue(tableExists("pet_supply_vectors"));
+ sqlConnection.createStatement().execute(
"CREATE CUSTOM INDEX IF NOT EXISTS idx_vector " +
"ON pet_supply_vectors(product_vector) " +
"USING 'StorageAttachedIndex'");
// When
- sqlConnection.createStatement().execute("" +
- "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
- "VALUES ('pf1843','HealthyFresh - Chicken raw dog food',[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])");
- sqlConnection.createStatement().execute("" +
- "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
- "VALUES ('pf1844','HealthyFresh - Beef raw dog food',[1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0])");
- sqlConnection.createStatement().execute("" +
- "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
- "VALUES ('pt0021','Dog Tennis Ball Toy',[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0])");
- sqlConnection.createStatement().execute("" +
- "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
- "VALUES ('pt0041','Dog Ring Chew Toy',[0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])");
- sqlConnection.createStatement().execute("" +
- "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
- "VALUES ('pf7043','PupperSausage Bacon dog Treats',[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1])");
- sqlConnection.createStatement().execute("" +
- "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) " +
- "VALUES ('pf7044','PupperSausage Beef dog Treats',[0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0])");
+ sqlConnection.createStatement().execute(
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) "
+ + "VALUES ('pf1843','HealthyFresh - Chicken raw dog food',[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0])");
+ sqlConnection.createStatement().execute(
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) "
+ + "VALUES ('pf1844','HealthyFresh - Beef raw dog food',[1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0])");
+ sqlConnection.createStatement().execute(
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) "
+ + "VALUES ('pt0021','Dog Tennis Ball Toy',[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0])");
+ sqlConnection.createStatement().execute(
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) "
+ + "VALUES ('pt0041','Dog Ring Chew Toy',[0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0])");
+ sqlConnection.createStatement().execute(
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) "
+ + "VALUES ('pf7043','PupperSausage Bacon dog Treats',[0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1])");
+ sqlConnection.createStatement().execute(
+ "INSERT INTO pet_supply_vectors (product_id, product_name, product_vector) "
+ + "VALUES ('pf7044','PupperSausage Beef dog Treats',[0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0])");
// Then (warning on Cassandra expected)
Assertions.assertEquals(6, countRecords("pet_supply_vectors"));
}
@Test
@Order(4)
- @EnabledIfEnvironmentVariable(named = "ASTRA_DB_APPLICATION_TOKEN", matches = "Astra.*")
+ @EnabledIfEnvironmentVariable(named = ASTRA_DB_TOKEN_ENV_VARIABLE, matches = ASTRA_DB_TOKEN_PATTERN)
void givenVectorTable_whenSimilaritySearch_shouldReturnResults() throws Exception {
// Given
- Assertions.assertTrue(tableExist("pet_supply_vectors"));
+ Assertions.assertTrue(tableExists("pet_supply_vectors"));
Assertions.assertEquals(6, countRecords("pet_supply_vectors"));
// When
- final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement("" +
+ final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement(
"SELECT\n" +
" product_id, product_vector,\n" +
" similarity_dot_product(product_vector,[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) as similarity\n" +
@@ -190,16 +192,17 @@ void givenVectorTable_whenSimilaritySearch_shouldReturnResults() throws Exceptio
Assertions.assertEquals(3.0d, rs.getDouble("similarity"));
}
- private boolean tableExist(String tableName) throws SQLException {
- String existTableCql = "select table_name,keyspace_name from system_schema.tables where keyspace_name=? and table_name=?";
+ private boolean tableExists(final String tableName) throws SQLException {
+ final String existTableCql =
+ "select table_name,keyspace_name from system_schema.tables where keyspace_name=? and table_name=?";
final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement(existTableCql);
prepStatement.setString(1, KEYSPACE_NAME);
prepStatement.setString(2, tableName);
return prepStatement.executeQuery().next();
}
- private int countRecords(String tablename) throws SQLException {
- String countRecordsCql = "select count(*) from " + tablename;
+ private int countRecords(final String tableName) throws SQLException {
+ String countRecordsCql = "select count(*) from " + tableName;
final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement(countRecordsCql);
final ResultSet resultSet = prepStatement.executeQuery();
resultSet.next();
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/UsingDseContainerTest.java b/src/test/java/com/ing/data/cassandra/jdbc/UsingDseContainerTest.java
index 1a34631..b1705ab 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/UsingDseContainerTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/UsingDseContainerTest.java
@@ -32,11 +32,11 @@ abstract class UsingDseContainerTest {
// https://www.testcontainers.org/test_framework_integration/manual_lifecycle_control/#singleton-containers
static CassandraContainer> cassandraContainer;
- protected static void initializeContainer(String version) {
- DockerImageName dockerImageName = DockerImageName
- .parse("datastax/dse-server:"+ version)
+ protected static void initializeContainer() {
+ // For the official DataStax Enterprise server image, see here: https://hub.docker.com/r/datastax/dse-server/
+ final DockerImageName dseServerImage = DockerImageName.parse("datastax/dse-server:7.0.0-a")
.asCompatibleSubstituteFor("cassandra");
- cassandraContainer = new CassandraContainer<>(dockerImageName)
+ cassandraContainer = new CassandraContainer<>(dseServerImage)
.withEnv("DS_LICENSE", "accept")
.withEnv("CLUSTER_NAME", "embedded_test_cluster")
.withEnv("DC", "datacenter1")
diff --git a/src/test/java/com/ing/data/cassandra/jdbc/VectorsDseContainerTest.java b/src/test/java/com/ing/data/cassandra/jdbc/VectorsDseContainerTest.java
index a123924..6bc816c 100644
--- a/src/test/java/com/ing/data/cassandra/jdbc/VectorsDseContainerTest.java
+++ b/src/test/java/com/ing/data/cassandra/jdbc/VectorsDseContainerTest.java
@@ -17,27 +17,23 @@
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
-import static org.hamcrest.CoreMatchers.is;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-
/**
- * Test CQL Vector data type
+ * Test CQL Vector data type using DataStax Enterprise.
*/
class VectorsDseContainerTest extends UsingDseContainerTest {
private static final String KEYSPACE = "test_keyspace_vect";
@BeforeAll
- static void setup() throws Exception {
- initializeContainer("7.0.0-a");
+ static void finalizeSetUpTests() throws Exception {
+ initializeContainer();
initConnection(KEYSPACE, "version=3.0.0", "localdatacenter=datacenter1");
}
@Test
void givenVectorTable_whenSimilaritySearch_shouldReturnResults() throws Exception {
// When
- final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement("" +
+ final CassandraPreparedStatement prepStatement = sqlConnection.prepareStatement(
"SELECT\n" +
" product_id, product_vector,\n" +
" similarity_dot_product(product_vector,[1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) as similarity\n" +
diff --git a/src/test/resources/initEmbeddedDse.cql b/src/test/resources/initEmbeddedDse.cql
index c5b41cd..8568e6e 100644
--- a/src/test/resources/initEmbeddedDse.cql
+++ b/src/test/resources/initEmbeddedDse.cql
@@ -20,6 +20,7 @@ VALUES ('pf1843','HealthyFresh - Chicken raw dog food',[1, 1, 1, 1, 1, 0, 0, 0,
INSERT INTO pet_supply_vectors (product_id, product_name, product_vector)
VALUES ('pf1844','HealthyFresh - Beef raw dog food',[1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]);
+
INSERT INTO pet_supply_vectors (product_id, product_name, product_vector)
VALUES ('pt0021','Dog Tennis Ball Toy',[0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0]);