Skip to content

Commit 71546e6

Browse files
committed
Fix issues #33 and #35
- handle VARBINARY and LONGVARBINARY types with either ByteArrayInputStream or byte[] in the methods CassandraPreparedStatement.setObject(). - fix configuration of the local datacenter using the one from the configuration file when such a file is used.
1 parent 5f9fda7 commit 71546e6

File tree

7 files changed

+151
-10
lines changed

7 files changed

+151
-10
lines changed

Diff for: CHANGELOG.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,21 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to
55
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
66

7+
## [4.10.2] - 2023-11-01
8+
### Fixed
9+
- Fix issue [#33](https://github.com/ing-bank/cassandra-jdbc-wrapper/issues/33) to handle `VARBINARY` and
10+
`LONGVARBINARY` types with either `ByteArrayInputStream` or `byte[]` in the methods
11+
`CassandraPreparedStatement.setObject()`.
12+
- Fix issue [#35](https://github.com/ing-bank/cassandra-jdbc-wrapper/issues/35) to fix configuration of the local
13+
datacenter using the one from the configuration file when such a file is used.
14+
715
## [4.10.1] - 2023-10-07
816
### Changed
917
- Update Apache Commons IO to version 2.14.0.
1018
- Harmonize logging.
1119
### Fixed
12-
- Fix multiple issues related to the method `findColumn(String)` of `CassandraResultSet` and `CassandraMetadataResultSet`:
20+
- Fix multiple issues related to the method `findColumn(String)` of `CassandraResultSet` and
21+
`CassandraMetadataResultSet`:
1322
- Fix issue [#31](https://github.com/ing-bank/cassandra-jdbc-wrapper/issues/31) to return a 1-based index value.
1423
- Return a result even if there's no row in the result set but the column exist in the statement.
1524
- Fix the exception thrown by the method when the given column name does not exist in the result set (was an
@@ -162,6 +171,7 @@ For this version, the changelog lists the main changes comparatively to the late
162171
- Fix logs in `CassandraConnection` constructor.
163172

164173
[original project]: https://github.com/adejanovski/cassandra-jdbc-wrapper/
174+
[4.10.2]: https://github.com/ing-bank/cassandra-jdbc-wrapper/compare/v4.10.1...v4.10.2
165175
[4.10.1]: https://github.com/ing-bank/cassandra-jdbc-wrapper/compare/v4.10.0...v4.10.1
166176
[4.10.0]: https://github.com/ing-bank/cassandra-jdbc-wrapper/compare/v4.9.1...v4.10.0
167177
[4.9.1]: https://github.com/ing-bank/cassandra-jdbc-wrapper/compare/v4.9.0...v4.9.1

Diff for: pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
<groupId>com.ing.data</groupId>
77
<artifactId>cassandra-jdbc-wrapper</artifactId>
8-
<version>4.10.1</version>
8+
<version>4.10.2</version>
99
<packaging>jar</packaging>
1010

1111
<name>Cassandra JDBC Wrapper</name>

Diff for: src/main/java/com/ing/data/cassandra/jdbc/CassandraPreparedStatement.java

+16-5
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,8 @@ public void setObject(final int parameterIndex, final Object x) throws SQLExcept
495495
targetType = Types.BIGINT;
496496
} else if (x.getClass().equals(ByteArrayInputStream.class)) {
497497
targetType = Types.BINARY;
498+
} else if (x instanceof byte[]) {
499+
targetType = Types.BINARY;
498500
} else if (x.getClass().equals(String.class)) {
499501
targetType = Types.VARCHAR;
500502
} else if (x.getClass().equals(Boolean.class)) {
@@ -554,11 +556,20 @@ public final void setObject(final int parameterIndex, final Object x, final int
554556
}
555557
break;
556558
case Types.BINARY:
557-
final byte[] array = new byte[((ByteArrayInputStream) x).available()];
558-
try {
559-
((ByteArrayInputStream) x).read(array);
560-
} catch (final IOException e) {
561-
LOG.warn("Exception while setting object of BINARY type.", e);
559+
case Types.VARBINARY:
560+
case Types.LONGVARBINARY:
561+
final byte[] array;
562+
if (x instanceof ByteArrayInputStream) {
563+
array = new byte[((ByteArrayInputStream) x).available()];
564+
try {
565+
((ByteArrayInputStream) x).read(array);
566+
} catch (final IOException e) {
567+
LOG.warn("Exception while setting object of BINARY/VARBINARY/LONGVARBINARY type.", e);
568+
}
569+
} else if (x instanceof byte[]) {
570+
array = (byte[]) x;
571+
} else {
572+
throw new SQLException("Unsupported parameter type: " + x.getClass());
562573
}
563574
this.boundStatement = this.boundStatement.setByteBuffer(parameterIndex - 1, ByteBuffer.wrap(array));
564575
break;

Diff for: src/main/java/com/ing/data/cassandra/jdbc/SessionHolder.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -183,10 +183,12 @@ boolean acquire() {
183183

184184
private Session createSession(final Properties properties) throws SQLException {
185185
File configurationFile = null;
186+
boolean configurationFileExists = false;
186187
final String configurationFilePath = properties.getProperty(TAG_CONFIG_FILE, StringUtils.EMPTY);
187188
if (StringUtils.isNotBlank(configurationFilePath)) {
188189
configurationFile = new File(configurationFilePath);
189-
if (configurationFile.exists()) {
190+
configurationFileExists = configurationFile.exists();
191+
if (configurationFileExists) {
190192
// We remove some parameters to use the values defined into the specified configuration file
191193
// instead.
192194
this.properties.remove(TAG_CONSISTENCY_LEVEL);
@@ -264,7 +266,13 @@ private Session createSession(final Properties properties) throws SQLException {
264266
}
265267

266268
// The DefaultLoadBalancingPolicy requires to specify a local data center.
267-
builder.withLocalDatacenter(localDatacenter);
269+
// Note (issue #35): This should only be set programmatically when there is no configuration file specified.
270+
// When a configuration file is used, we rely on the property 'basic.load-balancing-policy.local-datacenter'
271+
// of the configuration file, so we must not call withLocalDatacenter() method because when both are specified,
272+
// the programmatic value takes precedence.
273+
if (configurationFile == null || !configurationFileExists) {
274+
builder.withLocalDatacenter(localDatacenter);
275+
}
268276
if (loadBalancingPolicy.length() > 0) {
269277
// if a custom load balancing policy has been given in the JDBC URL, parse it and add it to the cluster
270278
// builder.

Diff for: src/test/java/com/ing/data/cassandra/jdbc/ConnectionUnitTest.java

+35-1
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
import org.slf4j.LoggerFactory;
4242

4343
import java.net.URL;
44+
import java.nio.charset.StandardCharsets;
45+
import java.nio.file.Files;
46+
import java.nio.file.Path;
47+
import java.nio.file.Paths;
4448
import java.sql.Connection;
4549
import java.sql.DatabaseMetaData;
4650
import java.sql.ResultSet;
@@ -83,7 +87,8 @@ class ConnectionUnitTest extends UsingCassandraContainerTest {
8387

8488
@Test
8589
void givenInvalidConfigurationFile_whenGetConnection_createConnectionIgnoringConfigFile() throws Exception {
86-
initConnection(KEYSPACE, "configfile=wrong_application.conf", "consistency=LOCAL_QUORUM");
90+
initConnection(KEYSPACE, "configfile=wrong_application.conf", "consistency=LOCAL_QUORUM",
91+
"localdatacenter=datacenter1");
8792
assertNotNull(sqlConnection);
8893
assertNotNull(sqlConnection.getDefaultConsistencyLevel());
8994
final ConsistencyLevel consistencyLevel = sqlConnection.getDefaultConsistencyLevel();
@@ -377,6 +382,35 @@ void givenEnabledSslWithJsse_whenConfigureSsl_addDefaultSslEngineFactoryToSessio
377382
sqlConnection.close();
378383
}
379384

385+
@Test
386+
void givenConfigurationFileWithSslEnabled_whenGetConnection_createConnectionWithExpectedConfig() throws Exception {
387+
final ClassLoader classLoader = this.getClass().getClassLoader();
388+
final URL confTestUrl = classLoader.getResource("test_application_with_ssl.conf");
389+
if (confTestUrl == null) {
390+
fail("Unable to find test_application_with_ssl.conf");
391+
}
392+
393+
// Update the truststore path in the configuration file and store the modified file in a temporary location.
394+
String content = new String(Files.readAllBytes(Paths.get(confTestUrl.toURI())));
395+
content = content.replaceAll("\\$TRUSTSTORE_PATH",
396+
Objects.requireNonNull(classLoader.getResource("cassandra.truststore")).getPath());
397+
final Path updatedConfTestPath = Files.createTempFile("test_application_with_ssl_", ".conf");
398+
Files.write(updatedConfTestPath, content.getBytes(StandardCharsets.UTF_8));
399+
400+
initConnection(KEYSPACE, "configfile=" + updatedConfTestPath);
401+
assertNotNull(sqlConnection);
402+
assertNotNull(sqlConnection.getSession());
403+
assertNotNull(sqlConnection.getSession().getContext());
404+
assertTrue(sqlConnection.getSession().getContext().getSslEngineFactory().isPresent());
405+
406+
final Statement statement = sqlConnection.createStatement();
407+
final ResultSet resultSet = statement.executeQuery("SELECT * FROM system.local");
408+
assertNotNull(resultSet);
409+
resultSet.close();
410+
statement.close();
411+
sqlConnection.close();
412+
}
413+
380414
@Test
381415
void givenSslEngineFactory_whenConfigureSsl_addGivenSslEngineFactoryToSessionBuilder() throws Exception {
382416
final SessionHolder sessionHolder = new SessionHolder(Collections.singletonMap(URL_KEY,

Diff for: src/test/java/com/ing/data/cassandra/jdbc/JdbcRegressionUnitTest.java

+48
Original file line numberDiff line numberDiff line change
@@ -984,4 +984,52 @@ void testIngIssue13_ResultSet() throws Exception {
984984
"Cassandra results cannot be unwrapped to String");
985985
}
986986
}
987+
988+
@Test
989+
@SuppressWarnings("ResultOfMethodCallIgnored")
990+
void testIngIssue33() throws Exception {
991+
final Statement stmt = sqlConnection.createStatement();
992+
993+
// Create the target table.
994+
final String createTableQuery = "CREATE TABLE t33_blob (key int PRIMARY KEY, blob_col blob);";
995+
stmt.execute(createTableQuery);
996+
stmt.close();
997+
sqlConnection.close();
998+
999+
// Open it up again to see the new column family.
1000+
sqlConnection = newConnection(KEYSPACE, "localdatacenter=datacenter1");
1001+
final String insertQuery = "INSERT INTO t33_blob (key, blob_col) VALUES(?, ?);";
1002+
final PreparedStatement stmt2 = sqlConnection.prepareStatement(insertQuery);
1003+
stmt2.setObject(1, 1);
1004+
stmt2.setObject(2, "test123".getBytes(StandardCharsets.UTF_8));
1005+
stmt2.execute();
1006+
stmt2.setObject(1, 2);
1007+
stmt2.setObject(2, "test456".getBytes(StandardCharsets.UTF_8), Types.VARBINARY);
1008+
stmt2.execute();
1009+
stmt2.setObject(1, 3);
1010+
stmt2.setObject(2, "test789".getBytes(StandardCharsets.UTF_8), Types.LONGVARBINARY);
1011+
stmt2.execute();
1012+
1013+
final Statement stmt3 = sqlConnection.createStatement();
1014+
ResultSet result = stmt3.executeQuery("SELECT * FROM t33_blob where key = 1;");
1015+
assertTrue(result.next());
1016+
byte[] array = new byte[result.getBinaryStream("blob_col").available()];
1017+
result.getBinaryStream("blob_col").read(array);
1018+
assertEquals("test123", new String(array, StandardCharsets.UTF_8));
1019+
1020+
result = stmt3.executeQuery("SELECT * FROM t33_blob where key = 2;");
1021+
assertTrue(result.next());
1022+
array = new byte[result.getBinaryStream("blob_col").available()];
1023+
result.getBinaryStream("blob_col").read(array);
1024+
assertEquals("test456", new String(array, StandardCharsets.UTF_8));
1025+
1026+
result = stmt3.executeQuery("SELECT * FROM t33_blob where key = 3;");
1027+
assertTrue(result.next());
1028+
array = new byte[result.getBinaryStream("blob_col").available()];
1029+
result.getBinaryStream("blob_col").read(array);
1030+
assertEquals("test789", new String(array, StandardCharsets.UTF_8));
1031+
1032+
stmt2.close();
1033+
stmt3.close();
1034+
}
9871035
}

Diff for: src/test/resources/test_application_with_ssl.conf

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
datastax-java-driver {
2+
# The two following properties should be ignored by the JDBC wrapper.
3+
basic.contact-points = [ "fake-server:9042" ]
4+
basic.session-keyspace = testKeyspace
5+
6+
# All the following properties should be taken into account by the JDBC wrapper.
7+
basic.request {
8+
consistency = LOCAL_ONE
9+
timeout = 10 seconds
10+
}
11+
12+
basic.load-balancing-policy {
13+
class = DefaultLoadBalancingPolicy
14+
local-datacenter = datacenter1
15+
}
16+
17+
advanced.auth-provider {
18+
class = PlainTextAuthProvider
19+
username = testUser
20+
password = testPassword
21+
}
22+
23+
advanced.ssl-engine-factory {
24+
class = DefaultSslEngineFactory
25+
hostname-validation = false
26+
# The variable 'TRUSTSTORE_PATH' is replaced by the real truststore path in the tests using this configuration file.
27+
truststore-path = $TRUSTSTORE_PATH
28+
truststore-password = changeit
29+
}
30+
}

0 commit comments

Comments
 (0)