You are viewing a plain text version of this content. The canonical link for it is here.
Posted to pr@cassandra.apache.org by "sunil9977 (via GitHub)" <gi...@apache.org> on 2026/01/15 06:00:21 UTC
[PR] CASSANDRA-18492: Add FULL index support for frozen collections in SAI [cassandra]
sunil9977 opened a new pull request, #4561:
URL: https://github.com/apache/cassandra/pull/4561
Cassandra-18492
- Allow FULL, VALUES, KEYS, and ENTRIES index types on frozen collections
patch by Sunil Ramchandra Pawar ; reviewed by Caleb Rackliffe
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2824299689
##########
src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java:
##########
@@ -283,22 +268,40 @@ private void validateIndexTarget(TableMetadata table, IndexMetadata.Kind kind, I
if (column.isPartitionKey() && table.partitionKeyColumns().size() == 1)
throw ire(ONLY_PARTITION_KEY, column);
- if (baseType.isFrozenCollection() && target.type != Type.FULL)
- throw ire(CREATE_ON_FROZEN_COLUMN, target.type, column, column.name.toCQLString());
-
- if (!baseType.isFrozenCollection() && target.type == Type.FULL)
+ if (target.type == Type.FULL && !isSAIIndex(attrs) && (!baseType.isCollection() || column.type.isMultiCell()))
throw ire(FULL_ON_FROZEN_COLLECTIONS);
if (!baseType.isCollection() && target.type != Type.SIMPLE)
throw ire(NON_COLLECTION_SIMPLE_INDEX, target.type, column);
- if (!(baseType instanceof MapType && baseType.isMultiCell()) && (target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES))
+ // Frozen collections are only supported with SAI indexes
+ if (!isSAIIndex(attrs) && baseType.isCollection() && !column.type.isMultiCell())
+ {
+ if (target.type == Type.VALUES || target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES)
+ {
+ throw ire(CREATE_ON_FROZEN_COLUMN, target.type.toString(), column.name, column.name);
+ }
+ }
+
+ if (!(baseType instanceof MapType) && (target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES ))
throw ire(CREATE_WITH_NON_MAP_TYPE, target.type, column);
if (column.type.isUDT() && column.type.isMultiCell())
throw ire(CREATE_ON_NON_FROZEN_UDT, column);
}
+ /**
+ * Checks if the given index attributes represent a Storage Attached Index.
+ */
+ private boolean isSAIIndex(IndexAttributes attrs)
+ {
+ if (!attrs.isCustom || attrs.customClass == null)
+ return false;
+
+ return attrs.customClass.equalsIgnoreCase(StorageAttachedIndex.NAME) ||
+ attrs.customClass.equals(StorageAttachedIndex.class.getName());
Review Comment:
This information is already codified in `IndexMetadata`, so we might be able to deduplicate a bit.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "adelapena (via GitHub)" <gi...@apache.org>.
adelapena commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2926674322
##########
src/java/org/apache/cassandra/cql3/restrictions/SimpleRestriction.java:
##########
@@ -218,6 +229,17 @@ public boolean isSupportedBy(Index index)
if (isOnToken())
return false;
+ if (columnsExpression.isMapElementExpression())
+ {
+ if (index instanceof StorageAttachedIndex)
Review Comment:
Looks great!
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "dcapwell (via GitHub)" <gi...@apache.org>.
dcapwell commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2748425697
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -453,6 +459,70 @@ public Iterator<ByteBuffer> valuesOf(Row row, long nowInSecs)
}
}
+ public Iterator<ByteBuffer> valuesOfFrozenCollection (Row row, long nowInSecs)
+ {
+ Cell<?> cell = row.getCell(columnMetadata);
Review Comment:
`public ByteBuffer valueOf(DecoratedKey key, Row row, long nowInSecs)` does the following check
```
if (row == null)
return null;
```
Yet this doesn't have such a null check? I can't tell if thats just being extra defensive or its needed, but for safety can you add it as well?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2824644693
##########
src/java/org/apache/cassandra/cql3/restrictions/SimpleRestriction.java:
##########
@@ -397,13 +418,28 @@ else if (isIN())
// TODO only map elements supported for now
if (columnsExpression.isMapElementExpression())
{
+ // For frozen maps, only SAI indexes can support map entry predicates
+ if (column.type.isCollection() && !column.type.isMultiCell())
+ {
+ for (Index index : indexRegistry.listIndexes())
+ {
+ if (index.dependsOn(column))
+ {
+ if (!(index instanceof StorageAttachedIndex))
+ {
+ throw invalidRequest("Map-entry predicates on frozen map column %s are not supported", column.name);
+ }
+ }
+ }
+ }
Review Comment:
Another option here is just to add this to the `Index` interface, default the method to return false, and have SAI return true. (ie. `Index#supportsMapElementExpression()`) Then we don't have to get into all the `instanceof` stuff.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2824298292
##########
src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java:
##########
@@ -283,22 +268,40 @@ private void validateIndexTarget(TableMetadata table, IndexMetadata.Kind kind, I
if (column.isPartitionKey() && table.partitionKeyColumns().size() == 1)
throw ire(ONLY_PARTITION_KEY, column);
- if (baseType.isFrozenCollection() && target.type != Type.FULL)
- throw ire(CREATE_ON_FROZEN_COLUMN, target.type, column, column.name.toCQLString());
-
- if (!baseType.isFrozenCollection() && target.type == Type.FULL)
+ if (target.type == Type.FULL && !isSAIIndex(attrs) && (!baseType.isCollection() || column.type.isMultiCell()))
throw ire(FULL_ON_FROZEN_COLLECTIONS);
if (!baseType.isCollection() && target.type != Type.SIMPLE)
throw ire(NON_COLLECTION_SIMPLE_INDEX, target.type, column);
- if (!(baseType instanceof MapType && baseType.isMultiCell()) && (target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES))
+ // Frozen collections are only supported with SAI indexes
+ if (!isSAIIndex(attrs) && baseType.isCollection() && !column.type.isMultiCell())
+ {
+ if (target.type == Type.VALUES || target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES)
+ {
+ throw ire(CREATE_ON_FROZEN_COLUMN, target.type.toString(), column.name, column.name);
+ }
+ }
Review Comment:
Did we purposefully change the ordering of these checks so we can assume the `target.type`?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2829433768
##########
test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java:
##########
@@ -93,21 +102,29 @@ public void indexFrozenMapQueryKeys() throws Throwable
{
createPopulatedFrozenMap(createIndexDDL("FULL(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1");
+
+ flush();
+ assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1");
Review Comment:
There's actually little utility in `CQLTester` called `beforeAndAfterFlush()` that you can use to do this.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "dcapwell (via GitHub)" <gi...@apache.org>.
dcapwell commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2748393364
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -453,6 +459,70 @@ public Iterator<ByteBuffer> valuesOf(Row row, long nowInSecs)
}
}
+ public Iterator<ByteBuffer> valuesOfFrozenCollection (Row row, long nowInSecs)
+ {
+ Cell<?> cell = row.getCell(columnMetadata);
+ if (cell == null || !cell.isLive(nowInSecs))
+ return null;
+
+ ByteBuffer buffer = cell.buffer();
+ if (buffer == null || buffer.remaining() == 0)
+ return null;
+
+ CollectionType<?> collectionType = (CollectionType<?>) columnMetadata.type.unwrap();
+ CollectionSerializer<?> serializer = collectionType.getSerializer();
+ List<ByteBuffer> elements = serializer.unpack(buffer);
+
+ Stream<ByteBuffer> stream;
+ switch (collectionType.kind)
+ {
+ case LIST:
+ case SET:
+ stream = elements.stream();
+ break;
+ case MAP:
+ stream = extractMapElements(elements);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported type of collection - " + collectionType.kind);
Review Comment:
Checked and our style guide doesn't call it out (mailing list talked about it) but streams are actually slow, so best to avoid them in hotter paths.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "dcapwell (via GitHub)" <gi...@apache.org>.
dcapwell commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2748406711
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -453,6 +459,70 @@ public Iterator<ByteBuffer> valuesOf(Row row, long nowInSecs)
}
}
+ public Iterator<ByteBuffer> valuesOfFrozenCollection (Row row, long nowInSecs)
Review Comment:
```suggestion
public Iterator<ByteBuffer> valuesOfFrozenCollection(Row row, long nowInSecs)
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2824659287
##########
src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java:
##########
@@ -126,9 +126,21 @@ private static void validate(SimpleRestriction restriction, SimpleRestriction ot
checkOperator(other);
if (restriction.isContains() != other.isContains())
+ {
+ SimpleRestriction mapEntryRestriction = restriction.isContains() ? restriction : other;
+ if (mapEntryRestriction.isMapElementExpression())
+ {
+ ColumnMetadata column = mapEntryRestriction.firstColumn();
+ if (column.type.isCollection() && !column.type.isMultiCell())
Review Comment:
Is this just `AbstractType#isFrozenCollection()`?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#issuecomment-4056583235
Committed as https://github.com/apache/cassandra/commit/8d325d50ed36d04d99b02469af2e3ceaa3384888
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2825155506
##########
test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java:
##########
@@ -1359,74 +1362,1114 @@ public void shouldRejectQueriesWithCustomExpressions()
}
@Test
- public void testInitialBuildParallelism()
+ public void testFrozenListFullIndex()
{
- Function<Long, SSTableReader> createMockSSTable = onDiskLength -> {
- SSTableReader reader = Mockito.mock(SSTableReader.class);
- when(reader.onDiskLength()).thenReturn(onDiskLength);
- return reader;
- };
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list)) USING 'sai'");
- Function<List<SSTableReader>, List<Long>> toSize = sstables -> sstables.stream().map(SSTableReader::onDiskLength).collect(Collectors.toList());
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, [4, 5, 6])");
- // total size = 55
- List<SSTableReader> sstables = LongStream.range(1, 11).boxed().map(createMockSSTable).collect(Collectors.toList());
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
- // avg = 55 == total size
- List<List<SSTableReader>> groups = StorageAttachedIndex.groupBySize(sstables, 1);
- Iterator<List<SSTableReader>> iterator = groups.iterator();
- assertEquals(1, groups.size());
- assertEquals(Arrays.asList(10L, 9L, 8L, 7L, 6L, 5L, 4L, 3L, 2L, 1L), toSize.apply(iterator.next())); // size = 55
+ flush();
- // avg = 27.5
- groups = StorageAttachedIndex.groupBySize(sstables, 2);
- iterator = groups.iterator();
- assertEquals(2, groups.size());
- assertEquals(Arrays.asList(10L, 9L, 8L, 7L), toSize.apply(iterator.next())); // size = 34
- assertEquals(Arrays.asList(6L, 5L, 4L, 3L, 2L, 1L), toSize.apply(iterator.next())); // size = 21
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
+ }
- // avg = 18.333
- groups = StorageAttachedIndex.groupBySize(sstables, 3);
- iterator = groups.iterator();
- assertEquals(3, groups.size());
- assertEquals(Arrays.asList(10L, 9L), toSize.apply(iterator.next())); // size = 19
- assertEquals(Arrays.asList(8L, 7L, 6L), toSize.apply(iterator.next())); // size = 21
- assertEquals(Arrays.asList(5L, 4L, 3L, 2L, 1L), toSize.apply(iterator.next())); // size = 15
+ @Test
+ public void testFrozenListValuesIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list)) USING 'sai'");
- // avg = 11
- groups = StorageAttachedIndex.groupBySize(sstables, 5);
- iterator = groups.iterator();
- assertEquals(4, groups.size());
- assertEquals(Arrays.asList(10L, 9L), toSize.apply(iterator.next())); // size = 19
- assertEquals(Arrays.asList(8L, 7L), toSize.apply(iterator.next())); // size = 15
- assertEquals(Arrays.asList(6L, 5L), toSize.apply(iterator.next())); // size = 11
- assertEquals(Arrays.asList(4L, 3L, 2L, 1L), toSize.apply(iterator.next())); // size = 11
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, [3, 4, 5])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, [4, 5, 6])");
- // avg = 5.5
- groups = StorageAttachedIndex.groupBySize(sstables, 10);
- iterator = groups.iterator();
- assertEquals(7, groups.size());
- assertEquals(singletonList(10L), toSize.apply(iterator.next()));
- assertEquals(singletonList(9L), toSize.apply(iterator.next()));
- assertEquals(singletonList(8L), toSize.apply(iterator.next()));
- assertEquals(singletonList(7L), toSize.apply(iterator.next()));
- assertEquals(singletonList(6L), toSize.apply(iterator.next()));
- assertEquals(Arrays.asList(5L, 4L), toSize.apply(iterator.next()));
- assertEquals(Arrays.asList(3L, 2L, 1L), toSize.apply(iterator.next()));
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list CONTAINS 3");
+ assertEquals(2, rows.all().size());
- // avg = 2.75
- groups = StorageAttachedIndex.groupBySize(sstables, 20);
- iterator = groups.iterator();
- assertEquals(9, groups.size());
- assertEquals(singletonList(10L), toSize.apply(iterator.next()));
- assertEquals(singletonList(9L), toSize.apply(iterator.next()));
- assertEquals(singletonList(8L), toSize.apply(iterator.next()));
- assertEquals(singletonList(7L), toSize.apply(iterator.next()));
- assertEquals(singletonList(6L), toSize.apply(iterator.next()));
- assertEquals(singletonList(5L), toSize.apply(iterator.next()));
- assertEquals(singletonList(4L), toSize.apply(iterator.next()));
- assertEquals(singletonList(3L), toSize.apply(iterator.next()));
- assertEquals(Arrays.asList(2L, 1L), toSize.apply(iterator.next()));
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list CONTAINS 3");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenSetFullIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_set)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenSetValuesIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'banana', 'cherry'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set CONTAINS 'banana'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set CONTAINS 'banana'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapFullIndexEquality()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, {'k3': 'v3', 'k4': 'v4'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapFullIndexMapEntryRequiresFiltering() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, ?)", ImmutableMap.of(3, "v3", 4, "v4"));
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapEntriesIndexMapEntry()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, ?)", ImmutableMap.of(3, "v3", 4, "v4"));
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapValuesIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, {'k3': 'v1', 'k4': 'v3'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, {'k5': 'v3', 'k6': 'v4'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapKeysIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ createIndex("CREATE INDEX ON %s(KEYS(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, {'k1': 'v3', 'k4': 'v4'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, {'k5': 'v5', 'k6': 'v6'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS KEY 'k1'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS KEY 'k1'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testDifferentIndexTypesOnDifferentColumns()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "map_full frozen<map<text, text>>, " +
+ "map_values frozen<map<text, text>>, " +
+ "map_keys frozen<map<text, text>>, " +
+ "map_entries frozen<map<text, text>>)");
+
+ createIndex("CREATE INDEX idx_full ON %s(FULL(map_full)) USING 'sai'");
+ createIndex("CREATE INDEX idx_values ON %s(VALUES(map_values)) USING 'sai'");
+ createIndex("CREATE INDEX idx_keys ON %s(KEYS(map_keys)) USING 'sai'");
+ createIndex("CREATE INDEX idx_entries ON %s(ENTRIES(map_entries)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, map_full, map_values, map_keys, map_entries) " +
+ "VALUES (1, {'k1': 'v1', 'k2': 'v2'}, {'k1': 'v1', 'k2': 'v2'}, {'k1': 'v1', 'k2': 'v2'}, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, map_full, map_values, map_keys, map_entries) " +
+ "VALUES (2, {'k1': 'v1', 'k2': 'v2'}, {'k3': 'v1', 'k4': 'v3'}, {'k1': 'v3', 'k5': 'v5'}, {'k1': 'v1', 'k6': 'v6'})");
+ execute("INSERT INTO %s (pk, map_full, map_values, map_keys, map_entries) " +
+ "VALUES (3, {'k3': 'v3', 'k4': 'v4'}, {'k5': 'v5', 'k6': 'v6'}, {'k7': 'v7', 'k8': 'v8'}, {'k9': 'v9', 'k10': 'v10'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE map_full = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_values CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_keys CONTAINS KEY 'k1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_entries['k1'] = 'v1'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_full = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_values CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_keys CONTAINS KEY 'k1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_entries['k1'] = 'v1'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFullIndexDoesNotSupportContainsOperations()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ flush();
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_list CONTAINS 1");
+ }
+
+ @Test
+ public void testValuesIndexDoesNotSupportEquality()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ flush();
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ }
+
+ @Test
+ public void testMapEntryWithAllowFilteringDifferentKeyTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(1, rows.all().size());
+
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of("k1", "v1", "k2", "v2"));
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map['k1'] = 'v1' ALLOW FILTERING");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map['k1'] = 'v1' ALLOW FILTERING");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapValuesIndexWithMapEntryQuery()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapKeysIndexWithMapEntryQuery()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(KEYS(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapDefaultIndexType()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(frozen_map) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, ?)", ImmutableMap.of(4, "v4", 5, "v5"));
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map = ?", ImmutableMap.of(1, "v1", 2, "v2"));
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testMapEntryQueryWithNullAndEmptyCollections()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(3, "v3", 4, "v4"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, NULL)");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (4, ?)", ImmutableMap.of());
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (5, ?)", ImmutableMap.of(1, "different_value"));
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s");
+ assertEquals(5, rows.all().size());
+ }
+
+ @Test
+ public void testFullIndexWithNullAndEmptyCollections()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, ?)", Arrays.asList(1, 2, 3));
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, ?)", Arrays.asList(1, 2, 3));
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, ?)", Arrays.asList(4, 5, 6));
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (4, NULL)");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (5, ?)", List.of());
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", List.of());
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", List.of());
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s");
+ assertEquals(5, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithNumericTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_bigint frozen<list<bigint>>, " +
+ "frozen_set_smallint frozen<set<smallint>>, " +
+ "frozen_map_tinyint frozen<map<tinyint, text>>, " +
+ "frozen_list_varint frozen<list<varint>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_bigint)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_smallint)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_tinyint)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list_varint)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_bigint, frozen_set_smallint, frozen_map_tinyint, frozen_list_varint) " +
+ "VALUES (1, [1, 2, 3], {10, 20}, {1: 'v1', 2: 'v2'}, [100, 200])");
+ execute("INSERT INTO %s (pk, frozen_list_bigint, frozen_set_smallint, frozen_map_tinyint, frozen_list_varint) " +
+ "VALUES (2, [1, 2, 3], {30, 40}, {3: 'v3'}, [300])");
+ execute("INSERT INTO %s (pk, frozen_list_bigint, frozen_set_smallint, frozen_map_tinyint, frozen_list_varint) " +
+ "VALUES (3, [], {}, {}, [])");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_bigint = ?", Arrays.asList(1L, 2L, 3L));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_smallint CONTAINS ?", (short)10);
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_tinyint[?] = 'v1'", (byte)1);
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_varint CONTAINS 100");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_bigint = ?", Arrays.asList(1L, 2L, 3L));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_smallint CONTAINS ?", (short)10);
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_tinyint[?] = 'v1'", (byte)1);
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_varint CONTAINS 100");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithDecimalTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_float frozen<list<float>>, " +
+ "frozen_set_double frozen<set<double>>, " +
+ "frozen_map_decimal frozen<map<decimal, text>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_float)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_double)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_decimal)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_float, frozen_set_double, frozen_map_decimal) " +
+ "VALUES (1, [1.1, 2.2], {10.5, 20.5}, {1.0: 'v1', 2.0: 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_list_float, frozen_set_double, frozen_map_decimal) " +
+ "VALUES (2, [1.1, 2.2], {30.5}, {3.0: 'v3'})");
+ execute("INSERT INTO %s (pk, frozen_list_float, frozen_set_double, frozen_map_decimal) " +
+ "VALUES (3, [], {}, {})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_float = ?", Arrays.asList(1.1f, 2.2f));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_double CONTAINS 10.5");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_decimal[1.0] = 'v1'");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_float = ?", Arrays.asList(1.1f, 2.2f));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_double CONTAINS 10.5");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_decimal[1.0] = 'v1'");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithTextVariants()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_varchar frozen<list<varchar>>, " +
+ "frozen_set_ascii frozen<set<ascii>>, " +
+ "frozen_map_text frozen<map<text, varchar>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_varchar)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_ascii)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_text)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_varchar, frozen_set_ascii, frozen_map_text) " +
+ "VALUES (1, ['apple', 'banana'], {'hello', 'world'}, {'key1': 'value1', 'key2': 'value2'})");
+ execute("INSERT INTO %s (pk, frozen_list_varchar, frozen_set_ascii, frozen_map_text) " +
+ "VALUES (2, ['apple', 'banana'], {'test'}, {'key3': 'value3'})");
+ execute("INSERT INTO %s (pk, frozen_list_varchar, frozen_set_ascii, frozen_map_text) " +
+ "VALUES (3, [], {}, {})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_varchar = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_ascii CONTAINS 'hello'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_text['key1'] = 'value1'");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_varchar = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_ascii CONTAINS 'hello'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_text['key1'] = 'value1'");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithTimeTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_timestamp frozen<list<timestamp>>, " +
+ "frozen_set_date frozen<set<date>>, " +
+ "frozen_map_time frozen<map<time, text>>, " +
+ "frozen_list_timeuuid frozen<list<timeuuid>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_timestamp)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_date)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_time)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list_timeuuid)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_timestamp, frozen_set_date, frozen_map_time, frozen_list_timeuuid) " +
+ "VALUES (1, ['2023-01-01 00:00:00+0000', '2023-01-02 00:00:00+0000'], {'2023-01-01', '2023-01-02'}, " +
+ "{'12:00:00': 'noon', '18:00:00': 'evening'}, [50554d6e-29bb-11e5-b345-feff819cdc9f])");
+ execute("INSERT INTO %s (pk, frozen_list_timestamp, frozen_set_date, frozen_map_time, frozen_list_timeuuid) " +
+ "VALUES (2, ['2023-01-01 00:00:00+0000', '2023-01-02 00:00:00+0000'], {'2023-01-03'}, " +
+ "{'06:00:00': 'morning'}, [50554d6e-29bb-11e5-b345-feff819cdc9f])");
+ execute("INSERT INTO %s (pk, frozen_list_timestamp, frozen_set_date, frozen_map_time, frozen_list_timeuuid) " +
+ "VALUES (3, [], {}, {}, [])");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_timestamp = ['2023-01-01 00:00:00+0000', '2023-01-02 00:00:00+0000']");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_date CONTAINS '2023-01-01'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_time['12:00:00'] = 'noon'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_timeuuid CONTAINS 50554d6e-29bb-11e5-b345-feff819cdc9f");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_timestamp = ['2023-01-01 00:00:00+0000', '2023-01-02 00:00:00+0000']");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_date CONTAINS '2023-01-01'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_time['12:00:00'] = 'noon'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_timeuuid CONTAINS 50554d6e-29bb-11e5-b345-feff819cdc9f");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithOtherTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_uuid frozen<list<uuid>>, " +
+ "frozen_set_boolean frozen<set<boolean>>, " +
+ "frozen_map_inet frozen<map<inet, text>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_uuid)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_boolean)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_inet)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_uuid, frozen_set_boolean, frozen_map_inet) " +
+ "VALUES (1, [550e8400-e29b-41d4-a716-446655440000, 550e8400-e29b-41d4-a716-446655440001], " +
+ "{true, false}, {'127.0.0.1': 'localhost', '192.168.1.1': 'router'})");
+ execute("INSERT INTO %s (pk, frozen_list_uuid, frozen_set_boolean, frozen_map_inet) " +
+ "VALUES (2, [550e8400-e29b-41d4-a716-446655440000, 550e8400-e29b-41d4-a716-446655440001], " +
+ "{true}, {'10.0.0.1': 'server'})");
+ execute("INSERT INTO %s (pk, frozen_list_uuid, frozen_map_inet) " +
+ "VALUES (3, [], {})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_uuid = ?",
+ Arrays.asList(UUID.fromString("550e8400-e29b-41d4-a716-446655440000"),
+ UUID.fromString("550e8400-e29b-41d4-a716-446655440001")));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_boolean CONTAINS true");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_inet['127.0.0.1'] = 'localhost'");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_uuid = ?",
+ Arrays.asList(UUID.fromString("550e8400-e29b-41d4-a716-446655440000"),
+ UUID.fromString("550e8400-e29b-41d4-a716-446655440001")));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_boolean CONTAINS true");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_inet['127.0.0.1'] = 'localhost'");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testNonFrozenCollectionsIndexes()
+ {
+ createTable("CREATE TABLE %s (id int PRIMARY KEY, list_col list<text>)");
+ createIndex("CREATE INDEX ON %s(VALUES(list_col)) USING 'sai'");
+
+ execute("INSERT INTO %s (id, list_col) VALUES (1, ['apple', 'banana'])");
+ execute("INSERT INTO %s (id, list_col) VALUES (2, ['cherry', 'date'])");
+ execute("INSERT INTO %s (id, list_col) VALUES (3, ['apple', 'banana', 'cherry'])");
+ flush();
+
+ ResultSet rows = executeNet("SELECT id FROM %s WHERE list_col CONTAINS 'apple'");
+ assertEquals(2, rows.all().size());
+
+ createTable("CREATE TABLE %s (id int PRIMARY KEY, set_col set<text>)");
+ createIndex("CREATE INDEX ON %s(VALUES(set_col)) USING 'sai'");
+
+ execute("INSERT INTO %s (id, set_col) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (id, set_col) VALUES (2, {'cherry', 'date'})");
+ execute("INSERT INTO %s (id, set_col) VALUES (3, {'apple', 'banana', 'cherry'})");
+ flush();
+
+ rows = executeNet("SELECT id FROM %s WHERE set_col CONTAINS 'apple'");
+ assertEquals(2, rows.all().size());
+
+ createTable("CREATE TABLE %s (id int PRIMARY KEY, map_col map<text, text>)");
+ createIndex("CREATE INDEX ON %s(VALUES(map_col)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(KEYS(map_col)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(map_col)) USING 'sai'");
+
+ execute("INSERT INTO %s (id, map_col) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (id, map_col) VALUES (2, {'k3': 'v3', 'k4': 'v4'})");
+ execute("INSERT INTO %s (id, map_col) VALUES (3, {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'})");
+ flush();
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col CONTAINS key 'k1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col['k1'] = 'v1'");
+ assertEquals(2, rows.all().size());
+
+ execute("UPDATE %s SET map_col = map_col + {'k1': 'v1_updated'} WHERE id = 1");
+ flush();
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col['k1'] = 'v1_updated'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col['k1'] = 'v1'");
+ assertEquals(1, rows.all().size());
+
+ execute("DELETE map_col['k1'] FROM %s WHERE id = 3");
+ flush();
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col CONTAINS key 'k1'");
+ assertEquals(1, rows.all().size());
+
+ assertThatThrownBy(() -> executeNet("SELECT id FROM %s WHERE map_col = {'k1': 'v1'} ALLOW FILTERING"))
+ .isInstanceOf(Exception.class);
+ }
+
+ @Test
+ public void testSaiNonFrozenMap()
+ {
+ createTable("CREATE TABLE %s (id int PRIMARY KEY, frozen_map map<text, text>)");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (id, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (id, frozen_map) VALUES (2, {'k3': 'v3', 'k4': 'v4'})");
+ execute("INSERT INTO %s (id, frozen_map) VALUES (3, {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'})");
+ execute("INSERT INTO %s (id, frozen_map) VALUES (4, {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'})");
+ flush();
+
+ ResultSet rows = executeNet("SELECT id FROM %s WHERE frozen_map['k1']='v1';");
+ assertEquals(3, rows.all().size());
+ }
+
Review Comment:
I'd consider moving basically all of these new tests to `CollectionIndexingTest` (or at least out of this class). This class is mostly (I know not purely) meant to look at DDL and operational issues.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2829374841
##########
src/java/org/apache/cassandra/cql3/Relation.java:
##########
@@ -204,7 +204,10 @@ public SingleRestriction toRestriction(TableMetadata table, VariableSpecificatio
AbstractType<?> baseType = column.type.unwrap();
checkFalse(baseType instanceof ListType, "Indexes on list entries (%s[index] = value) are not supported.", column.name);
checkTrue(baseType instanceof MapType, "Column %s cannot be used as a map", column.name);
- checkTrue(baseType.isMultiCell(), "Map-entry predicates on frozen map column %s are not supported", column.name);
+
+ if (column.isClusteringColumn() && baseType.isCollection() && !column.type.isMultiCell())
+ throw invalidRequest("Map-entry predicates on frozen map column %s are not supported", column.name);
Review Comment:
nit: Might be useful to create a constant from this and reuse it in places like tests. Could save us in the future from having to make an annoying set of changes to that string in several places (ex. `CollectionIndexingTest`)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2826594922
##########
src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java:
##########
@@ -283,22 +268,40 @@ private void validateIndexTarget(TableMetadata table, IndexMetadata.Kind kind, I
if (column.isPartitionKey() && table.partitionKeyColumns().size() == 1)
throw ire(ONLY_PARTITION_KEY, column);
- if (baseType.isFrozenCollection() && target.type != Type.FULL)
- throw ire(CREATE_ON_FROZEN_COLUMN, target.type, column, column.name.toCQLString());
-
- if (!baseType.isFrozenCollection() && target.type == Type.FULL)
+ if (target.type == Type.FULL && !isSAIIndex(attrs) && (!baseType.isCollection() || column.type.isMultiCell()))
throw ire(FULL_ON_FROZEN_COLLECTIONS);
if (!baseType.isCollection() && target.type != Type.SIMPLE)
throw ire(NON_COLLECTION_SIMPLE_INDEX, target.type, column);
- if (!(baseType instanceof MapType && baseType.isMultiCell()) && (target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES))
+ // Frozen collections are only supported with SAI indexes
+ if (!isSAIIndex(attrs) && baseType.isCollection() && !column.type.isMultiCell())
+ {
+ if (target.type == Type.VALUES || target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES)
+ {
+ throw ire(CREATE_ON_FROZEN_COLUMN, target.type.toString(), column.name, column.name);
+ }
+ }
Review Comment:
The inner if intentionally skips FULL because legacy indexes already support FULL on frozen collections. Only `VALUES/KEYS/KEYS_AND_VALUES` are blocked for non-SAI.
Tested with test case `FrozenCollectionsTest#testSecondaryIndex()`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2832620748
##########
src/java/org/apache/cassandra/cql3/Relation.java:
##########
@@ -204,7 +204,10 @@ public SingleRestriction toRestriction(TableMetadata table, VariableSpecificatio
AbstractType<?> baseType = column.type.unwrap();
checkFalse(baseType instanceof ListType, "Indexes on list entries (%s[index] = value) are not supported.", column.name);
checkTrue(baseType instanceof MapType, "Column %s cannot be used as a map", column.name);
- checkTrue(baseType.isMultiCell(), "Map-entry predicates on frozen map column %s are not supported", column.name);
+
+ if (column.isClusteringColumn() && baseType.isCollection() && !column.type.isMultiCell())
+ throw invalidRequest("Map-entry predicates on frozen map column %s are not supported", column.name);
Review Comment:
Added the constant and modified the tests too.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2833600753
##########
src/java/org/apache/cassandra/index/sai/plan/Expression.java:
##########
@@ -324,6 +324,10 @@ public boolean isSatisfiedBy(ByteBuffer columnValue)
private boolean validateStringValue(ByteBuffer columnValue, ByteBuffer requestedValue)
{
+ if (indexTermType.isFrozenCollection() &&
+ (operator == IndexOperator.CONTAINS_VALUE || operator == IndexOperator.CONTAINS_KEY))
+ return termMatches(columnValue, requestedValue);
Review Comment:
I’m still not sure what this extra check for contains key and contains value is doing. Should we reject other index operators? If the operator is fine, can we then just fall through to the logic below?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "dcapwell (via GitHub)" <gi...@apache.org>.
dcapwell commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2748482665
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -453,6 +459,70 @@ public Iterator<ByteBuffer> valuesOf(Row row, long nowInSecs)
}
}
+ public Iterator<ByteBuffer> valuesOfFrozenCollection (Row row, long nowInSecs)
Review Comment:
The `valuesOfFrozenCollection` method only handles `REGULAR` and `STATIC` columns (via `row.getCell()`), but doesn't check `columnMetadata.kind`. **When this method is called for a clustering column or composite partition key column that is a frozen collection, it returns null, causing queries to return 0 results.**
### Confirmed by Testing
I created a test that demonstrates the bug:
```java
/**
* Tests VALUES index on a frozen list used as a CLUSTERING column.
* <p>
* CASSANDRA-18492: This test demonstrates a bug where VALUES/KEYS/ENTRIES indexes
* on frozen collections that are clustering columns return 0 results.
* </p>
* <p>
* Root cause: {@code IndexTermType.valuesOfFrozenCollection()} uses {@code row.getCell(columnMetadata)}
* which returns null for clustering columns (their data is in {@code row.clustering()}, not cells).
* </p>
*/
@Test
public void testFrozenListClusteringKeyWithValuesIndex()
{
createTable("CREATE TABLE %s (pk int, ck frozen<list<int>>, v int, PRIMARY KEY (pk, ck))");
createIndex("CREATE INDEX ON %s(VALUES(ck)) USING 'sai'");
execute("INSERT INTO %s (pk, ck, v) VALUES (1, [1, 2, 3], 100)");
execute("INSERT INTO %s (pk, ck, v) VALUES (1, [4, 5, 6], 200)");
execute("INSERT INTO %s (pk, ck, v) VALUES (2, [1, 7, 8], 300)");
// Test memtable path
ResultSet rows = executeNet("SELECT pk, v FROM %s WHERE ck CONTAINS 1");
// BUG: Currently returns 0 rows instead of 2
assertEquals("Memtable query should find 2 rows containing value 1", 2, rows.all().size());
flush();
// Test SSTable path
rows = executeNet("SELECT pk, v FROM %s WHERE ck CONTAINS 1");
// BUG: Currently returns 0 rows instead of 2
assertEquals("SSTable query should find 2 rows containing value 1", 2, rows.all().size());
}
/**
* Tests VALUES index on a frozen set used as a CLUSTERING column.
* <p>
* CASSANDRA-18492: Same bug as {@link #testFrozenListClusteringKeyWithValuesIndex()}.
* </p>
*/
@Test
public void testFrozenSetClusteringKeyWithValuesIndex()
{
createTable("CREATE TABLE %s (pk int, ck frozen<set<text>>, v int, PRIMARY KEY (pk, ck))");
createIndex("CREATE INDEX ON %s(VALUES(ck)) USING 'sai'");
execute("INSERT INTO %s (pk, ck, v) VALUES (1, {'a', 'b'}, 100)");
execute("INSERT INTO %s (pk, ck, v) VALUES (1, {'c', 'd'}, 200)");
execute("INSERT INTO %s (pk, ck, v) VALUES (2, {'a', 'e'}, 300)");
// Test memtable path
ResultSet rows = executeNet("SELECT pk, v FROM %s WHERE ck CONTAINS 'a'");
// BUG: Currently returns 0 rows instead of 2
assertEquals("Memtable query should find 2 rows containing 'a'", 2, rows.all().size());
flush();
// Test SSTable path
rows = executeNet("SELECT pk, v FROM %s WHERE ck CONTAINS 'a'");
// BUG: Currently returns 0 rows instead of 2
assertEquals("SSTable query should find 2 rows containing 'a'", 2, rows.all().size());
}
/**
* Tests KEYS index on a frozen map used as a CLUSTERING column.
* <p>
* CASSANDRA-18492: Same bug as {@link #testFrozenListClusteringKeyWithValuesIndex()}.
* </p>
*/
@Test
public void testFrozenMapClusteringKeyWithKeysIndex()
{
createTable("CREATE TABLE %s (pk int, ck frozen<map<text, int>>, v int, PRIMARY KEY (pk, ck))");
createIndex("CREATE INDEX ON %s(KEYS(ck)) USING 'sai'");
execute("INSERT INTO %s (pk, ck, v) VALUES (1, {'x': 1, 'y': 2}, 100)");
execute("INSERT INTO %s (pk, ck, v) VALUES (1, {'z': 3}, 200)");
execute("INSERT INTO %s (pk, ck, v) VALUES (2, {'x': 4}, 300)");
// Test memtable path
ResultSet rows = executeNet("SELECT pk, v FROM %s WHERE ck CONTAINS KEY 'x'");
// BUG: Currently returns 0 rows instead of 2
assertEquals("Memtable query should find 2 rows with key 'x'", 2, rows.all().size());
flush();
// Test SSTable path
rows = executeNet("SELECT pk, v FROM %s WHERE ck CONTAINS KEY 'x'");
// BUG: Currently returns 0 rows instead of 2
assertEquals("SSTable query should find 2 rows with key 'x'", 2, rows.all().size());
}
/**
* Tests VALUES index on a frozen map used as a CLUSTERING column.
* <p>
* CASSANDRA-18492: Same bug as {@link #testFrozenListClusteringKeyWithValuesIndex()}.
* </p>
*/
@Test
public void testFrozenMapClusteringKeyWithValuesIndex()
{
createTable("CREATE TABLE %s (pk int, ck frozen<map<text, int>>, v int, PRIMARY KEY (pk, ck))");
createIndex("CREATE INDEX ON %s(VALUES(ck)) USING 'sai'");
execute("INSERT INTO %s (pk, ck, v) VALUES (1, {'x': 1, 'y': 2}, 100)");
execute("INSERT INTO %s (pk, ck, v) VALUES (1, {'z': 3}, 200)");
execute("INSERT INTO %s (pk, ck, v) VALUES (2, {'x': 1}, 300)");
// Test memtable path
ResultSet rows = executeNet("SELECT pk, v FROM %s WHERE ck CONTAINS 1");
// BUG: Currently returns 0 rows instead of 2
assertEquals("Memtable query should find 2 rows with value 1", 2, rows.all().size());
flush();
// Test SSTable path
rows = executeNet("SELECT pk, v FROM %s WHERE ck CONTAINS 1");
// BUG: Currently returns 0 rows instead of 2
assertEquals("SSTable query should find 2 rows with value 1", 2, rows.all().size());
}
```
**Test result**: `Got less rows than expected. Expected 2 but got 0`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "dcapwell (via GitHub)" <gi...@apache.org>.
dcapwell commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2748404412
##########
test/unit/org/apache/cassandra/db/AbstractReadQueryToCQLStringTest.java:
##########
@@ -657,7 +656,8 @@ public void testFrozenCollections() throws Throwable
test("SELECT * FROM %s WHERE u = {a: 'a', b: 1} ALLOW FILTERING");
testInvalid("SELECT * FROM %s WHERE l['a'] = 'a' ALLOW FILTERING");
testInvalid("SELECT * FROM %s WHERE s['a'] = 'a' ALLOW FILTERING");
- testInvalid("SELECT * FROM %s WHERE m['a'] = 'a' ALLOW FILTERING");
+ // CASSANDRA-18942 Allow filtering works with map[key]
Review Comment:
```suggestion
// CASSANDRA-18492 Allow filtering works with map[key]
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "adelapena (via GitHub)" <gi...@apache.org>.
adelapena commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2926668094
##########
test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java:
##########
@@ -204,6 +222,941 @@ public void unindexedContainsExpressions()
assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS KEY 2 AND m CONTAINS 3"), row);
}
+ @Test
+ public void testFrozenListFullIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, [4, 5, 6])");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenListValuesIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, [3, 4, 5])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, [4, 5, 6])");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list CONTAINS 3");
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenSetFullIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_set)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenSetValuesIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'banana', 'cherry'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set CONTAINS 'banana'");
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenMapFullIndexEquality() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, {'k3': 'v3', 'k4': 'v4'})");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenMapFullIndexMapEntryRequiresFiltering() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, ?)", ImmutableMap.of(3, "v3", 4, "v4"));
+
+ beforeAndAfterFlush(() -> {
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenMapEntriesIndexMapEntry() throws Throwable
Review Comment:
I see the solution for now is not supporting an entries index on clustering column. I think that's perfectly fine, we could have some followup to support this at some point.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2832600749
##########
src/java/org/apache/cassandra/index/sai/plan/Expression.java:
##########
@@ -324,6 +324,10 @@ public boolean isSatisfiedBy(ByteBuffer columnValue)
private boolean validateStringValue(ByteBuffer columnValue, ByteBuffer requestedValue)
{
+ if (indexTermType.isFrozenCollection() &&
+ (operator == IndexOperator.CONTAINS_VALUE || operator == IndexOperator.CONTAINS_KEY))
+ return termMatches(columnValue, requestedValue);
Review Comment:
Fixed it and added few test cases too in `CollectionIndexingTest.java`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2829504528
##########
src/java/org/apache/cassandra/index/sai/plan/Expression.java:
##########
@@ -324,6 +324,10 @@ public boolean isSatisfiedBy(ByteBuffer columnValue)
private boolean validateStringValue(ByteBuffer columnValue, ByteBuffer requestedValue)
{
+ if (indexTermType.isFrozenCollection() &&
+ (operator == IndexOperator.CONTAINS_VALUE || operator == IndexOperator.CONTAINS_KEY))
+ return termMatches(columnValue, requestedValue);
Review Comment:
I modified one of the tests to try to use an analyzer...
```
@Test
public void testFrozenSetValuesIndex()
{
createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
createIndex("CREATE INDEX ON %s(VALUES(frozen_set)) USING 'sai' WITH OPTIONS = { 'case_sensitive' : false }");
execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'Banana'})");
execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'banana', 'cherry'})");
execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set CONTAINS 'banana'");
assertEquals(2, rows.all().size());
flush();
rows = executeNet("SELECT pk FROM %s WHERE frozen_set CONTAINS 'banana'");
assertEquals(2, rows.all().size());
}
```
This fails to find/match the capitalized "Banana". It works in the non-frozen case, and it also seems to work if you just remove this new block above and let the following logic execute. Anyway, throw a couple new tests around that (or parameterize the existing ones), and see how it goes.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2915715804
##########
test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java:
##########
@@ -204,6 +222,941 @@ public void unindexedContainsExpressions()
assertRows(execute("SELECT k, v, m FROM %s WHERE v = 1 AND m CONTAINS KEY 2 AND m CONTAINS 3"), row);
}
+ @Test
+ public void testFrozenListFullIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, [4, 5, 6])");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenListValuesIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, [3, 4, 5])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, [4, 5, 6])");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list CONTAINS 3");
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenSetFullIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_set)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenSetValuesIndex() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'banana', 'cherry'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set CONTAINS 'banana'");
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenMapFullIndexEquality() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, {'k3': 'v3', 'k4': 'v4'})");
+
+ beforeAndAfterFlush(() -> {
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenMapFullIndexMapEntryRequiresFiltering() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, ?)", ImmutableMap.of(3, "v3", 4, "v4"));
+
+ beforeAndAfterFlush(() -> {
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ });
+ }
+
+ @Test
+ public void testFrozenMapEntriesIndexMapEntry() throws Throwable
Review Comment:
Thanks @adelapena for pointing out. I've addressed it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz closed pull request #4561: CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI
URL: https://github.com/apache/cassandra/pull/4561
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "dcapwell (via GitHub)" <gi...@apache.org>.
dcapwell commented on PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#issuecomment-3827378340
I am going on paternity leave and get back in April so I won't be able to review the patch anymore. GL and good work so far =)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2839551392
##########
src/java/org/apache/cassandra/index/sai/plan/Expression.java:
##########
@@ -324,6 +324,10 @@ public boolean isSatisfiedBy(ByteBuffer columnValue)
private boolean validateStringValue(ByteBuffer columnValue, ByteBuffer requestedValue)
{
+ if (indexTermType.isFrozenCollection() &&
+ (operator == IndexOperator.CONTAINS_VALUE || operator == IndexOperator.CONTAINS_KEY))
+ return termMatches(columnValue, requestedValue);
Review Comment:
Removed the redundant IF.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2915783187
##########
src/java/org/apache/cassandra/cql3/restrictions/SimpleRestriction.java:
##########
@@ -218,6 +229,17 @@ public boolean isSupportedBy(Index index)
if (isOnToken())
return false;
+ if (columnsExpression.isMapElementExpression())
+ {
+ if (index instanceof StorageAttachedIndex)
Review Comment:
I've addressed it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2824304569
##########
src/java/org/apache/cassandra/cql3/statements/schema/CreateIndexStatement.java:
##########
@@ -283,22 +268,40 @@ private void validateIndexTarget(TableMetadata table, IndexMetadata.Kind kind, I
if (column.isPartitionKey() && table.partitionKeyColumns().size() == 1)
throw ire(ONLY_PARTITION_KEY, column);
- if (baseType.isFrozenCollection() && target.type != Type.FULL)
- throw ire(CREATE_ON_FROZEN_COLUMN, target.type, column, column.name.toCQLString());
-
- if (!baseType.isFrozenCollection() && target.type == Type.FULL)
+ if (target.type == Type.FULL && !isSAIIndex(attrs) && (!baseType.isCollection() || column.type.isMultiCell()))
throw ire(FULL_ON_FROZEN_COLLECTIONS);
if (!baseType.isCollection() && target.type != Type.SIMPLE)
throw ire(NON_COLLECTION_SIMPLE_INDEX, target.type, column);
- if (!(baseType instanceof MapType && baseType.isMultiCell()) && (target.type == Type.KEYS || target.type == Type.KEYS_AND_VALUES))
+ // Frozen collections are only supported with SAI indexes
+ if (!isSAIIndex(attrs) && baseType.isCollection() && !column.type.isMultiCell())
Review Comment:
nit: Perhaps we could assign the result of `!isSAIIndex()` to a well-named variable here and avoid calling it twice?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2826573057
##########
src/java/org/apache/cassandra/cql3/restrictions/MergedRestriction.java:
##########
@@ -126,9 +126,21 @@ private static void validate(SimpleRestriction restriction, SimpleRestriction ot
checkOperator(other);
if (restriction.isContains() != other.isContains())
+ {
+ SimpleRestriction mapEntryRestriction = restriction.isContains() ? restriction : other;
+ if (mapEntryRestriction.isMapElementExpression())
+ {
+ ColumnMetadata column = mapEntryRestriction.firstColumn();
+ if (column.type.isCollection() && !column.type.isMultiCell())
Review Comment:
Yes! corrected it.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "maedhroz (via GitHub)" <gi...@apache.org>.
maedhroz commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2829945755
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -453,10 +459,80 @@ public Iterator<ByteBuffer> valuesOf(Row row, long nowInSecs)
}
}
+ public Iterator<ByteBuffer> valuesOfFrozenCollection(Row row, long nowInSecs)
+ {
+ if (row == null)
+ return null;
+
+ ByteBuffer buffer;
+
+ if (columnMetadata.kind == ColumnMetadata.Kind.CLUSTERING)
+ buffer = row.clustering().bufferAt(columnMetadata.position());
+ else
+ {
+ Cell<?> cell = row.getCell(columnMetadata);
+ if (cell == null || !cell.isLive(nowInSecs))
+ return null;
+ buffer = cell.buffer();
+ }
+
+ if (buffer == null || buffer.remaining() == 0)
+ return null;
+
+ CollectionType<?> collectionType = (CollectionType<?>) columnMetadata.type.unwrap();
+ CollectionSerializer<?> serializer = collectionType.getSerializer();
+ List<ByteBuffer> elements = serializer.unpack(buffer);
+
+ switch (collectionType.kind)
+ {
+ case LIST:
+ case SET:
+ break;
+ case MAP:
+ elements = extractMapElements(elements);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported type of collection - " + collectionType.kind);
+ }
+
+ if (isInetAddress())
+ elements.sort((c1, c2) -> compareInet(encodeInetAddress(c1), encodeInetAddress(c2)));
+
+ return elements.iterator();
+ }
+
+ private List<ByteBuffer> extractMapElements(List<ByteBuffer> elements)
+ {
+ List<ByteBuffer> result = new ArrayList<>();
Review Comment:
```suggestion
List<ByteBuffer> result = new ArrayList<>(elements.size());
```
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2826576276
##########
test/unit/org/apache/cassandra/index/sai/cql/StorageAttachedIndexDDLTest.java:
##########
@@ -1359,74 +1362,1114 @@ public void shouldRejectQueriesWithCustomExpressions()
}
@Test
- public void testInitialBuildParallelism()
+ public void testFrozenListFullIndex()
{
- Function<Long, SSTableReader> createMockSSTable = onDiskLength -> {
- SSTableReader reader = Mockito.mock(SSTableReader.class);
- when(reader.onDiskLength()).thenReturn(onDiskLength);
- return reader;
- };
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list)) USING 'sai'");
- Function<List<SSTableReader>, List<Long>> toSize = sstables -> sstables.stream().map(SSTableReader::onDiskLength).collect(Collectors.toList());
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, [4, 5, 6])");
- // total size = 55
- List<SSTableReader> sstables = LongStream.range(1, 11).boxed().map(createMockSSTable).collect(Collectors.toList());
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
- // avg = 55 == total size
- List<List<SSTableReader>> groups = StorageAttachedIndex.groupBySize(sstables, 1);
- Iterator<List<SSTableReader>> iterator = groups.iterator();
- assertEquals(1, groups.size());
- assertEquals(Arrays.asList(10L, 9L, 8L, 7L, 6L, 5L, 4L, 3L, 2L, 1L), toSize.apply(iterator.next())); // size = 55
+ flush();
- // avg = 27.5
- groups = StorageAttachedIndex.groupBySize(sstables, 2);
- iterator = groups.iterator();
- assertEquals(2, groups.size());
- assertEquals(Arrays.asList(10L, 9L, 8L, 7L), toSize.apply(iterator.next())); // size = 34
- assertEquals(Arrays.asList(6L, 5L, 4L, 3L, 2L, 1L), toSize.apply(iterator.next())); // size = 21
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
+ }
- // avg = 18.333
- groups = StorageAttachedIndex.groupBySize(sstables, 3);
- iterator = groups.iterator();
- assertEquals(3, groups.size());
- assertEquals(Arrays.asList(10L, 9L), toSize.apply(iterator.next())); // size = 19
- assertEquals(Arrays.asList(8L, 7L, 6L), toSize.apply(iterator.next())); // size = 21
- assertEquals(Arrays.asList(5L, 4L, 3L, 2L, 1L), toSize.apply(iterator.next())); // size = 15
+ @Test
+ public void testFrozenListValuesIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list)) USING 'sai'");
- // avg = 11
- groups = StorageAttachedIndex.groupBySize(sstables, 5);
- iterator = groups.iterator();
- assertEquals(4, groups.size());
- assertEquals(Arrays.asList(10L, 9L), toSize.apply(iterator.next())); // size = 19
- assertEquals(Arrays.asList(8L, 7L), toSize.apply(iterator.next())); // size = 15
- assertEquals(Arrays.asList(6L, 5L), toSize.apply(iterator.next())); // size = 11
- assertEquals(Arrays.asList(4L, 3L, 2L, 1L), toSize.apply(iterator.next())); // size = 11
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, [3, 4, 5])");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, [4, 5, 6])");
- // avg = 5.5
- groups = StorageAttachedIndex.groupBySize(sstables, 10);
- iterator = groups.iterator();
- assertEquals(7, groups.size());
- assertEquals(singletonList(10L), toSize.apply(iterator.next()));
- assertEquals(singletonList(9L), toSize.apply(iterator.next()));
- assertEquals(singletonList(8L), toSize.apply(iterator.next()));
- assertEquals(singletonList(7L), toSize.apply(iterator.next()));
- assertEquals(singletonList(6L), toSize.apply(iterator.next()));
- assertEquals(Arrays.asList(5L, 4L), toSize.apply(iterator.next()));
- assertEquals(Arrays.asList(3L, 2L, 1L), toSize.apply(iterator.next()));
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list CONTAINS 3");
+ assertEquals(2, rows.all().size());
- // avg = 2.75
- groups = StorageAttachedIndex.groupBySize(sstables, 20);
- iterator = groups.iterator();
- assertEquals(9, groups.size());
- assertEquals(singletonList(10L), toSize.apply(iterator.next()));
- assertEquals(singletonList(9L), toSize.apply(iterator.next()));
- assertEquals(singletonList(8L), toSize.apply(iterator.next()));
- assertEquals(singletonList(7L), toSize.apply(iterator.next()));
- assertEquals(singletonList(6L), toSize.apply(iterator.next()));
- assertEquals(singletonList(5L), toSize.apply(iterator.next()));
- assertEquals(singletonList(4L), toSize.apply(iterator.next()));
- assertEquals(singletonList(3L), toSize.apply(iterator.next()));
- assertEquals(Arrays.asList(2L, 1L), toSize.apply(iterator.next()));
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list CONTAINS 3");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenSetFullIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_set)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenSetValuesIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_set frozen<set<text>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (2, {'banana', 'cherry'})");
+ execute("INSERT INTO %s (pk, frozen_set) VALUES (3, {'cherry', 'date'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_set CONTAINS 'banana'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set CONTAINS 'banana'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapFullIndexEquality()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, {'k3': 'v3', 'k4': 'v4'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapFullIndexMapEntryRequiresFiltering() throws Throwable
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, ?)", ImmutableMap.of(3, "v3", 4, "v4"));
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapEntriesIndexMapEntry()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, ?)", ImmutableMap.of(3, "v3", 4, "v4"));
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapValuesIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, {'k3': 'v1', 'k4': 'v3'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, {'k5': 'v3', 'k6': 'v4'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapKeysIndex()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ createIndex("CREATE INDEX ON %s(KEYS(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, {'k1': 'v3', 'k4': 'v4'})");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, {'k5': 'v5', 'k6': 'v6'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS KEY 'k1'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS KEY 'k1'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testDifferentIndexTypesOnDifferentColumns()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "map_full frozen<map<text, text>>, " +
+ "map_values frozen<map<text, text>>, " +
+ "map_keys frozen<map<text, text>>, " +
+ "map_entries frozen<map<text, text>>)");
+
+ createIndex("CREATE INDEX idx_full ON %s(FULL(map_full)) USING 'sai'");
+ createIndex("CREATE INDEX idx_values ON %s(VALUES(map_values)) USING 'sai'");
+ createIndex("CREATE INDEX idx_keys ON %s(KEYS(map_keys)) USING 'sai'");
+ createIndex("CREATE INDEX idx_entries ON %s(ENTRIES(map_entries)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, map_full, map_values, map_keys, map_entries) " +
+ "VALUES (1, {'k1': 'v1', 'k2': 'v2'}, {'k1': 'v1', 'k2': 'v2'}, {'k1': 'v1', 'k2': 'v2'}, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (pk, map_full, map_values, map_keys, map_entries) " +
+ "VALUES (2, {'k1': 'v1', 'k2': 'v2'}, {'k3': 'v1', 'k4': 'v3'}, {'k1': 'v3', 'k5': 'v5'}, {'k1': 'v1', 'k6': 'v6'})");
+ execute("INSERT INTO %s (pk, map_full, map_values, map_keys, map_entries) " +
+ "VALUES (3, {'k3': 'v3', 'k4': 'v4'}, {'k5': 'v5', 'k6': 'v6'}, {'k7': 'v7', 'k8': 'v8'}, {'k9': 'v9', 'k10': 'v10'})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE map_full = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_values CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_keys CONTAINS KEY 'k1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_entries['k1'] = 'v1'");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_full = ?", ImmutableMap.of("k1", "v1", "k2", "v2"));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_values CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_keys CONTAINS KEY 'k1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE map_entries['k1'] = 'v1'");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFullIndexDoesNotSupportContainsOperations()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ flush();
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_list CONTAINS 1");
+ }
+
+ @Test
+ public void testValuesIndexDoesNotSupportEquality()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, [1, 2, 3])");
+ flush();
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ }
+
+ @Test
+ public void testMapEntryWithAllowFilteringDifferentKeyTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(1, rows.all().size());
+
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<text, text>>)");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of("k1", "v1", "k2", "v2"));
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map['k1'] = 'v1' ALLOW FILTERING");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map['k1'] = 'v1' ALLOW FILTERING");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapValuesIndexWithMapEntryQuery()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapKeysIndexWithMapEntryQuery()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(KEYS(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenMapDefaultIndexType()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(frozen_map) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(1, "v1", 3, "v3"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, ?)", ImmutableMap.of(4, "v4", 5, "v5"));
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map = ?", ImmutableMap.of(1, "v1", 2, "v2"));
+
+ assertInvalidMessage(StatementRestrictions.REQUIRES_ALLOW_FILTERING_MESSAGE,
+ "SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1' ALLOW FILTERING");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testMapEntryQueryWithNullAndEmptyCollections()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_map frozen<map<int, text>>)");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (1, ?)", ImmutableMap.of(1, "v1", 2, "v2"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (2, ?)", ImmutableMap.of(3, "v3", 4, "v4"));
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (3, NULL)");
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (4, ?)", ImmutableMap.of());
+ execute("INSERT INTO %s (pk, frozen_map) VALUES (5, ?)", ImmutableMap.of(1, "different_value"));
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map[1] = 'v1'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s");
+ assertEquals(5, rows.all().size());
+ }
+
+ @Test
+ public void testFullIndexWithNullAndEmptyCollections()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, frozen_list frozen<list<int>>)");
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (1, ?)", Arrays.asList(1, 2, 3));
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (2, ?)", Arrays.asList(1, 2, 3));
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (3, ?)", Arrays.asList(4, 5, 6));
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (4, NULL)");
+ execute("INSERT INTO %s (pk, frozen_list) VALUES (5, ?)", List.of());
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", List.of());
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", Arrays.asList(1, 2, 3));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list = ?", List.of());
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s");
+ assertEquals(5, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithNumericTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_bigint frozen<list<bigint>>, " +
+ "frozen_set_smallint frozen<set<smallint>>, " +
+ "frozen_map_tinyint frozen<map<tinyint, text>>, " +
+ "frozen_list_varint frozen<list<varint>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_bigint)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_smallint)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_tinyint)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list_varint)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_bigint, frozen_set_smallint, frozen_map_tinyint, frozen_list_varint) " +
+ "VALUES (1, [1, 2, 3], {10, 20}, {1: 'v1', 2: 'v2'}, [100, 200])");
+ execute("INSERT INTO %s (pk, frozen_list_bigint, frozen_set_smallint, frozen_map_tinyint, frozen_list_varint) " +
+ "VALUES (2, [1, 2, 3], {30, 40}, {3: 'v3'}, [300])");
+ execute("INSERT INTO %s (pk, frozen_list_bigint, frozen_set_smallint, frozen_map_tinyint, frozen_list_varint) " +
+ "VALUES (3, [], {}, {}, [])");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_bigint = ?", Arrays.asList(1L, 2L, 3L));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_smallint CONTAINS ?", (short)10);
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_tinyint[?] = 'v1'", (byte)1);
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_varint CONTAINS 100");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_bigint = ?", Arrays.asList(1L, 2L, 3L));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_smallint CONTAINS ?", (short)10);
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_tinyint[?] = 'v1'", (byte)1);
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_varint CONTAINS 100");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithDecimalTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_float frozen<list<float>>, " +
+ "frozen_set_double frozen<set<double>>, " +
+ "frozen_map_decimal frozen<map<decimal, text>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_float)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_double)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_decimal)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_float, frozen_set_double, frozen_map_decimal) " +
+ "VALUES (1, [1.1, 2.2], {10.5, 20.5}, {1.0: 'v1', 2.0: 'v2'})");
+ execute("INSERT INTO %s (pk, frozen_list_float, frozen_set_double, frozen_map_decimal) " +
+ "VALUES (2, [1.1, 2.2], {30.5}, {3.0: 'v3'})");
+ execute("INSERT INTO %s (pk, frozen_list_float, frozen_set_double, frozen_map_decimal) " +
+ "VALUES (3, [], {}, {})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_float = ?", Arrays.asList(1.1f, 2.2f));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_double CONTAINS 10.5");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_decimal[1.0] = 'v1'");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_float = ?", Arrays.asList(1.1f, 2.2f));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_double CONTAINS 10.5");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_decimal[1.0] = 'v1'");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithTextVariants()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_varchar frozen<list<varchar>>, " +
+ "frozen_set_ascii frozen<set<ascii>>, " +
+ "frozen_map_text frozen<map<text, varchar>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_varchar)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_ascii)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_text)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_varchar, frozen_set_ascii, frozen_map_text) " +
+ "VALUES (1, ['apple', 'banana'], {'hello', 'world'}, {'key1': 'value1', 'key2': 'value2'})");
+ execute("INSERT INTO %s (pk, frozen_list_varchar, frozen_set_ascii, frozen_map_text) " +
+ "VALUES (2, ['apple', 'banana'], {'test'}, {'key3': 'value3'})");
+ execute("INSERT INTO %s (pk, frozen_list_varchar, frozen_set_ascii, frozen_map_text) " +
+ "VALUES (3, [], {}, {})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_varchar = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_ascii CONTAINS 'hello'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_text['key1'] = 'value1'");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_varchar = ?", Arrays.asList("apple", "banana"));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_ascii CONTAINS 'hello'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_text['key1'] = 'value1'");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithTimeTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_timestamp frozen<list<timestamp>>, " +
+ "frozen_set_date frozen<set<date>>, " +
+ "frozen_map_time frozen<map<time, text>>, " +
+ "frozen_list_timeuuid frozen<list<timeuuid>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_timestamp)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_date)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_time)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_list_timeuuid)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_timestamp, frozen_set_date, frozen_map_time, frozen_list_timeuuid) " +
+ "VALUES (1, ['2023-01-01 00:00:00+0000', '2023-01-02 00:00:00+0000'], {'2023-01-01', '2023-01-02'}, " +
+ "{'12:00:00': 'noon', '18:00:00': 'evening'}, [50554d6e-29bb-11e5-b345-feff819cdc9f])");
+ execute("INSERT INTO %s (pk, frozen_list_timestamp, frozen_set_date, frozen_map_time, frozen_list_timeuuid) " +
+ "VALUES (2, ['2023-01-01 00:00:00+0000', '2023-01-02 00:00:00+0000'], {'2023-01-03'}, " +
+ "{'06:00:00': 'morning'}, [50554d6e-29bb-11e5-b345-feff819cdc9f])");
+ execute("INSERT INTO %s (pk, frozen_list_timestamp, frozen_set_date, frozen_map_time, frozen_list_timeuuid) " +
+ "VALUES (3, [], {}, {}, [])");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_timestamp = ['2023-01-01 00:00:00+0000', '2023-01-02 00:00:00+0000']");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_date CONTAINS '2023-01-01'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_time['12:00:00'] = 'noon'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_timeuuid CONTAINS 50554d6e-29bb-11e5-b345-feff819cdc9f");
+ assertEquals(2, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_timestamp = ['2023-01-01 00:00:00+0000', '2023-01-02 00:00:00+0000']");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_date CONTAINS '2023-01-01'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_time['12:00:00'] = 'noon'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_timeuuid CONTAINS 50554d6e-29bb-11e5-b345-feff819cdc9f");
+ assertEquals(2, rows.all().size());
+ }
+
+ @Test
+ public void testFrozenCollectionsWithOtherTypes()
+ {
+ createTable("CREATE TABLE %s (pk int PRIMARY KEY, " +
+ "frozen_list_uuid frozen<list<uuid>>, " +
+ "frozen_set_boolean frozen<set<boolean>>, " +
+ "frozen_map_inet frozen<map<inet, text>>)");
+
+ createIndex("CREATE INDEX ON %s(FULL(frozen_list_uuid)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(VALUES(frozen_set_boolean)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map_inet)) USING 'sai'");
+
+ execute("INSERT INTO %s (pk, frozen_list_uuid, frozen_set_boolean, frozen_map_inet) " +
+ "VALUES (1, [550e8400-e29b-41d4-a716-446655440000, 550e8400-e29b-41d4-a716-446655440001], " +
+ "{true, false}, {'127.0.0.1': 'localhost', '192.168.1.1': 'router'})");
+ execute("INSERT INTO %s (pk, frozen_list_uuid, frozen_set_boolean, frozen_map_inet) " +
+ "VALUES (2, [550e8400-e29b-41d4-a716-446655440000, 550e8400-e29b-41d4-a716-446655440001], " +
+ "{true}, {'10.0.0.1': 'server'})");
+ execute("INSERT INTO %s (pk, frozen_list_uuid, frozen_map_inet) " +
+ "VALUES (3, [], {})");
+
+ ResultSet rows = executeNet("SELECT pk FROM %s WHERE frozen_list_uuid = ?",
+ Arrays.asList(UUID.fromString("550e8400-e29b-41d4-a716-446655440000"),
+ UUID.fromString("550e8400-e29b-41d4-a716-446655440001")));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_boolean CONTAINS true");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_inet['127.0.0.1'] = 'localhost'");
+ assertEquals(1, rows.all().size());
+
+ flush();
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_list_uuid = ?",
+ Arrays.asList(UUID.fromString("550e8400-e29b-41d4-a716-446655440000"),
+ UUID.fromString("550e8400-e29b-41d4-a716-446655440001")));
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_set_boolean CONTAINS true");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT pk FROM %s WHERE frozen_map_inet['127.0.0.1'] = 'localhost'");
+ assertEquals(1, rows.all().size());
+ }
+
+ @Test
+ public void testNonFrozenCollectionsIndexes()
+ {
+ createTable("CREATE TABLE %s (id int PRIMARY KEY, list_col list<text>)");
+ createIndex("CREATE INDEX ON %s(VALUES(list_col)) USING 'sai'");
+
+ execute("INSERT INTO %s (id, list_col) VALUES (1, ['apple', 'banana'])");
+ execute("INSERT INTO %s (id, list_col) VALUES (2, ['cherry', 'date'])");
+ execute("INSERT INTO %s (id, list_col) VALUES (3, ['apple', 'banana', 'cherry'])");
+ flush();
+
+ ResultSet rows = executeNet("SELECT id FROM %s WHERE list_col CONTAINS 'apple'");
+ assertEquals(2, rows.all().size());
+
+ createTable("CREATE TABLE %s (id int PRIMARY KEY, set_col set<text>)");
+ createIndex("CREATE INDEX ON %s(VALUES(set_col)) USING 'sai'");
+
+ execute("INSERT INTO %s (id, set_col) VALUES (1, {'apple', 'banana'})");
+ execute("INSERT INTO %s (id, set_col) VALUES (2, {'cherry', 'date'})");
+ execute("INSERT INTO %s (id, set_col) VALUES (3, {'apple', 'banana', 'cherry'})");
+ flush();
+
+ rows = executeNet("SELECT id FROM %s WHERE set_col CONTAINS 'apple'");
+ assertEquals(2, rows.all().size());
+
+ createTable("CREATE TABLE %s (id int PRIMARY KEY, map_col map<text, text>)");
+ createIndex("CREATE INDEX ON %s(VALUES(map_col)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(KEYS(map_col)) USING 'sai'");
+ createIndex("CREATE INDEX ON %s(ENTRIES(map_col)) USING 'sai'");
+
+ execute("INSERT INTO %s (id, map_col) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (id, map_col) VALUES (2, {'k3': 'v3', 'k4': 'v4'})");
+ execute("INSERT INTO %s (id, map_col) VALUES (3, {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'})");
+ flush();
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col CONTAINS 'v1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col CONTAINS key 'k1'");
+ assertEquals(2, rows.all().size());
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col['k1'] = 'v1'");
+ assertEquals(2, rows.all().size());
+
+ execute("UPDATE %s SET map_col = map_col + {'k1': 'v1_updated'} WHERE id = 1");
+ flush();
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col['k1'] = 'v1_updated'");
+ assertEquals(1, rows.all().size());
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col['k1'] = 'v1'");
+ assertEquals(1, rows.all().size());
+
+ execute("DELETE map_col['k1'] FROM %s WHERE id = 3");
+ flush();
+
+ rows = executeNet("SELECT id FROM %s WHERE map_col CONTAINS key 'k1'");
+ assertEquals(1, rows.all().size());
+
+ assertThatThrownBy(() -> executeNet("SELECT id FROM %s WHERE map_col = {'k1': 'v1'} ALLOW FILTERING"))
+ .isInstanceOf(Exception.class);
+ }
+
+ @Test
+ public void testSaiNonFrozenMap()
+ {
+ createTable("CREATE TABLE %s (id int PRIMARY KEY, frozen_map map<text, text>)");
+ createIndex("CREATE INDEX ON %s(ENTRIES(frozen_map)) USING 'sai'");
+
+ execute("INSERT INTO %s (id, frozen_map) VALUES (1, {'k1': 'v1', 'k2': 'v2'})");
+ execute("INSERT INTO %s (id, frozen_map) VALUES (2, {'k3': 'v3', 'k4': 'v4'})");
+ execute("INSERT INTO %s (id, frozen_map) VALUES (3, {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'})");
+ execute("INSERT INTO %s (id, frozen_map) VALUES (4, {'k1': 'v1', 'k2': 'v2', 'k3': 'v3'})");
+ flush();
+
+ ResultSet rows = executeNet("SELECT id FROM %s WHERE frozen_map['k1']='v1';");
+ assertEquals(3, rows.all().size());
+ }
+
Review Comment:
Sure, moved all new tests cases to `CollectionIndexingTest`
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2832462656
##########
test/unit/org/apache/cassandra/index/sai/cql/CollectionIndexingTest.java:
##########
@@ -93,21 +102,29 @@ public void indexFrozenMapQueryKeys() throws Throwable
{
createPopulatedFrozenMap(createIndexDDL("FULL(value)"));
assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1");
+
+ flush();
+ assertUnsupportedIndexOperator(2, "SELECT * FROM %s WHERE value contains key 1");
Review Comment:
Updated all new tests to use `beforeAndAfterFlush()`.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "dcapwell (via GitHub)" <gi...@apache.org>.
dcapwell commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2747937562
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -476,7 +546,7 @@ else if (isLong())
return indexType.unwrap().compare(b1, b2);
// BigInteger values, frozen types and composite types (map entries) use compareUnsigned to maintain
// a consistent order between the in-memory index and the on-disk index.
- else if (isBigInteger() || isBigDecimal() || isComposite() || isFrozen())
+ else if (isBigInteger() || isBigDecimal() || isComposite())
Review Comment:
do we not also need to update `public Comparator<ByteBuffer> comparator()` on line 526
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "dcapwell (via GitHub)" <gi...@apache.org>.
dcapwell commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2748408935
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -453,6 +459,70 @@ public Iterator<ByteBuffer> valuesOf(Row row, long nowInSecs)
}
}
+ public Iterator<ByteBuffer> valuesOfFrozenCollection (Row row, long nowInSecs)
+ {
+ Cell<?> cell = row.getCell(columnMetadata);
+ if (cell == null || !cell.isLive(nowInSecs))
+ return null;
+
+ ByteBuffer buffer = cell.buffer();
+ if (buffer == null || buffer.remaining() == 0)
+ return null;
+
+ CollectionType<?> collectionType = (CollectionType<?>) columnMetadata.type.unwrap();
+ CollectionSerializer<?> serializer = collectionType.getSerializer();
+ List<ByteBuffer> elements = serializer.unpack(buffer);
+
+ Stream<ByteBuffer> stream;
+ switch (collectionType.kind)
+ {
+ case LIST:
+ case SET:
+ stream = elements.stream();
+ break;
+ case MAP:
+ stream = extractMapElements(elements);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported type of collection - " + collectionType.kind);
+ }
+
+ if (isInetAddress())
+ stream = stream.sorted((c1, c2) -> compareInet(encodeInetAddress(c1), encodeInetAddress(c2)));
+
+ List<ByteBuffer> resultList = stream.collect(java.util.stream.Collectors.toList());
Review Comment:
```suggestion
List<ByteBuffer> resultList = stream.collect(Collectors.toList());
```
Is there a reason not to import collectors?
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2772645957
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -453,6 +459,70 @@ public Iterator<ByteBuffer> valuesOf(Row row, long nowInSecs)
}
}
+ public Iterator<ByteBuffer> valuesOfFrozenCollection (Row row, long nowInSecs)
+ {
+ Cell<?> cell = row.getCell(columnMetadata);
+ if (cell == null || !cell.isLive(nowInSecs))
+ return null;
+
+ ByteBuffer buffer = cell.buffer();
+ if (buffer == null || buffer.remaining() == 0)
+ return null;
+
+ CollectionType<?> collectionType = (CollectionType<?>) columnMetadata.type.unwrap();
+ CollectionSerializer<?> serializer = collectionType.getSerializer();
+ List<ByteBuffer> elements = serializer.unpack(buffer);
+
+ Stream<ByteBuffer> stream;
+ switch (collectionType.kind)
+ {
+ case LIST:
+ case SET:
+ stream = elements.stream();
+ break;
+ case MAP:
+ stream = extractMapElements(elements);
+ break;
+ default:
+ throw new IllegalArgumentException("Unsupported type of collection - " + collectionType.kind);
Review Comment:
Removed the streams.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org
Re: [PR] CASSANDRA-18492: Allow value/element indexing on frozen collections in SAI [cassandra]
Posted by "sunil9977 (via GitHub)" <gi...@apache.org>.
sunil9977 commented on code in PR #4561:
URL: https://github.com/apache/cassandra/pull/4561#discussion_r2772647172
##########
src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java:
##########
@@ -453,6 +459,70 @@ public Iterator<ByteBuffer> valuesOf(Row row, long nowInSecs)
}
}
+ public Iterator<ByteBuffer> valuesOfFrozenCollection (Row row, long nowInSecs)
+ {
+ Cell<?> cell = row.getCell(columnMetadata);
Review Comment:
Sure, added the check.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org
---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscribe@cassandra.apache.org
For additional commands, e-mail: pr-help@cassandra.apache.org