diff --git a/CHANGES.txt b/CHANGES.txt index 374db56c60..9f4038ff7f 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -3,6 +3,7 @@ * Add the ability to disable bulk loading of SSTables (CASSANDRA-18781) * Clean up obsolete functions and simplify cql_version handling in cqlsh (CASSANDRA-18787) Merged from 5.0: + * Fix SAI unindexed contexts not considering CONTAINS KEY (CASSANDRA-19040) * Ensure that empty SAI column indexes do not fail on validation after full-SSTable streaming (CASSANDRA-19017) * SAI in-memory index should check max term size (CASSANDRA-18926) * Set default disk_access_mode to mmap_index_only (CASSANDRA-19021) diff --git a/src/java/org/apache/cassandra/index/sai/plan/QueryController.java b/src/java/org/apache/cassandra/index/sai/plan/QueryController.java index eee85f016e..b236c61db4 100644 --- a/src/java/org/apache/cassandra/index/sai/plan/QueryController.java +++ b/src/java/org/apache/cassandra/index/sai/plan/QueryController.java @@ -146,7 +146,9 @@ public class QueryController cfs.getPartitioner(), cfs.getComparator(), expression.column(), - IndexTarget.Type.VALUES, + expression.operator().isContainsKey() + ? IndexTarget.Type.KEYS + : IndexTarget.Type.VALUES, null) : indexes.iterator().next().getIndexContext(); } diff --git a/test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java b/test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java index a82f539842..b490dfa946 100644 --- a/test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java +++ b/test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java @@ -42,28 +42,28 @@ public class CollectionIndexingTest extends SAITester } @Test - public void indexMap() throws Throwable + public void indexMap() { createPopulatedMap(createIndexDDL("value")); assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS 'v1'").size()); } @Test - public void indexMapKeys() throws Throwable + public void indexMapKeys() { createPopulatedMap(createIndexDDL("KEYS(value)")); assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS KEY 1").size()); } @Test - public void indexMapValues() throws Throwable + public void indexMapValues() { createPopulatedMap(createIndexDDL("VALUES(value)")); assertEquals(2, execute("SELECT * FROM %s WHERE value CONTAINS 'v1'").size()); } @Test - public void indexMapEntries() throws Throwable + public void indexMapEntries() { createPopulatedMap(createIndexDDL("ENTRIES(value)")); assertEquals(2, execute("SELECT * FROM %s WHERE value[1] = 'v1'").size()); @@ -71,7 +71,7 @@ public class CollectionIndexingTest extends SAITester } @Test - public void indexFrozenList() throws Throwable + public void indexFrozenList() { createPopulatedFrozenList(createIndexDDL("FULL(value)")); assertEquals(2, execute("SELECT * FROM %s WHERE value = ?", Arrays.asList(1, 2, 3)).size()); @@ -176,6 +176,34 @@ public class CollectionIndexingTest extends SAITester assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value[1] = 'v1'"); } + @Test + public void unindexedContainsExpressions() + { + createTable("CREATE TABLE %s (k int PRIMARY KEY, v int, m map)"); + createIndex("CREATE INDEX ON %s(v) USING 'SAI'"); // just to make sure that SAI is involved + + Object[] row = row(0, 1, map(2, 3)); + execute("INSERT INTO %s (k, v, m) VALUES (?, ?, ?)", row); + execute("INSERT INTO %s (k, v, m) VALUES (?, ?, ?)", 1, 1, map(12, 13)); + + // try without any indexes on the map + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS 3 ALLOW FILTERING"), row); + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS KEY 2 ALLOW FILTERING"), row); + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS KEY 2 AND m CONTAINS 3 ALLOW FILTERING"), row); + + // try with index on map values + createIndex("CREATE INDEX ON %s(m) USING 'SAI'"); + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS 3"), row); + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS KEY 2 ALLOW FILTERING"), row); + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS KEY 2 AND m CONTAINS 3 ALLOW FILTERING"), row); + + // try with index on map keys + createIndex("CREATE INDEX ON %s(KEYS(m)) USING 'SAI'"); + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS 3"), row); + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS KEY 2"), row); + assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS KEY 2 AND m CONTAINS 3"), row); + } + private void createPopulatedMap(String createIndex) { createTable("CREATE TABLE %s (pk int primary key, value map)"); @@ -191,7 +219,7 @@ public class CollectionIndexingTest extends SAITester } @SuppressWarnings("SameParameterValue") - private void createPopulatedFrozenMap(String createIndex) throws Throwable + private void createPopulatedFrozenMap(String createIndex) { createTable("CREATE TABLE %s (pk int primary key, value frozen>)"); createIndex(createIndex);