mirror of https://github.com/apache/cassandra
IndexOutOfBoundsException when accessing partition where the column was deleted
patch by Sunil Ramchandra Pawar; reviewed by Caleb Rackliffe, David Capwell for CASSANDRA-20108
This commit is contained in:
parent
a7eea177d2
commit
4fc8bb29fc
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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))");
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue