This is an automated email from the ASF dual-hosted git repository.

maedhroz pushed a commit to branch cassandra-5.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git


The following commit(s) were added to refs/heads/cassandra-5.0 by this push:
     new 87f2a7b763 Avoid over-skipping of key iterators from static column 
indexes during mixed intersections
87f2a7b763 is described below

commit 87f2a7b7637a346cdeea23e0b74d9968ccfca619
Author: Caleb Rackliffe <calebrackli...@gmail.com>
AuthorDate: Fri Jan 19 04:39:02 2024 -0600

    Avoid over-skipping of key iterators from static column indexes during 
mixed intersections
    
    patch by Caleb Rackliffe; reviewed by Piotr Kołaczkowski and Alex Petrov 
for CASSANDRA-19278
    
    Co-authored-by: Caleb Rackliffe <calebrackli...@gmail.com>
    Co-authored-by: Piotr Kołaczkowski <pkola...@gmail.com>
---
 CHANGES.txt                                        |   1 +
 .../cassandra/index/sai/disk/RowMapping.java       |  49 ++--
 .../index/sai/disk/v1/MemtableIndexWriter.java     |  31 +--
 .../iterators/KeyRangeIntersectionIterator.java    | 114 ++++++---
 .../index/sai/iterators/KeyRangeIterator.java      |   8 +-
 .../cassandra/index/sai/utils/PrimaryKey.java      |  53 +++-
 .../index/sai/cql/RandomIntersectionTest.java      | 227 -----------------
 .../index/sai/cql/StaticColumnIndexTest.java       |  21 +-
 .../cql/intersection/RandomIntersectionTester.java | 270 +++++++++++++++++++++
 .../intersection/RandomMixedIntersectionTest.java  |  53 ++++
 .../RandomMixedPartitionIntersectionTest.java      |  53 ++++
 .../RandomRegularIntersectionTest.java             |  53 ++++
 .../RandomRegularPartitionIntersectionTest.java    |  53 ++++
 .../intersection/RandomStaticIntersectionTest.java |  53 ++++
 .../RandomStaticPartitionIntersectionTest.java     |  53 ++++
 .../TwoRegularOneStaticIntersectionTest.java       |  53 ++++
 ...oRegularOneStaticPartitionIntersectionTest.java |  53 ++++
 .../cassandra/index/sai/utils/PrimaryKeyTest.java  |   3 +-
 18 files changed, 897 insertions(+), 304 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index 73b0ecdea9..90cb544d10 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.0-beta2
+ * Avoid over-skipping of key iterators from static column indexes during 
mixed intersections (CASSANDRA-19278)
  * Make concurrent_index_builders configurable at runtime (CASSANDRA-19266)
  * Fix storage_compatibility_mode for streaming (CASSANDRA-19126)
  * Add support of vector type to cqlsh COPY command (CASSANDRA-19118)
diff --git a/src/java/org/apache/cassandra/index/sai/disk/RowMapping.java 
b/src/java/org/apache/cassandra/index/sai/disk/RowMapping.java
index ec122ae006..43bb79b91b 100644
--- a/src/java/org/apache/cassandra/index/sai/disk/RowMapping.java
+++ b/src/java/org/apache/cassandra/index/sai/disk/RowMapping.java
@@ -70,12 +70,6 @@ public class RowMapping
         {
             return -1;
         }
-
-        @Override
-        public int size()
-        {
-            return 0;
-        }
     };
 
     private final InMemoryTrie<Long> rowMapping = new 
InMemoryTrie<>(BufferType.OFF_HEAP);
@@ -84,10 +78,14 @@ public class RowMapping
 
     public PrimaryKey minKey;
     public PrimaryKey maxKey;
+    public PrimaryKey minStaticKey;
+    public PrimaryKey maxStaticKey;
 
     public long maxSSTableRowId = -1;
+    public long maxStaticSSTableRowId = -1;
 
-    public int count;
+    public int rowCount;
+    public int staticRowCount;
 
     private RowMapping()
     {}
@@ -171,20 +169,32 @@ public class RowMapping
 
         rowMapping.putSingleton(key, sstableRowId, OVERWRITE_TRANSFORMER);
 
-        maxSSTableRowId = Math.max(maxSSTableRowId, sstableRowId);
-
-        // data is written in token sorted order
-        if (minKey == null)
-            minKey = key;
-        maxKey = key;
-        count++;
+        // Data is written in primary key order. If a schema contains 
clustering keys, it may also contain static
+        // columns. We track min, max, and count for static keys separately 
here so that we can pass them to the segment
+        // metadata for indexes on static columns.
+        if (key.kind() == PrimaryKey.Kind.STATIC)
+        {
+            if (minStaticKey == null)
+                minStaticKey = key;
+            maxStaticKey = key;
+            staticRowCount++;
+            maxStaticSSTableRowId = Math.max(maxStaticSSTableRowId, 
sstableRowId);
+        }
+        else
+        {
+            if (minKey == null)
+                minKey = key;
+            maxKey = key;
+            rowCount++;
+            maxSSTableRowId = Math.max(maxSSTableRowId, sstableRowId);
+        }
     }
 
     /**
-     * Returns the SSTable row Id for a {@link PrimaryKey}
+     * Returns the SSTable row ID for a {@link PrimaryKey}
      *
      * @param key the {@link PrimaryKey}
-     * @return a valid SSTable row Id for the {@link PrimaryKey} or -1 if the 
{@link PrimaryKey} doesn't exist
+     * @return a valid SSTable row ID for the {@link PrimaryKey} or -1 if the 
{@link PrimaryKey} doesn't exist
      * in the {@link RowMapping}
      */
     public int get(PrimaryKey key)
@@ -193,13 +203,8 @@ public class RowMapping
         return sstableRowId == null ? -1 : Math.toIntExact(sstableRowId);
     }
 
-    public int size()
-    {
-        return count;
-    }
-
     public boolean hasRows()
     {
-        return maxSSTableRowId >= 0;
+        return maxSSTableRowId >= 0 || maxStaticSSTableRowId >= 0;
     }
 }
diff --git 
a/src/java/org/apache/cassandra/index/sai/disk/v1/MemtableIndexWriter.java 
b/src/java/org/apache/cassandra/index/sai/disk/v1/MemtableIndexWriter.java
index 65e42ef91e..2bf6639e16 100644
--- a/src/java/org/apache/cassandra/index/sai/disk/v1/MemtableIndexWriter.java
+++ b/src/java/org/apache/cassandra/index/sai/disk/v1/MemtableIndexWriter.java
@@ -155,15 +155,15 @@ public class MemtableIndexWriter implements 
PerColumnIndexWriter
             return 0;
         }
 
+        PrimaryKey minKey = indexTermType.columnMetadata().isStatic() ? 
rowMapping.minStaticKey : rowMapping.minKey;
+        PrimaryKey maxKey = indexTermType.columnMetadata().isStatic() ? 
rowMapping.maxStaticKey : rowMapping.maxKey;
+
         // During index memtable flush, the data is sorted based on terms.
         SegmentMetadata metadata = new SegmentMetadata(0,
                                                        numRows,
-                                                       
terms.getMinSSTableRowId(),
-                                                       
terms.getMaxSSTableRowId(),
-                                                       rowMapping.minKey,
-                                                       rowMapping.maxKey,
-                                                       terms.getMinTerm(),
-                                                       terms.getMaxTerm(),
+                                                       
terms.getMinSSTableRowId(), terms.getMaxSSTableRowId(),
+                                                       minKey, maxKey, 
+                                                       terms.getMinTerm(), 
terms.getMaxTerm(),
                                                        indexMetas);
 
         try (MetadataWriter metadataWriter = new 
MetadataWriter(indexDescriptor.openPerIndexOutput(IndexComponent.META, 
indexIdentifier)))
@@ -176,18 +176,19 @@ public class MemtableIndexWriter implements 
PerColumnIndexWriter
 
     private void flushVectorIndex(long startTime, Stopwatch stopwatch) throws 
IOException
     {
-        SegmentMetadata.ComponentMetadataMap metadataMap = 
memtable.writeDirect(indexDescriptor, indexIdentifier, rowMapping::get);
+        int rowCount = indexTermType.columnMetadata().isStatic() ? 
rowMapping.staticRowCount : rowMapping.rowCount;
+        PrimaryKey minKey = indexTermType.columnMetadata().isStatic() ? 
rowMapping.minStaticKey : rowMapping.minKey;
+        PrimaryKey maxKey = indexTermType.columnMetadata().isStatic() ? 
rowMapping.maxStaticKey : rowMapping.maxKey;
+        long maxSSTableRowId = indexTermType.columnMetadata().isStatic() ? 
rowMapping.maxStaticSSTableRowId : rowMapping.maxSSTableRowId;
 
-        completeIndexFlush(rowMapping.size(), startTime, stopwatch);
+        SegmentMetadata.ComponentMetadataMap metadataMap = 
memtable.writeDirect(indexDescriptor, indexIdentifier, rowMapping::get);
+        completeIndexFlush(rowCount, startTime, stopwatch);
 
         SegmentMetadata metadata = new SegmentMetadata(0,
-                                                       rowMapping.size(),
-                                                       0,
-                                                       
rowMapping.maxSSTableRowId,
-                                                       rowMapping.minKey,
-                                                       rowMapping.maxKey,
-                                                       ByteBufferUtil.bytes(0),
-                                                       ByteBufferUtil.bytes(0),
+                                                       rowCount,
+                                                       0, maxSSTableRowId,
+                                                       minKey, maxKey, 
+                                                       
ByteBufferUtil.bytes(0), ByteBufferUtil.bytes(0),
                                                        metadataMap);
 
         try (MetadataWriter writer = new 
MetadataWriter(indexDescriptor.openPerIndexOutput(IndexComponent.META, 
indexIdentifier)))
diff --git 
a/src/java/org/apache/cassandra/index/sai/iterators/KeyRangeIntersectionIterator.java
 
b/src/java/org/apache/cassandra/index/sai/iterators/KeyRangeIntersectionIterator.java
index 6e297b338c..f674c04dfc 100644
--- 
a/src/java/org/apache/cassandra/index/sai/iterators/KeyRangeIntersectionIterator.java
+++ 
b/src/java/org/apache/cassandra/index/sai/iterators/KeyRangeIntersectionIterator.java
@@ -28,13 +28,19 @@ import org.slf4j.LoggerFactory;
 
 import org.apache.cassandra.config.CassandraRelevantProperties;
 import org.apache.cassandra.index.sai.utils.PrimaryKey;
+import org.apache.cassandra.index.sai.utils.PrimaryKey.Kind;
 import org.apache.cassandra.io.util.FileUtils;
 import org.apache.cassandra.tracing.Tracing;
 
+import javax.annotation.Nullable;
+
 /**
  * A simple intersection iterator that makes no real attempts at optimising 
the iteration apart from
- * initially sorting the ranges. This implementation also supports an 
intersection limit which limits
- * the number of ranges that will be included in the intersection. This 
currently defaults to 2.
+ * initially sorting the ranges. This implementation also supports an 
intersection limit via
+ * {@code CassandraRelevantProperties.SAI_INTERSECTION_CLAUSE_LIMIT} which 
limits the number of ranges that will 
+ * be included in the intersection.
+ * <p> 
+ * Intersection only works for ranges that are compatible according to {@link 
PrimaryKey.Kind#isIntersectable(Kind)}.
  */
 public class KeyRangeIntersectionIterator extends KeyRangeIterator
 {
@@ -56,52 +62,82 @@ public class KeyRangeIntersectionIterator extends 
KeyRangeIterator
     @Override
     protected PrimaryKey computeNext()
     {
-        // Range iterator that has been advanced in the previous cycle of the 
outer loop.
-        // Initially there hasn't been the previous cycle, so set to null.
-        int alreadyAvanced = -1;
-
-        // The highest primary key seen on any range iterator so far.
+        // Advance one iterator to the next key and remember the key as the 
highest seen so far.
         // It can become null when we reach the end of the iterator.
-        PrimaryKey highestKey = getCurrent();
+        // If there are both static and non-static keys being iterated here, 
we advance a non-static one,
+        // regardless of the order of ranges in the ranges list.
+        PrimaryKey highestKey = advanceOneRange();
 
         outer:
-        // We need to check if highestKey exceeds the maximum because the 
maximum is
-        // the lowest value maximum of all the ranges. As a result any value 
could
-        // potentially exceed it.
+        // After advancing one iterator, we must try to advance all the other 
iterators that got behind,
+        // so they catch up to it. Note that we will not advance the iterators 
for static columns
+        // as long as they point to the partition of the highest key. (This is 
because STATIC primary keys 
+        // compare to other keys only by partition.) This loop continues until 
all iterators point to the same key,
+        // or if we run out of keys on any of them, or if we exceed the 
maximum key.
+        // There is no point in iterating after maximum, because no keys will 
match beyond that point.
         while (highestKey != null && highestKey.compareTo(getMaximum()) <= 0)
         {
-            // Try advance all iterators to the highest key seen so far.
+            // Try to advance all iterators to the highest key seen so far.
             // Once this inner loop finishes normally, all iterators are 
guaranteed to be at the same value.
-            for (int index = 0; index < ranges.size(); index++)
+            for (KeyRangeIterator range : ranges)
             {
-                if (index != alreadyAvanced)
+                if (range.getCurrent().compareTo(highestKey) < 0)
                 {
-                    KeyRangeIterator range = ranges.get(index);
-                    PrimaryKey nextKey = nextOrNull(range, highestKey);
-                    if (nextKey == null || nextKey.compareTo(highestKey) > 0)
+                    // If we advance a STATIC key, then we must advance it to 
the same partition as the highestKey.
+                    // Advancing a STATIC key to a WIDE key directly (without 
throwing away the clustering) would
+                    // go too far, as WIDE keys are stored after STATIC in the 
posting list.
+                    PrimaryKey nextKey = range.getCurrent().kind() == 
Kind.STATIC
+                                         ? nextOrNull(range, 
highestKey.toStatic())
+                                         : nextOrNull(range, highestKey);
+
+                    // We use strict comparison here, since it orders WIDE 
primary keys after STATIC primary keys
+                    // in the same partition. When WIDE keys are present, we 
want to return them rather than STATIC
+                    // keys to avoid retrieving and post-filtering entire 
partitions.
+                    if (nextKey == null || nextKey.compareToStrict(highestKey) 
> 0)
                     {
                         // We jumped over the highest key seen so far, so make 
it the new highest key.
                         highestKey = nextKey;
-                        // Remember this iterator to avoid advancing it again, 
because it is already at the highest key
-                        alreadyAvanced = index;
-                        // This iterator jumped over, so the other iterators 
are lagging behind now,
+
+                        // This iterator jumped over, so the other iterators 
might be lagging behind now,
                         // including the ones already advanced in the earlier 
cycles of the inner loop.
-                        // Therefore, restart the inner loop in order to 
advance
-                        // the other iterators except this one to match the 
new highest key.
+                        // Therefore, restart the inner loop in order to 
advance the lagging iterators.
                         continue outer;
                     }
-                    assert nextKey.compareTo(highestKey) == 0:
-                    String.format("skipped to an item smaller than the target; 
" +
-                                  "iterator: %s, target key: %s, returned key: 
%s", range, highestKey, nextKey);
+                    assert nextKey.compareTo(highestKey) == 0 :
+                        String.format("Skipped to a key smaller than the 
target! " +
+                                      "iterator: %s, target key: %s, returned 
key: %s", range, highestKey, nextKey);
                 }
             }
-            // If we reached here, next() has been called at least once on 
each range iterator and
-            // the last call to next() on each iterator returned a value equal 
to the highestKey.
+
+            // If we get here, all iterators have been advanced to the same 
key. When STATIC and WIDE keys are
+            // mixed, this means WIDE keys point to exactly the same row, and 
STATIC keys the same partition.
             return highestKey;
         }
+
         return endOfData();
     }
 
+    /**
+     * Advances the iterator of one range to the next item, which becomes the 
highest seen so far.
+     * Iterators pointing to STATIC keys are advanced only if no non-STATIC 
keys have been advanced.
+     *
+     * @return the next highest key or null if the iterator has reached the end
+     */
+    private @Nullable PrimaryKey advanceOneRange()
+    {
+        PrimaryKey highestKey = getCurrent();
+
+        for (KeyRangeIterator range : ranges)
+            if (range.getCurrent().kind() != Kind.STATIC)
+                return nextOrNull(range, highestKey);
+        
+        for (KeyRangeIterator range : ranges)
+            if (range.getCurrent().kind() == Kind.STATIC)
+                return nextOrNull(range, highestKey);
+
+        throw new IllegalStateException("There should be at least one range to 
advance!");
+    }
+
     @Override
     protected void performSkipTo(PrimaryKey nextKey)
     {
@@ -236,6 +272,20 @@ public class KeyRangeIntersectionIterator extends 
KeyRangeIterator
             if (ranges.size() == 1)
                 return ranges.get(0);
 
+            // Make sure intersection is supported on the ranges provided:
+            PrimaryKey.Kind firstKind = null;
+            
+            for (KeyRangeIterator range : ranges)
+            {
+                PrimaryKey key = range.getCurrent();
+
+                if (key != null)
+                    if (firstKind == null)
+                        firstKind = key.kind();
+                    else if (!firstKind.isIntersectable(key.kind()))
+                        throw new IllegalArgumentException("Cannot intersect " 
+ firstKind + " and " + key.kind() + " ranges!");
+            }
+
             return new KeyRangeIntersectionIterator(statistics, ranges);
         }
 
@@ -277,18 +327,18 @@ public class KeyRangeIntersectionIterator extends 
KeyRangeIterator
 
     /**
      * Ranges are overlapping the following cases:
-     *
+     * <p>
      *   * When they have a common subrange:
-     *
+     * <p>
      *   min       b.current      max          b.max
      *   +---------|--------------+------------|
-     *
+     * <p>
      *   b.current      min       max          b.max
      *   |--------------+---------+------------|
-     *
+     * <p>
      *   min        b.current     b.max        max
      *   +----------|-------------|------------+
-     *
+     * <p>
      *
      *  If either range is empty, they're disjoint.
      */
diff --git 
a/src/java/org/apache/cassandra/index/sai/iterators/KeyRangeIterator.java 
b/src/java/org/apache/cassandra/index/sai/iterators/KeyRangeIterator.java
index cb6b69a5a9..da1b8c2a04 100644
--- a/src/java/org/apache/cassandra/index/sai/iterators/KeyRangeIterator.java
+++ b/src/java/org/apache/cassandra/index/sai/iterators/KeyRangeIterator.java
@@ -211,19 +211,19 @@ public abstract class KeyRangeIterator extends 
AbstractGuavaIterator<PrimaryKey>
         }
     }
 
-    protected static <T extends Comparable<T>> T nullSafeMin(T a, T b)
+    protected static PrimaryKey nullSafeMin(PrimaryKey a, PrimaryKey b)
     {
         if (a == null) return b;
         if (b == null) return a;
 
-        return a.compareTo(b) > 0 ? b : a;
+        return a.compareToStrict(b) > 0 ? b : a;
     }
 
-    protected static <T extends Comparable<T>> T nullSafeMax(T a, T b)
+    protected static PrimaryKey nullSafeMax(PrimaryKey a, PrimaryKey b)
     {
         if (a == null) return b;
         if (b == null) return a;
 
-        return a.compareTo(b) > 0 ? a : b;
+        return a.compareToStrict(b) > 0 ? a : b;
     }
 }
diff --git a/src/java/org/apache/cassandra/index/sai/utils/PrimaryKey.java 
b/src/java/org/apache/cassandra/index/sai/utils/PrimaryKey.java
index f3492927eb..c079a66c4c 100644
--- a/src/java/org/apache/cassandra/index/sai/utils/PrimaryKey.java
+++ b/src/java/org/apache/cassandra/index/sai/utils/PrimaryKey.java
@@ -20,7 +20,6 @@ package org.apache.cassandra.index.sai.utils;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Objects;
-
 import java.util.stream.Collectors;
 
 import org.apache.cassandra.db.BufferDecoratedKey;
@@ -59,6 +58,18 @@ public interface PrimaryKey extends Comparable<PrimaryKey>, 
ByteComparable
         {
             this.hasClustering = hasClustering;
         }
+
+        public boolean isIntersectable(Kind other)
+        {
+            if (this == TOKEN)
+                return other == TOKEN;
+            else if (this == SKINNY)
+                return other == SKINNY;
+            else if (this == WIDE || this == STATIC)
+                return other == WIDE || other == STATIC;
+            
+            throw new AssertionError("Unknown Kind: " + other);
+        }
     }
 
     class Factory
@@ -315,6 +326,15 @@ public interface PrimaryKey extends 
Comparable<PrimaryKey>, ByteComparable
                 return 0;
             }
 
+            @Override
+            public int compareToStrict(PrimaryKey o)
+            {
+                int cmp = compareTo(o);
+                // Always order this STATIC key before a WIDE key in the same 
partition, as this corresponds to the
+                // order of the corresponding row IDs in an on-disk postings 
list.
+                return o.kind() == Kind.WIDE && cmp == 0 ? -1 : cmp;
+            }
+
             @Override
             public int hashCode()
             {
@@ -326,6 +346,12 @@ public interface PrimaryKey extends 
Comparable<PrimaryKey>, ByteComparable
             {
                 return String.format("PrimaryKey: { token: %s, partition: %s, 
clustering: STATIC } ", token(), partitionKey());
             }
+
+            @Override
+            public PrimaryKey toStatic()
+            {
+                return this;
+            }
         }
 
         class WidePrimaryKey extends SkinnyPrimaryKey
@@ -376,6 +402,15 @@ public interface PrimaryKey extends 
Comparable<PrimaryKey>, ByteComparable
                 return clusteringComparator.compare(clustering(), 
o.clustering());
             }
 
+            @Override
+            public int compareToStrict(PrimaryKey o)
+            {
+                int cmp = compareTo(o);
+                // Always order this WIDE key before a STATIC key in the same 
partition, as this corresponds to the
+                // order of the corresponding row IDs in an on-disk postings 
list.
+                return o.kind() == Kind.STATIC && cmp == 0 ? 1 : cmp;
+            }
+
             @Override
             public int hashCode()
             {
@@ -393,6 +428,12 @@ public interface PrimaryKey extends 
Comparable<PrimaryKey>, ByteComparable
                                            .map(ByteBufferUtil::bytesToHex)
                                            .collect(Collectors.joining(", ")));
             }
+
+            @Override
+            public PrimaryKey toStatic()
+            {
+                return new StaticPrimaryKey(partitionKey);
+            }
         }
     }
 
@@ -438,4 +479,14 @@ public interface PrimaryKey extends 
Comparable<PrimaryKey>, ByteComparable
      * @throws UnsupportedOperationException for {@link PrimaryKey} 
implementations that are not byte-comparable
      */
     ByteSource asComparableBytes(ByteComparable.Version version);
+
+    default PrimaryKey toStatic()
+    {
+        throw new UnsupportedOperationException("Only STATIC and WIDE keys can 
be converted to STATIC");
+    }
+
+    default int compareToStrict(PrimaryKey o)
+    {
+        return compareTo(o);
+    }
 }
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/RandomIntersectionTest.java 
b/test/unit/org/apache/cassandra/index/sai/cql/RandomIntersectionTest.java
deleted file mode 100644
index 3ab0b80e35..0000000000
--- a/test/unit/org/apache/cassandra/index/sai/cql/RandomIntersectionTest.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.cassandra.index.sai.cql;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.stream.Collectors;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-
-import org.apache.cassandra.index.sai.utils.SAIRandomizedTester;
-
-@RunWith(Parameterized.class)
-public class RandomIntersectionTest extends SAIRandomizedTester
-{
-    private static final Object[][] EMPTY_ROWS = new Object[][]{};
-
-    @Parameterized.Parameter
-    public String testName;
-
-    @Parameterized.Parameter(1)
-    public boolean partitionRestricted;
-
-    @Parameterized.Parameter(2)
-    public boolean largePartition;
-
-    @Parameterized.Parameter(3)
-    public boolean v1Cardinality;
-
-    @Parameterized.Parameter(4)
-    public boolean v2Cardinality;
-
-    @Parameterized.Parameters(name = "{0}")
-    public static List<Object[]> parameters()
-    {
-        List<Object[]> parameters = new LinkedList<>();
-
-        parameters.add(new Object[]{ "Large partition restricted high high", 
true, true, true, true });
-        parameters.add(new Object[]{ "Large partition restricted low low", 
true, true, false, false });
-        parameters.add(new Object[]{ "Large partition restricted high low", 
true, true, true, false });
-        parameters.add(new Object[]{ "Large partition unrestricted high high", 
false, true, true, true });
-        parameters.add(new Object[]{ "Large partition unrestricted low low", 
false, true, false, false });
-        parameters.add(new Object[]{ "Large partition unrestricted high low", 
false, true, true, false });
-        parameters.add(new Object[]{ "Small partition restricted high high", 
true, false, true, true });
-        parameters.add(new Object[]{ "Small partition restricted low low", 
true, false, false, false });
-        parameters.add(new Object[]{ "Small partition restricted high low", 
true, false, true, false });
-        parameters.add(new Object[]{ "Small partition unrestricted high high", 
false, false, true, true });
-        parameters.add(new Object[]{ "Small partition unrestricted low low", 
false, false, false, false });
-        parameters.add(new Object[]{ "Small partition unrestricted high low", 
false, false, true, false });
-
-        return parameters;
-    }
-
-    private int numRows;
-
-    @Before
-    public void createTableAndIndexes()
-    {
-        createTable("CREATE TABLE %s (pk int, ck int, v1 int, v2 int, PRIMARY 
KEY(pk, ck))");
-        createIndex("CREATE INDEX ON %s(v1) USING 'sai'");
-        createIndex("CREATE INDEX ON %s(v2) USING 'sai'");
-
-        numRows = nextInt(50000, 200000);
-    }
-
-    @Test
-    public void randomIntersectionTest() throws Throwable
-    {
-        if (partitionRestricted)
-            runRestrictedQueries();
-        else
-            runUnrestrictedQueries();
-    }
-
-    private void runRestrictedQueries() throws Throwable
-    {
-        Map<Integer, List<TestRow>> testRowMap = buildAndLoadTestRows();
-
-        beforeAndAfterFlush(() -> {
-            for (int queryCount = 0; queryCount < nextInt(10, 100); 
queryCount++)
-            {
-                int pk = testRowMap.keySet().stream().skip(nextInt(0, 
testRowMap.size())).findFirst().orElseThrow();
-                int v1 = nextV1();
-                int v2 = nextV2();
-
-                List<Object[]> expected = testRowMap.get(pk)
-                                                    .stream()
-                                                    
.sorted(Comparator.comparingInt(o -> o.ck))
-                                                    .filter(row -> row.v1 > v1 
&& row.v2 > v2)
-                                                    .map(row -> row(row.ck))
-                                                    
.collect(Collectors.toList());
-
-                assertRows(execute("SELECT ck FROM %s WHERE pk = ? AND v1 > ? 
AND v2 > ?", pk, v1, v2), expected.toArray(EMPTY_ROWS));
-            }
-        });
-    }
-
-    private void runUnrestrictedQueries() throws Throwable
-    {
-        Map<Integer, List<TestRow>> testRowMap = buildAndLoadTestRows();
-
-        beforeAndAfterFlush(() -> {
-            for (int queryCount = 0; queryCount < nextInt(10, 100); 
queryCount++)
-            {
-                int v1 = nextV1();
-                int v2 = nextV2();
-
-                List<Object[]> expected = testRowMap.values()
-                                                    .stream()
-                                                    
.flatMap(Collection::stream)
-                                                    .filter(row -> row.v1 == 
v1 && row.v2 == v2)
-                                                    .map(row -> row(row.ck))
-                                                    
.collect(Collectors.toList());
-
-                assertRowsIgnoringOrder(execute("SELECT ck FROM %s WHERE v1 = 
? AND v2 = ?", v1, v2), expected.toArray(EMPTY_ROWS));
-            }
-        });
-    }
-
-    private Map<Integer, List<TestRow>> buildAndLoadTestRows()
-    {
-        Map<Integer, List<TestRow>> testRowMap = new HashMap<>();
-
-        int clusterSize = largePartition ? nextInt(500, 5000) : nextInt(10, 
100);
-        int partition = nextInt(0, numRows);
-        List<TestRow> rowList = new ArrayList<>(clusterSize);
-        testRowMap.put(partition, rowList);
-        int clusterCount = 0;
-        for (int index = 0; index < numRows; index++)
-        {
-            TestRow row = new TestRow(partition, nextInt(10, numRows), 
nextV1(), nextV2());
-            while (rowList.contains(row))
-                row = new TestRow(partition, nextInt(10, numRows), nextV1(), 
nextV2());
-
-            rowList.add(row);
-            clusterCount++;
-            if (clusterCount == clusterSize)
-            {
-                clusterCount = 0;
-                clusterSize = largePartition ? nextInt(500, 5000) : 
nextInt(10, 100);
-                partition = nextInt(0, numRows);
-                while (testRowMap.containsKey(partition))
-                    partition = nextInt(0, numRows);
-                rowList = new ArrayList<>(clusterSize);
-                testRowMap.put(partition, rowList);
-            }
-        }
-        testRowMap.values().stream().flatMap(Collection::stream).forEach(row 
-> execute("INSERT INTO %s (pk, ck, v1, v2) VALUES (?, ?, ?, ?)",
-                                                                               
         row.pk, row.ck, row.v1, row.v2));
-        return testRowMap;
-    }
-
-    private int nextV1()
-    {
-        return v1Cardinality ? nextInt(10, numRows/10) : nextInt(10, 
numRows/1000);
-    }
-
-    private int nextV2()
-    {
-        return v2Cardinality ? nextInt(10, numRows/10) : nextInt(10, 
numRows/1000);
-    }
-
-    private static class TestRow implements Comparable<TestRow>
-    {
-        final int pk;
-        final int ck;
-        final int v1;
-        final int v2;
-
-        TestRow(int pk, int ck, int v1, int v2)
-        {
-            this.pk = pk;
-            this.ck = ck;
-            this.v1 = v1;
-            this.v2 = v2;
-        }
-
-        @Override
-        public int compareTo(TestRow other)
-        {
-            int cmp = Integer.compare(pk, other.pk);
-            if (cmp != 0)
-                return cmp;
-            return Integer.compare(ck, other.ck);
-        }
-
-        @Override
-        public boolean equals(Object obj)
-        {
-            if (obj instanceof TestRow)
-                return compareTo((TestRow) obj) == 0;
-
-            return false;
-        }
-
-        @Override
-        public int hashCode()
-        {
-            return Objects.hash(pk, ck);
-        }
-    }
-}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/StaticColumnIndexTest.java 
b/test/unit/org/apache/cassandra/index/sai/cql/StaticColumnIndexTest.java
index 0bdee106fd..faaf74f5c6 100644
--- a/test/unit/org/apache/cassandra/index/sai/cql/StaticColumnIndexTest.java
+++ b/test/unit/org/apache/cassandra/index/sai/cql/StaticColumnIndexTest.java
@@ -49,7 +49,26 @@ public class StaticColumnIndexTest extends SAITester
         execute("INSERT INTO %s(pk, ck,       val2) VALUES(?, ?,    ?)", 1, 2, 
    2000);
         execute("INSERT INTO %s(pk, ck, val1, val2) VALUES(?, ?, ?, ?)", 2, 1, 
40, 2000);
 
-        beforeAndAfterFlush(() -> assertRows(execute("SELECT pk, ck, val1, 
val2 FROM %s WHERE val1 = 20 AND val2 = 2000 ALLOW FILTERING"),
+        beforeAndAfterFlush(() -> assertRows(execute("SELECT pk, ck, val1, 
val2 FROM %s WHERE val1 = 20 AND val2 = 2000"),
                                              row(1, 2, 20, 2000)));
     }
+
+    @Test
+    public void staticAndNonStaticRangeIntersection() throws Throwable
+    {
+        createTable("CREATE TABLE %s (pk int, ck int, v1 int, s1 int static, 
PRIMARY KEY(pk, ck))");
+        createIndex("CREATE INDEX ON %s(v1) USING 'sai'");
+        createIndex("CREATE INDEX ON %s(s1) USING 'sai'");
+
+        execute("INSERT INTO %s (pk, ck, v1) VALUES (?, ?, ?)", 0, 1, 0);
+        execute("INSERT INTO %s (pk, ck, v1) VALUES (?, ?, ?)", 0, 2, 1);
+        execute("INSERT INTO %s (pk, ck, v1) VALUES (?, ?, ?)", 0, 3, 2);
+        execute("INSERT INTO %s (pk, ck, v1) VALUES (?, ?, ?)", 0, 4, 3);
+        execute("INSERT INTO %s (pk, ck, v1) VALUES (?, ?, ?)", 0, 5, 4);
+        execute("INSERT INTO %s (pk, ck, v1) VALUES (?, ?, ?)", 0, 6, 5);
+
+        execute("INSERT INTO %s (pk, s1) VALUES (?, ?)", 0, 100);
+
+        beforeAndAfterFlush(() -> assertRowCount(execute("SELECT * FROM %s 
WHERE pk = ? AND v1 > ? AND s1 = ?", 0, 2, 100), 3));
+    }
 }
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomIntersectionTester.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomIntersectionTester.java
new file mode 100644
index 0000000000..3b1436ae39
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomIntersectionTester.java
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import org.junit.Before;
+import org.junit.runners.Parameterized;
+
+import org.apache.cassandra.config.CassandraRelevantProperties;
+import org.apache.cassandra.cql3.UntypedResultSet;
+import org.apache.cassandra.index.sai.utils.SAIRandomizedTester;
+
+public abstract class RandomIntersectionTester extends SAIRandomizedTester
+{
+    private static final Object[][] EMPTY_ROWS = new Object[][]{};
+
+    protected enum Mode { REGULAR, STATIC, REGULAR_STATIC, 
TWO_REGULAR_ONE_STATIC }
+
+    @Parameterized.Parameter
+    public String testName;
+
+    @Parameterized.Parameter(1)
+    public boolean partitionRestricted;
+
+    @Parameterized.Parameter(2)
+    public boolean largePartition;
+
+    @Parameterized.Parameter(3)
+    public boolean v1Cardinality;
+
+    @Parameterized.Parameter(4)
+    public boolean v2Cardinality;
+
+    @Parameterized.Parameter(5)
+    public Mode mode;
+
+    private int numPartitions;
+
+    @Before
+    public void createTableAndIndexes()
+    {
+        CassandraRelevantProperties.SAI_INTERSECTION_CLAUSE_LIMIT.setInt(3);
+
+        createTable("CREATE TABLE %s (pk int, ck int, v1 int, v2 int, s1 int 
static, s2 int static, PRIMARY KEY(pk, ck))");
+        createIndex("CREATE INDEX ON %s(v1) USING 'sai'");
+        createIndex("CREATE INDEX ON %s(v2) USING 'sai'");
+        createIndex("CREATE INDEX ON %s(s1) USING 'sai'");
+        createIndex("CREATE INDEX ON %s(s2) USING 'sai'");
+
+        numPartitions = nextInt(15000, 100000);
+    }
+
+    protected void runRestrictedQueries() throws Throwable
+    {
+        Map<Integer, List<TestRow>> testRowMap = buildAndLoadTestRows();
+
+        beforeAndAfterFlush(() -> {
+            for (int queryCount = 0; queryCount < nextInt(10, 100); 
queryCount++)
+            {
+                int pk = testRowMap.keySet().stream().skip(nextInt(0, 
testRowMap.size())).findFirst().orElseThrow();
+                int v1 = nextV1();
+                int v2 = nextV2();
+
+                Predicate<TestRow> predicate = null;
+
+                if (mode == Mode.REGULAR)
+                    predicate = row -> row.v1 > v1 && row.v2 > v2;
+                else if (mode == Mode.STATIC)
+                    predicate = row -> row.s1 > v1 && row.s2 > v2;
+                else if (mode == Mode.REGULAR_STATIC)
+                    predicate = row -> row.v1 > v1 && row.s2 > v2;
+                else if (mode == Mode.TWO_REGULAR_ONE_STATIC)
+                    predicate = row -> row.v1 > v1 && row.v2 > v2 && row.s2 > 
v2;
+
+                assert predicate != null : "Predicate should be assigned!";
+
+                List<Object[]> expected = testRowMap.get(pk)
+                                                    .stream()
+                                                    
.sorted(Comparator.comparingInt(o -> o.ck))
+                                                    .filter(predicate)
+                                                    .map(row -> row(row.pk, 
row.ck))
+                                                    
.collect(Collectors.toList());
+
+                UntypedResultSet result = null;
+
+                if (mode == Mode.REGULAR)
+                    result = execute("SELECT pk, ck FROM %s WHERE pk = ? AND 
v1 > ? AND v2 > ?", pk, v1, v2);
+                else if (mode == Mode.STATIC)
+                    result = execute("SELECT pk, ck FROM %s WHERE pk = ? AND 
s1 > ? AND s2 > ?", pk, v1, v2);
+                else if (mode == Mode.REGULAR_STATIC)
+                    result = execute("SELECT pk, ck FROM %s WHERE pk = ? AND 
v1 > ? AND s2 > ?", pk, v1, v2);
+                else if (mode == Mode.TWO_REGULAR_ONE_STATIC)
+                    result = execute("SELECT pk, ck FROM %s WHERE pk = ? AND 
v1 > ? AND v2 > ? AND s2 > ?", pk, v1, v2, v2);
+
+                assertRows(result, expected.toArray(EMPTY_ROWS));
+            }
+        });
+    }
+
+    protected void runUnrestrictedQueries() throws Throwable
+    {
+        Map<Integer, List<TestRow>> testRowMap = buildAndLoadTestRows();
+
+        beforeAndAfterFlush(() -> {
+            for (int queryCount = 0; queryCount < nextInt(10, 100); 
queryCount++)
+            {
+                int v1 = nextV1();
+                int v2 = nextV2();
+
+                Predicate<TestRow> predicate = null;
+                
+                if (mode == Mode.REGULAR)
+                    predicate = row -> row.v1 == v1 && row.v2 > v2;
+                else if (mode == Mode.STATIC)
+                    predicate = row -> row.s1 > v1 && row.s2 > v2;
+                else if (mode == Mode.REGULAR_STATIC)
+                    predicate = row -> row.v1 == v1 && row.s2 > v2;
+                else if (mode == Mode.TWO_REGULAR_ONE_STATIC)
+                    predicate = row -> row.v1 == v1 && row.v2 > v2 && row.s2 > 
v2;
+                
+                assert predicate != null : "Predicate should be assigned!";
+                
+                List<Object[]> expected = testRowMap.values()
+                                                    .stream()
+                                                    
.flatMap(Collection::stream)
+                                                    .filter(predicate)
+                                                    .map(row -> row(row.pk, 
row.ck))
+                                                    
.collect(Collectors.toList());
+
+                UntypedResultSet result = null;
+                
+                if (mode == Mode.REGULAR)
+                    result = execute("SELECT pk, ck FROM %s WHERE v1 = ? AND 
v2 > ?", v1, v2);
+                else if (mode == Mode.STATIC)
+                    result = execute("SELECT pk, ck FROM %s WHERE s1 > ? AND 
s2 > ?", v1, v2);
+                else if (mode == Mode.REGULAR_STATIC)
+                    result = execute("SELECT pk, ck FROM %s WHERE v1 = ? AND 
s2 > ?", v1, v2);
+                else if (mode == Mode.TWO_REGULAR_ONE_STATIC)
+                    result = execute("SELECT pk, ck FROM %s WHERE v1 = ? AND 
v2 > ? AND s2 > ?", v1, v2, v2);
+
+                assertRowsIgnoringOrder(result, expected.toArray(EMPTY_ROWS));
+            }
+        });
+    }
+
+    private Map<Integer, List<TestRow>> buildAndLoadTestRows()
+    {
+        Map<Integer, List<TestRow>> testRowMap = new HashMap<>();
+
+        int clusterSize = nextPartitionSize();
+        int partition = nextInt(0, numPartitions);
+        int s1 = nextV1();
+        int s2 = nextV2();
+        List<TestRow> rowList = new ArrayList<>(clusterSize);
+        testRowMap.put(partition, rowList);
+        int clusterCount = 0;
+
+        for (int index = 0; index < numPartitions; index++)
+        {
+            TestRow row = new TestRow(partition, nextInt(10, numPartitions), 
nextV1(), nextV2(), s1, s2);
+            while (rowList.contains(row))
+                row = new TestRow(partition, nextInt(10, numPartitions), 
nextV1(), nextV2(), s1, s2);
+
+            rowList.add(row);
+            clusterCount++;
+
+            if (clusterCount == clusterSize)
+            {
+                clusterCount = 0;
+                clusterSize = nextPartitionSize();
+                partition = nextInt(0, numPartitions);
+                while (testRowMap.containsKey(partition))
+                    partition = nextInt(0, numPartitions);
+                rowList = new ArrayList<>(clusterSize);
+                testRowMap.put(partition, rowList);
+            }
+        }
+       
+        testRowMap.values().stream().flatMap(Collection::stream).forEach(row 
-> {
+            execute("INSERT INTO %s (pk, ck, v1, v2) VALUES (?, ?, ?, ?)", 
row.pk, row.ck, row.v1, row.v2);
+            execute("INSERT INTO %s (pk, s1, s2) VALUES (?, ?, ?)", row.pk, 
row.s1, row.s2);
+        });
+
+        return testRowMap;
+    }
+
+    private int nextPartitionSize()
+    {
+        return largePartition ? nextInt(1024, 4096) : nextInt(1, 64);
+    }
+
+    private int nextV1()
+    {
+        return v1Cardinality ? nextInt(10, numPartitions / 10) : nextInt(10, 
numPartitions / 1000);
+    }
+
+    private int nextV2()
+    {
+        return v2Cardinality ? nextInt(10, numPartitions / 10) : nextInt(10, 
numPartitions / 1000);
+    }
+
+    private static class TestRow implements Comparable<TestRow>
+    {
+        final int pk;
+        final int ck;
+        final int v1;
+        final int v2;
+        final int s1;
+        final int s2;
+
+        TestRow(int pk, int ck, int v1, int v2, int s1, int s2)
+        {
+            this.pk = pk;
+            this.ck = ck;
+            this.v1 = v1;
+            this.v2 = v2;
+            this.s1 = s1;
+            this.s2 = s2;
+        }
+
+        @Override
+        public int compareTo(TestRow other)
+        {
+            int cmp = Integer.compare(pk, other.pk);
+            if (cmp != 0)
+                return cmp;
+            return Integer.compare(ck, other.ck);
+        }
+
+        @Override
+        public boolean equals(Object obj)
+        {
+            if (obj instanceof TestRow)
+                return compareTo((TestRow) obj) == 0;
+
+            return false;
+        }
+
+        @Override
+        public int hashCode()
+        {
+            return Objects.hash(pk, ck);
+        }
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomMixedIntersectionTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomMixedIntersectionTest.java
new file mode 100644
index 0000000000..4260ab96a8
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomMixedIntersectionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static 
org.apache.cassandra.index.sai.cql.intersection.RandomIntersectionTester.Mode.REGULAR_STATIC;
+
+@RunWith(Parameterized.class)
+public class RandomMixedIntersectionTest extends RandomIntersectionTester
+{
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters()
+    {
+        List<Object[]> parameters = new LinkedList<>();
+
+        parameters.add(new Object[] { "Large partition unrestricted, high, 
high", false, true, true, true, REGULAR_STATIC});
+        parameters.add(new Object[] { "Large partition unrestricted, low, 
low", false, true, false, false, REGULAR_STATIC});
+        parameters.add(new Object[] { "Large partition unrestricted, high, 
low", false, true, true, false, REGULAR_STATIC});
+        parameters.add(new Object[] { "Small partition unrestricted, high, 
high", false, false, true, true, REGULAR_STATIC});
+        parameters.add(new Object[] { "Small partition unrestricted, low, 
low", false, false, false, false, REGULAR_STATIC});
+        parameters.add(new Object[] { "Small partition unrestricted, high, 
low", false, false, true, false, REGULAR_STATIC});
+
+        return parameters;
+    }
+
+    @Test
+    public void testMixedIntersection() throws Throwable
+    {
+        runUnrestrictedQueries();
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomMixedPartitionIntersectionTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomMixedPartitionIntersectionTest.java
new file mode 100644
index 0000000000..dc12e927fa
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomMixedPartitionIntersectionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static 
org.apache.cassandra.index.sai.cql.intersection.RandomIntersectionTester.Mode.REGULAR_STATIC;
+
+@RunWith(Parameterized.class)
+public class RandomMixedPartitionIntersectionTest extends 
RandomIntersectionTester
+{
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters()
+    {
+        List<Object[]> parameters = new LinkedList<>();
+
+        parameters.add(new Object[] { "Large partition restricted, high, 
high", true, true, true, true, REGULAR_STATIC});
+        parameters.add(new Object[] { "Large partition restricted, low, low", 
true, true, false, false, REGULAR_STATIC});
+        parameters.add(new Object[] { "Large partition restricted, high, low", 
true, true, true, false, REGULAR_STATIC});
+        parameters.add(new Object[] { "Small partition restricted, high, 
high", true, false, true, true, REGULAR_STATIC});
+        parameters.add(new Object[] { "Small partition restricted, low, low", 
true, false, false, false, REGULAR_STATIC});
+        parameters.add(new Object[] { "Small partition restricted, high, low", 
true, false, true, false, REGULAR_STATIC});
+
+        return parameters;
+    }
+
+    @Test
+    public void testMixedIntersection() throws Throwable
+    {
+        runRestrictedQueries();
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomRegularIntersectionTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomRegularIntersectionTest.java
new file mode 100644
index 0000000000..f05e301103
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomRegularIntersectionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static 
org.apache.cassandra.index.sai.cql.intersection.RandomIntersectionTester.Mode.REGULAR;
+
+@RunWith(Parameterized.class)
+public class RandomRegularIntersectionTest extends RandomIntersectionTester
+{
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters()
+    {
+        List<Object[]> parameters = new LinkedList<>();
+
+        parameters.add(new Object[] { "Large partition unrestricted, high, 
high", false, true, true, true, REGULAR });
+        parameters.add(new Object[] { "Large partition unrestricted, low, 
low", false, true, false, false, REGULAR });
+        parameters.add(new Object[] { "Large partition unrestricted, high, 
low", false, true, true, false, REGULAR });
+        parameters.add(new Object[] { "Small partition unrestricted, high, 
high", false, false, true, true, REGULAR });
+        parameters.add(new Object[] { "Small partition unrestricted, low, 
low", false, false, false, false, REGULAR });
+        parameters.add(new Object[] { "Small partition unrestricted, high, 
low", false, false, true, false, REGULAR });
+
+        return parameters;
+    }
+
+    @Test
+    public void testRegularIntersection() throws Throwable
+    {
+        runUnrestrictedQueries();
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomRegularPartitionIntersectionTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomRegularPartitionIntersectionTest.java
new file mode 100644
index 0000000000..b14fefe743
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomRegularPartitionIntersectionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static 
org.apache.cassandra.index.sai.cql.intersection.RandomIntersectionTester.Mode.REGULAR;
+
+@RunWith(Parameterized.class)
+public class RandomRegularPartitionIntersectionTest extends 
RandomIntersectionTester
+{
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters()
+    {
+        List<Object[]> parameters = new LinkedList<>();
+
+        parameters.add(new Object[] { "Large partition restricted, high, 
high", true, true, true, true, REGULAR });
+        parameters.add(new Object[] { "Large partition restricted, low, low", 
true, true, false, false, REGULAR });
+        parameters.add(new Object[] { "Large partition restricted, high, low", 
true, true, true, false, REGULAR });
+        parameters.add(new Object[] { "Small partition restricted, high, 
high", true, false, true, true, REGULAR });
+        parameters.add(new Object[] { "Small partition restricted, low, low", 
true, false, false, false, REGULAR });
+        parameters.add(new Object[] { "Small partition restricted, high, low", 
true, false, true, false, REGULAR });
+
+        return parameters;
+    }
+
+    @Test
+    public void testRegularIntersection() throws Throwable
+    {
+        runRestrictedQueries();
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomStaticIntersectionTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomStaticIntersectionTest.java
new file mode 100644
index 0000000000..a1c31eaddc
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomStaticIntersectionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static 
org.apache.cassandra.index.sai.cql.intersection.RandomIntersectionTester.Mode.STATIC;
+
+@RunWith(Parameterized.class)
+public class RandomStaticIntersectionTest extends RandomIntersectionTester
+{
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters()
+    {
+        List<Object[]> parameters = new LinkedList<>();
+
+        parameters.add(new Object[] { "Large partition unrestricted, high, 
high", false, true, true, true, STATIC });
+        parameters.add(new Object[] { "Large partition unrestricted, low, 
low", false, true, false, false, STATIC });
+        parameters.add(new Object[] { "Large partition unrestricted, high, 
low", false, true, true, false, STATIC });
+        parameters.add(new Object[] { "Small partition unrestricted, high, 
high", false, false, true, true, STATIC });
+        parameters.add(new Object[] { "Small partition unrestricted, low, 
low", false, false, false, false, STATIC });
+        parameters.add(new Object[] { "Small partition unrestricted, high, 
low", false, false, true, false, STATIC });
+
+        return parameters;
+    }
+
+    @Test
+    public void testStaticIntersection() throws Throwable
+    {
+        runUnrestrictedQueries();
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomStaticPartitionIntersectionTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomStaticPartitionIntersectionTest.java
new file mode 100644
index 0000000000..b5e458ecfb
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/RandomStaticPartitionIntersectionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static 
org.apache.cassandra.index.sai.cql.intersection.RandomIntersectionTester.Mode.STATIC;
+
+@RunWith(Parameterized.class)
+public class RandomStaticPartitionIntersectionTest extends 
RandomIntersectionTester
+{
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters()
+    {
+        List<Object[]> parameters = new LinkedList<>();
+
+        parameters.add(new Object[] { "Large partition restricted, high, 
high", true, true, true, true, STATIC });
+        parameters.add(new Object[] { "Large partition restricted, low, low", 
true, true, false, false, STATIC });
+        parameters.add(new Object[] { "Large partition restricted, high, low", 
true, true, true, false, STATIC });
+        parameters.add(new Object[] { "Small partition restricted, high, 
high", true, false, true, true, STATIC });
+        parameters.add(new Object[] { "Small partition restricted, low, low", 
true, false, false, false, STATIC });
+        parameters.add(new Object[] { "Small partition restricted, high, low", 
true, false, true, false, STATIC });
+
+        return parameters;
+    }
+
+    @Test
+    public void testStaticIntersection() throws Throwable
+    {
+        runRestrictedQueries();
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/TwoRegularOneStaticIntersectionTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/TwoRegularOneStaticIntersectionTest.java
new file mode 100644
index 0000000000..ddf4551e5e
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/TwoRegularOneStaticIntersectionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static 
org.apache.cassandra.index.sai.cql.intersection.RandomIntersectionTester.Mode.TWO_REGULAR_ONE_STATIC;
+
+@RunWith(Parameterized.class)
+public class TwoRegularOneStaticIntersectionTest extends 
RandomIntersectionTester
+{
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters()
+    {
+        List<Object[]> parameters = new LinkedList<>();
+
+        parameters.add(new Object[] { "Large partition unrestricted, high, 
high", false, true, true, true, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Large partition unrestricted, low, 
low", false, true, false, false, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Large partition unrestricted, high, 
low", false, true, true, false, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Small partition unrestricted, high, 
high", false, false, true, true, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Small partition unrestricted, low, 
low", false, false, false, false, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Small partition unrestricted, high, 
low", false, false, true, false, TWO_REGULAR_ONE_STATIC});
+
+        return parameters;
+    }
+
+    @Test
+    public void testMixedIntersection() throws Throwable
+    {
+        runUnrestrictedQueries();
+    }
+}
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/intersection/TwoRegularOneStaticPartitionIntersectionTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/TwoRegularOneStaticPartitionIntersectionTest.java
new file mode 100644
index 0000000000..2bfc7438a3
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/intersection/TwoRegularOneStaticPartitionIntersectionTest.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.cassandra.index.sai.cql.intersection;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.util.LinkedList;
+import java.util.List;
+
+import static 
org.apache.cassandra.index.sai.cql.intersection.RandomIntersectionTester.Mode.TWO_REGULAR_ONE_STATIC;
+
+@RunWith(Parameterized.class)
+public class TwoRegularOneStaticPartitionIntersectionTest extends 
RandomIntersectionTester
+{
+    @Parameterized.Parameters(name = "{0}")
+    public static List<Object[]> parameters()
+    {
+        List<Object[]> parameters = new LinkedList<>();
+
+        parameters.add(new Object[] { "Large partition restricted, high, 
high", true, true, true, true, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Large partition restricted, low, low", 
true, true, false, false, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Large partition restricted, high, low", 
true, true, true, false, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Small partition restricted, high, 
high", true, false, true, true, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Small partition restricted, low, low", 
true, false, false, false, TWO_REGULAR_ONE_STATIC});
+        parameters.add(new Object[] { "Small partition restricted, high, low", 
true, false, true, false, TWO_REGULAR_ONE_STATIC});
+
+        return parameters;
+    }
+
+    @Test
+    public void testMixedIntersection() throws Throwable
+    {
+        runRestrictedQueries();
+    }
+}
diff --git a/test/unit/org/apache/cassandra/index/sai/utils/PrimaryKeyTest.java 
b/test/unit/org/apache/cassandra/index/sai/utils/PrimaryKeyTest.java
index 1c4b7d40ba..51edc67389 100644
--- a/test/unit/org/apache/cassandra/index/sai/utils/PrimaryKeyTest.java
+++ b/test/unit/org/apache/cassandra/index/sai/utils/PrimaryKeyTest.java
@@ -83,8 +83,7 @@ public class PrimaryKeyTest extends AbstractPrimaryKeyTester
     public void simplePartitonStaticAndSingleClusteringAscTest()
     {
         PrimaryKey.Factory factory = new 
PrimaryKey.Factory(Murmur3Partitioner.instance, 
simplePartitionStaticAndSingleClusteringAsc.comparator);
-//        int rows = nextInt(10, 100);
-        int rows = 10;
+        int rows = nextInt(10, 100);
         PrimaryKey[] keys = new PrimaryKey[rows];
         int partition = 0;
         int clustering = 0;


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to