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 2651623af6 Interpret inet, bigint, varint, and decimal as non-reversed 
types for query construction and post-filtering
2651623af6 is described below

commit 2651623af6bb3da5f820d9e09abfbdd0683a1322
Author: Caleb Rackliffe <[email protected]>
AuthorDate: Wed Nov 20 16:13:01 2024 -0600

    Interpret inet, bigint, varint, and decimal as non-reversed types for query 
construction and post-filtering
    
    patch by Caleb Rackliffe; reviewed by David Capwell for CASSANDRA-20100
---
 CHANGES.txt                                        |   1 +
 .../cassandra/index/sai/utils/IndexTermType.java   |  49 +++++--
 .../sai/cql/DescClusteringRangeQueryTest.java      | 145 +++++++++++++++++++++
 3 files changed, 183 insertions(+), 12 deletions(-)

diff --git a/CHANGES.txt b/CHANGES.txt
index a8072f3e38..6fbc22f8fb 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,4 +1,5 @@
 5.0.3
+ * Interpret inet, bigint, varint, and decimal as non-reversed types for query 
construction and post-filtering (CASSANDRA-20100)
  * Fix delayed gossip shutdown messages clobbering startup states that leave 
restarted nodes appearing down (CASSANDRA-20033)
  * Streamline the serialized format for index status gossip messages 
(CASSANDRA-20058)
  * Batch clusterings into single SAI partition post-filtering reads 
(CASSANDRA-19497)
diff --git a/src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java 
b/src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java
index a558d5ee82..51600f9d79 100644
--- a/src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java
+++ b/src/java/org/apache/cassandra/index/sai/utils/IndexTermType.java
@@ -141,20 +141,24 @@ public class IndexTermType
         this.indexTargetType = indexTargetType;
         this.capabilities = calculateCapabilities(columnMetadata, 
partitionColumns, indexTargetType);
         this.indexType = calculateIndexType(columnMetadata.type, capabilities, 
indexTargetType);
-        if (indexType.subTypes().isEmpty())
+
+        AbstractType<?> baseType = indexType.unwrap();
+
+        if (baseType.subTypes().isEmpty())
         {
             this.subTypes = Collections.emptyList();
         }
         else
         {
-            List<IndexTermType> subTypes = new 
ArrayList<>(indexType.subTypes().size());
-            for (AbstractType<?> subType : indexType.subTypes())
+            List<IndexTermType> subTypes = new 
ArrayList<>(baseType.subTypes().size());
+            for (AbstractType<?> subType : baseType.subTypes())
                 subTypes.add(new 
IndexTermType(columnMetadata.withNewType(subType), partitionColumns, 
indexTargetType));
             this.subTypes = Collections.unmodifiableList(subTypes);
         }
+
         if (isVector())
         {
-            VectorType<?> vectorType = (VectorType<?>) indexType;
+            VectorType<?> vectorType = (VectorType<?>) baseType;
             vectorElementType = vectorType.elementType;
             vectorDimension = vectorType.dimension;
         }
@@ -454,12 +458,14 @@ public class IndexTermType
     {
         if (isInetAddress())
             return compareInet(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 (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())
             return FastByteOperations.compareUnsigned(b1, b2);
 
-        return indexType.compare(b1, b2 );
+        return indexType.compare(b1, b2);
     }
 
     /**
@@ -491,10 +497,17 @@ public class IndexTermType
     {
         if (isInetAddress())
             return compareInet(requestedValue.encoded, columnValue.encoded);
-            // Override comparisons for frozen collections and composite types 
(map entries)
+        // bigint, decimal, and varint are not indexed in reversed 
byte-comparable form or treated as reversed types by
+        // Expression, so it is correct to compare with the base/unwrapped type
+        else if (isLong() || isBigDecimal() || isBigInteger())
+            return indexType.unwrap().compare(requestedValue.raw, 
columnValue.raw);
+        // Override comparisons for frozen collections and composite types 
(map entries)
         else if (isComposite() || isFrozen())
             return FastByteOperations.compareUnsigned(requestedValue.raw, 
columnValue.raw);
 
+        // Reversed types are treated as such by Expression here, so we cannot 
blindly compare with the unwrapped type.
+        // In the future, we might consider simplifying things to have SAI 
ignore reversed types altogether, but this
+        // will require a change to the on-disk formats.
         return indexType.compare(requestedValue.raw, columnValue.raw);
     }
 
@@ -628,10 +641,7 @@ public class IndexTermType
             capabilities.add(Capability.COMPOSITE_PARTITION);
 
         AbstractType<?> type = columnMetadata.type;
-
-        if (type.isReversed())
-            capabilities.add(Capability.REVERSED);
-
+        boolean reversed = type.isReversed();
         AbstractType<?> baseType = type.unwrap();
 
         if (baseType.isCollection())
@@ -666,16 +676,31 @@ public class IndexTermType
             capabilities.add(Capability.VECTOR);
 
         if (indexType instanceof InetAddressType)
+        {
             capabilities.add(Capability.INET_ADDRESS);
+            reversed = false;
+        }
 
         if (indexType instanceof IntegerType)
+        {
             capabilities.add(Capability.BIG_INTEGER);
+            reversed = false;
+        }
 
         if (indexType instanceof DecimalType)
+        {
             capabilities.add(Capability.BIG_DECIMAL);
+            reversed = false;
+        }
 
         if (indexType instanceof LongType)
+        {
             capabilities.add(Capability.LONG);
+            reversed = false;
+        }
+
+        if (reversed)
+            capabilities.add(Capability.REVERSED);
 
         return capabilities;
     }
diff --git 
a/test/unit/org/apache/cassandra/index/sai/cql/DescClusteringRangeQueryTest.java
 
b/test/unit/org/apache/cassandra/index/sai/cql/DescClusteringRangeQueryTest.java
new file mode 100644
index 0000000000..7a93947cfd
--- /dev/null
+++ 
b/test/unit/org/apache/cassandra/index/sai/cql/DescClusteringRangeQueryTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.math.BigDecimal;
+import java.math.BigInteger;
+import java.net.InetAddress;
+
+import org.junit.Test;
+
+import com.datastax.driver.core.ResultSet;
+import org.apache.cassandra.index.sai.SAITester;
+
+public class DescClusteringRangeQueryTest extends SAITester
+{
+    @Test
+    public void testReversedIntBetween() throws Throwable
+    {
+        createTable("CREATE TABLE %s(p int, c int, abbreviation ascii, PRIMARY 
KEY (p, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        createIndex("CREATE INDEX clustering_test_index ON %s(c) USING 'sai'");
+        createIndex("CREATE INDEX abbreviation_test_index ON %s(abbreviation) 
USING 'sai'");
+
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 1, 'CA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 2, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 3, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 4, 'TX')");
+
+        beforeAndAfterFlush(() ->
+        {
+            ResultSet rangeRowsNet = executeNet("SELECT * FROM %s WHERE c >= 2 
AND c <= 3 AND abbreviation = 'MA'");
+            assertRowsNet(rangeRowsNet, row (0, 3, "MA"), row (0, 2, "MA"));
+        });
+    }
+
+    @Test
+    public void testReversedLongBetween() throws Throwable
+    {
+        createTable("CREATE TABLE %s(p int, c bigint, abbreviation ascii, 
PRIMARY KEY (p, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        createIndex("CREATE INDEX clustering_test_index ON %s(c) USING 'sai'");
+        createIndex("CREATE INDEX abbreviation_test_index ON %s(abbreviation) 
USING 'sai'");
+
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 1, 'CA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 2, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 3, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 4, 'TX')");
+
+        beforeAndAfterFlush(() ->
+        {
+            ResultSet rangeRowsNet = executeNet("SELECT * FROM %s WHERE c >= 2 
AND c <= 3 AND abbreviation = 'MA'");
+            assertRowsNet(rangeRowsNet, row (0, 3L, "MA"), row (0, 2L, "MA"));
+        });
+    }
+
+    @Test
+    public void testReversedBigIntegerBetween() throws Throwable
+    {
+        createTable("CREATE TABLE %s(p int, c varint, abbreviation ascii, 
PRIMARY KEY (p, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        createIndex("CREATE INDEX clustering_test_index ON %s(c) USING 'sai'");
+        createIndex("CREATE INDEX abbreviation_test_index ON %s(abbreviation) 
USING 'sai'");
+
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 1, 'CA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 2, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 3, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 4, 'TX')");
+
+        beforeAndAfterFlush(() ->
+        {
+            ResultSet rangeRowsNet = executeNet("SELECT * FROM %s WHERE c >= 2 
AND c <= 3 AND abbreviation = 'MA'");
+            assertRowsNet(rangeRowsNet, row (0, new BigInteger("3"), "MA"), 
row (0, new BigInteger("2"), "MA"));
+        });
+    }
+
+    @Test
+    public void testReversedBigDecimalBetween() throws Throwable
+    {
+        createTable("CREATE TABLE %s(p int, c decimal, abbreviation ascii, 
PRIMARY KEY (p, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        createIndex("CREATE INDEX clustering_test_index ON %s(c) USING 'sai'");
+        createIndex("CREATE INDEX abbreviation_test_index ON %s(abbreviation) 
USING 'sai'");
+
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 1.1, 'CA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 2.1, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 2.9, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 4.0, 'TX')");
+
+        beforeAndAfterFlush(() ->
+        {
+            ResultSet rangeRowsNet = executeNet("SELECT * FROM %s WHERE c > 
1.9 AND c < 3.0 AND abbreviation = 'MA'");
+            assertRowsNet(rangeRowsNet, row (0, new BigDecimal("2.9"), "MA"), 
row (0, new BigDecimal("2.1"), "MA"));
+        });
+    }
+
+    @Test
+    public void testReversedInetBetween() throws Throwable
+    {
+        createTable("CREATE TABLE %s(p int, c inet, abbreviation ascii, 
PRIMARY KEY (p, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        createIndex("CREATE INDEX clustering_test_index ON %s(c) USING 'sai'");
+        createIndex("CREATE INDEX abbreviation_test_index ON %s(abbreviation) 
USING 'sai'");
+
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, '127.0.0.1', 
'CA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, '127.0.0.2', 
'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, '127.0.0.3', 
'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, '127.0.0.4', 
'TX')");
+
+        beforeAndAfterFlush(() ->
+        {
+            ResultSet rangeRowsNet = executeNet("SELECT * FROM %s WHERE c >= 
'127.0.0.2' AND c <= '127.0.0.3' AND abbreviation = 'MA'");
+            assertRowsNet(rangeRowsNet, row (0, 
InetAddress.getByName("127.0.0.3"), "MA"), row (0, 
InetAddress.getByName("127.0.0.2"), "MA"));
+        });
+    }
+
+    @Test
+    public void testReversedIntBetweenWithAnalyzer() throws Throwable
+    {
+        createTable("CREATE TABLE %s(p int, c int, abbreviation ascii, PRIMARY 
KEY (p, c)) WITH CLUSTERING ORDER BY (c DESC)");
+        createIndex("CREATE INDEX clustering_test_index ON %s(c) USING 'sai'");
+        createIndex("CREATE INDEX abbreviation_test_index ON %s(abbreviation) 
USING 'sai' WITH OPTIONS = {'case_sensitive': 'false'}");
+
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 1, 'CA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 2, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 3, 'MA')");
+        execute("INSERT INTO %s(p, c, abbreviation) VALUES (0, 4, 'TX')");
+
+        beforeAndAfterFlush(() ->
+        {
+            ResultSet rangeRowsNet = executeNet("SELECT * FROM %s WHERE c >= 2 
AND c <= 3 AND abbreviation = 'MA'");
+            assertRowsNet(rangeRowsNet, row (0, 3, "MA"), row (0, 2, "MA"));
+        });
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to