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]