This is an automated email from the ASF dual-hosted git repository.
dcapwell pushed a commit to branch cassandra-4.0
in repository https://gitbox.apache.org/repos/asf/cassandra.git
The following commit(s) were added to refs/heads/cassandra-4.0 by this push:
new 4fc8bb29fc IndexOutOfBoundsException when accessing partition where
the column was deleted
4fc8bb29fc is described below
commit 4fc8bb29fcda935728d8863a4499fa0e9d924b82
Author: Sunil Ramchandra Pawar <[email protected]>
AuthorDate: Tue Jan 7 08:58:48 2025 -0800
IndexOutOfBoundsException when accessing partition where the column was
deleted
patch by Sunil Ramchandra Pawar; reviewed by Caleb Rackliffe, David Capwell
for CASSANDRA-20108
---
CHANGES.txt | 1 +
.../org/apache/cassandra/db/filter/RowFilter.java | 32 ++++++++++++----------
.../cql3/validation/operations/SelectTest.java | 30 ++++++++++++++++++++
.../cassandra/index/sasi/plan/OperationTest.java | 2 +-
4 files changed, 49 insertions(+), 16 deletions(-)
diff --git a/CHANGES.txt b/CHANGES.txt
index 23dcc154f8..7eb0068d79 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,5 +1,6 @@
4.0.16
* Fix gossip issue with gossip-only and bootstrapping nodes missing
DC/Rack/Host ID endpoint state (CASSANDRA-19983)
+ * IndexOutOfBoundsException when accessing partition where the column was
deleted (CASSANDRA-20108)
4.0.15
diff --git a/src/java/org/apache/cassandra/db/filter/RowFilter.java
b/src/java/org/apache/cassandra/db/filter/RowFilter.java
index 68a1d57fe1..69a57918cf 100644
--- a/src/java/org/apache/cassandra/db/filter/RowFilter.java
+++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java
@@ -175,7 +175,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
for (Expression e : expressions)
{
- if (!e.isSatisfiedBy(metadata, partitionKey, purged))
+ if (!e.isSatisfiedBy(metadata, partitionKey, purged, nowInSec))
return false;
}
return true;
@@ -301,7 +301,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
// Short-circuit all partitions that won't match based on
static and partition keys
for (Expression e : partitionLevelExpressions)
- if (!e.isSatisfiedBy(metadata,
partition.partitionKey(), partition.staticRow()))
+ if (!e.isSatisfiedBy(metadata,
partition.partitionKey(), partition.staticRow(), nowInSec))
{
partition.close();
return null;
@@ -327,7 +327,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
return null;
for (Expression e : rowLevelExpressions)
- if (!e.isSatisfiedBy(metadata, pk, purged))
+ if (!e.isSatisfiedBy(metadata, pk, purged, nowInSec))
return null;
return row;
@@ -437,9 +437,9 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
* (i.e. it should come from a RowIterator).
* @return whether the row is satisfied by this expression.
*/
- public abstract boolean isSatisfiedBy(TableMetadata metadata,
DecoratedKey partitionKey, Row row);
+ public abstract boolean isSatisfiedBy(TableMetadata metadata,
DecoratedKey partitionKey, Row row, int nowInSec);
- protected ByteBuffer getValue(TableMetadata metadata, DecoratedKey
partitionKey, Row row)
+ protected ByteBuffer getValue(TableMetadata metadata, DecoratedKey
partitionKey, Row row, int nowInSec)
{
switch (column.kind)
{
@@ -451,7 +451,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
return row.clustering().bufferAt(column.position());
default:
Cell<?> cell = row.getCell(column);
- return cell == null ? null : cell.buffer();
+ return cell == null || cell.isTombstone() ||
!cell.isLive(nowInSec) ? null : cell.buffer();
}
}
@@ -594,7 +594,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
super(column, operator, value);
}
- public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey
partitionKey, Row row)
+ public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey
partitionKey, Row row, int nowInSec)
{
// We support null conditions for LWT (in ColumnCondition) but not
for RowFilter.
// TODO: we should try to merge both code someday.
@@ -614,7 +614,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
// representation. See CASSANDRA-11629
if (column.type.isCounter())
{
- ByteBuffer foundValue = getValue(metadata,
partitionKey, row);
+ ByteBuffer foundValue = getValue(metadata,
partitionKey, row, nowInSec);
if (foundValue == null)
return false;
@@ -624,7 +624,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
else
{
// Note that CQL expression are always of the form
'x < 4', i.e. the tested value is on the left.
- ByteBuffer foundValue = getValue(metadata,
partitionKey, row);
+ ByteBuffer foundValue = getValue(metadata,
partitionKey, row, nowInSec);
return foundValue != null &&
operator.isSatisfiedBy(column.type, foundValue, value);
}
}
@@ -635,7 +635,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
case LIKE_MATCHES:
{
assert !column.isComplex() : "Only CONTAINS and
CONTAINS_KEY are supported for 'complex' types";
- ByteBuffer foundValue = getValue(metadata,
partitionKey, row);
+ ByteBuffer foundValue = getValue(metadata,
partitionKey, row, nowInSec);
// Note that CQL expression are always of the form 'x
< 4', i.e. the tested value is on the left.
return foundValue != null &&
operator.isSatisfiedBy(column.type, foundValue, value);
}
@@ -665,7 +665,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
}
else
{
- ByteBuffer foundValue = getValue(metadata,
partitionKey, row);
+ ByteBuffer foundValue = getValue(metadata,
partitionKey, row, nowInSec);
if (foundValue == null)
return false;
@@ -692,7 +692,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
}
else
{
- ByteBuffer foundValue = getValue(metadata,
partitionKey, row);
+ ByteBuffer foundValue = getValue(metadata,
partitionKey, row, nowInSec);
return foundValue != null &&
mapType.getSerializer().getSerializedValue(foundValue, value,
mapType.getKeysType()) != null;
}
@@ -765,7 +765,8 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
return CompositeType.build(ByteBufferAccessor.instance, key,
value);
}
- public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey
partitionKey, Row row)
+ @Override
+ public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey
partitionKey, Row row, int nowInSec)
{
assert key != null;
// We support null conditions for LWT (in ColumnCondition) but not
for RowFilter.
@@ -783,7 +784,7 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
}
else
{
- ByteBuffer serializedMap = getValue(metadata, partitionKey,
row);
+ ByteBuffer serializedMap = getValue(metadata, partitionKey,
row, nowInSec);
if (serializedMap == null)
return false;
@@ -879,7 +880,8 @@ public abstract class RowFilter implements
Iterable<RowFilter.Expression>
}
// Filtering by custom expressions isn't supported yet, so just accept
any row
- public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey
partitionKey, Row row)
+ @Override
+ public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey
partitionKey, Row row, int nowInSec)
{
return true;
}
diff --git
a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
index d0493cf8fc..0a7b507df1 100644
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java
@@ -2301,6 +2301,36 @@ public class SelectTest extends CQLTester
});
}
+ @Test
+ public void filteringOnDeletedStaticColumnValue() throws Throwable
+ {
+ // Create table with int-only columns
+ createTable("CREATE TABLE %s (pk0 int, pk1 int, ck0 int, ck1 int, s0
tinyint static, v0 int, v1 int, PRIMARY KEY ((pk0, pk1), ck0, ck1))");
+
+ // Insert rows
+ execute("INSERT INTO %s (pk0, pk1, s0, ck0, ck1, v0, v1) VALUES (?, ?,
?, ?, ?, ?, ?)", 1000, 2000, (byte) 126, 100, 1, 20, 30);
+ execute("INSERT INTO %s (pk0, pk1, s0, ck0, ck1, v0, v1) VALUES (?, ?,
?, ?, ?, ?, ?)", 1000, 2000, (byte) 125, 200, 2, 40, 50);
+ execute("INSERT INTO %s (pk0, pk1, s0, ck0, ck1, v0, v1) VALUES (?, ?,
?, ?, ?, ?, ?)", 1000, 3000, (byte) 122, 300, 3, 60, 70);
+ execute("DELETE s0,v0,v1 FROM %s WHERE pk0=1000 AND pk1=2000 and
ck0=100 and ck1=1");
+
+ beforeAndAfterFlush(() -> {
+ // Verify the columns are deleted
+ assertRows(execute("SELECT pk0, pk1, s0, ck0, ck1, v0, v1 FROM %s
WHERE s0=? ALLOW FILTERING", (byte) 122),
+ row(1000, 3000, (byte) 122, 300, 3, 60, 70));
+ });
+
+ execute("DELETE v0 FROM %s WHERE pk0=1000 AND pk1=3000 AND ck0=300 AND
ck1=3");
+
+ beforeAndAfterFlush(() -> {
+ assertRows(execute("SELECT pk0, pk1, s0, ck0, ck1, v0, v1 FROM %s
WHERE s0=? ALLOW FILTERING", (byte) 122),
+ row(1000, 3000, (byte) 122, 300, 3, null, 70));
+
+ assertRows(execute("SELECT pk0, pk1, s0, ck0, ck1, v0, v1 FROM %s
WHERE pk0=1000 AND pk1=3000 AND ck0=300 AND ck1=3"),
+ row(1000, 3000, (byte) 122, 300, 3, null, 70));
+ });
+
+ }
+
@Test
public void containsFilteringOnNonClusteringColumn() throws Throwable {
createTable("CREATE TABLE %s (a int, b int, c int, d list<int>,
PRIMARY KEY (a, b, c))");
diff --git a/test/unit/org/apache/cassandra/index/sasi/plan/OperationTest.java
b/test/unit/org/apache/cassandra/index/sasi/plan/OperationTest.java
index 4468f2c219..e80e68fb76 100644
--- a/test/unit/org/apache/cassandra/index/sasi/plan/OperationTest.java
+++ b/test/unit/org/apache/cassandra/index/sasi/plan/OperationTest.java
@@ -647,7 +647,7 @@ public class OperationTest extends SchemaLoader
}
@Override
- public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey
partitionKey, Row row)
+ public boolean isSatisfiedBy(TableMetadata metadata, DecoratedKey
partitionKey, Row row, int nowInSec)
{
throw new UnsupportedOperationException();
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]