Skip to content

Commit

Permalink
Fix #75: handle complex types in CassandraResultSet.getObject() methods
Browse files Browse the repository at this point in the history
  • Loading branch information
maximevw committed Dec 15, 2024
1 parent 80837fe commit cc0f152
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Fixed
- Do not try to register codecs again (if already done previously) on a pre-existing session to avoid warnings in logs.
- Fix some logging in `SessionHolder` to not leak connection credentials.
- Fix `CodecNotFoundException` when getting complex objects, e.g. collections of collections, from a result set (see
issue [#75](https://github.com/ing-bank/cassandra-jdbc-wrapper/issues/75)).

## [4.13.1] - 2024-09-04
### Fixed
Expand Down
13 changes: 9 additions & 4 deletions src/main/java/com/ing/data/cassandra/jdbc/types/TypesMap.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ public final class TypesMap {
TYPES_MAP.put("org.apache.cassandra.db.marshal.inet", JdbcInetAddress.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.int", JdbcInt32.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.list", JdbcList.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.map", JdbcList.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.set", JdbcList.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.map", JdbcMap.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.set", JdbcSet.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.smallint", JdbcShort.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.text", JdbcUTF8.INSTANCE);
TYPES_MAP.put("org.apache.cassandra.db.marshal.time", JdbcTime.INSTANCE);
Expand Down Expand Up @@ -95,8 +95,13 @@ private TypesMap() {
public static AbstractJdbcType<?> getTypeForComparator(final String comparator) {
// If not fully qualified, assume it's the short name for a built-in type.
if (comparator != null && !comparator.contains(".")) {
return TYPES_MAP.getOrDefault("org.apache.cassandra.db.marshal." + comparator.toLowerCase(),
JdbcOther.INSTANCE);
String cqlSimpleType = comparator.toLowerCase();
// If the CQL type is a collection (map, list, set, ...), ignore the types of elements in the collection
// to retrieve the corresponding JDBC type.
if (cqlSimpleType.contains("<")) {
cqlSimpleType = cqlSimpleType.substring(0, comparator.indexOf("<"));
}
return TYPES_MAP.getOrDefault("org.apache.cassandra.db.marshal." + cqlSimpleType, JdbcOther.INSTANCE);
}
return TYPES_MAP.getOrDefault(comparator, JdbcOther.INSTANCE);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
import com.datastax.oss.driver.api.core.data.UdtValue;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
Expand Down Expand Up @@ -51,6 +49,7 @@
import java.util.UUID;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
Expand Down Expand Up @@ -1032,4 +1031,78 @@ void testIngIssue33() throws Exception {
stmt2.close();
stmt3.close();
}

@Test
@SuppressWarnings("unchecked")
void testIngIssue75() throws Exception {
final Statement stmt = sqlConnection.createStatement();

// Create the table with complex types.
final String createTableQuery = "CREATE TABLE t75 (id int PRIMARY KEY, "
+ "complex_type1 list<frozen<map<text, text>>>, "
+ "complex_type2 list<frozen<map<text, list<frozen<map<text, text>>>>>>, "
+ "complex_type3 set<frozen<map<text, set<bigint>>>>);";
stmt.execute(createTableQuery);
stmt.close();

// Insert data into the table.
final String insertQuery =
"INSERT INTO t75(id, complex_type1, complex_type2, complex_type3) values(?, ?, ?, ?);";
final PreparedStatement stmt2 = sqlConnection.prepareStatement(insertQuery);
stmt2.setObject(1, 1);

final Map<String, String> map = new HashMap<>();
map.put("a", "10");
map.put("b", "20");
final List<Map<String, String>> list = new ArrayList<>();
list.add(map);
stmt2.setObject(2, list);

final Map<String, List<Map<String, String>>> map2 = new HashMap<>();
map2.put("c", list);
final List<Map<String, List<Map<String, String>>>> list2 = new ArrayList<>();
list2.add(map2);
stmt2.setObject(3, list2);

final Map<String, Set<Long>> map3 = new HashMap<>();
final Set<Long> innerSet = new HashSet<>();
innerSet.add(10L);
innerSet.add(15L);
map3.put("d", innerSet);
final Set<Map<String, Set<Long>>> outerSet = new HashSet<>();
outerSet.add(map3);
stmt2.setObject(4, outerSet);

stmt2.execute();
stmt2.close();

final Statement stmt3 = sqlConnection.createStatement();
final CassandraResultSet result = (CassandraResultSet) stmt3.executeQuery("SELECT * FROM t75 WHERE id = 1;");

assertTrue(result.next());
assertEquals(1, result.getInt("id"));

final List<Map<String, String>> complexType1ValueAsList =
(List<Map<String, String>>) result.getList("complex_type1");
final List<Map<String, String>> complexType1ValueAsObject =
(List<Map<String, String>>) result.getObject("complex_type1");
assertThat(complexType1ValueAsList, hasItem(map));
assertThat(complexType1ValueAsObject, hasItem(map));

final List<Map<String, List<Map<String, String>>>> complexType2ValueAsList =
(List<Map<String, List<Map<String, String>>>>) result.getList("complex_type2");
final List<Map<String, List<Map<String, String>>>> complexType2ValueAsObject =
(List<Map<String, List<Map<String, String>>>>) result.getObject("complex_type2");
assertThat(complexType2ValueAsList, hasItem(map2));
assertThat(complexType2ValueAsObject, hasItem(map2));

final Set<Map<String, Set<Long>>> complexType3ValueAsSet =
(Set<Map<String, Set<Long>>>) result.getSet("complex_type3");
final Set<Map<String, Set<Long>>> complexType3ValueAsObject =
(Set<Map<String, Set<Long>>>) result.getObject("complex_type3");
assertThat(complexType3ValueAsSet, hasItem(map3));
assertThat(complexType3ValueAsObject, hasItem(map3));

stmt3.close();
}
}

0 comments on commit cc0f152

Please sign in to comment.