Avoid potential NPE for queries with ORDER BY and IN

patch by blerer; reviewed by beobal for CASSANDRA-10955
This commit is contained in:
Benjamin Lerer 2016-01-13 15:41:51 +01:00 committed by Sylvain Lebresne
parent 0b479a7f3e
commit deafdbe373
3 changed files with 59 additions and 7 deletions

View File

@ -1,4 +1,5 @@
2.2.5
* Fix potential NPE on ORDER BY queries with IN (CASSANDRA-10955)
* Avoid over-fetching during the page of range queries (CASSANDRA-8521)
* Start L0 STCS-compactions even if there is a L0 -> L1 compaction
going (CASSANDRA-10979)

View File

@ -1092,10 +1092,21 @@ public class SelectStatement implements CQLStatement
}
}
private static abstract class ColumnComparator<T> implements Comparator<T>
{
protected final int compare(Comparator<ByteBuffer> comparator, ByteBuffer aValue, ByteBuffer bValue)
{
if (aValue == null)
return bValue == null ? 0 : -1;
return bValue == null ? 1 : comparator.compare(aValue, bValue);
}
}
/**
* Used in orderResults(...) method when single 'ORDER BY' condition where given
*/
private static class SingleColumnComparator implements Comparator<List<ByteBuffer>>
private static class SingleColumnComparator extends ColumnComparator<List<ByteBuffer>>
{
private final int index;
private final Comparator<ByteBuffer> comparator;
@ -1108,14 +1119,14 @@ public class SelectStatement implements CQLStatement
public int compare(List<ByteBuffer> a, List<ByteBuffer> b)
{
return comparator.compare(a.get(index), b.get(index));
return compare(comparator, a.get(index), b.get(index));
}
}
/**
* Used in orderResults(...) method when multiple 'ORDER BY' conditions where given
*/
private static class CompositeComparator implements Comparator<List<ByteBuffer>>
private static class CompositeComparator extends ColumnComparator<List<ByteBuffer>>
{
private final List<Comparator<ByteBuffer>> orderTypes;
private final List<Integer> positions;
@ -1133,10 +1144,7 @@ public class SelectStatement implements CQLStatement
Comparator<ByteBuffer> type = orderTypes.get(i);
int columnPos = positions.get(i);
ByteBuffer aValue = a.get(columnPos);
ByteBuffer bValue = b.get(columnPos);
int comparison = type.compare(aValue, bValue);
int comparison = compare(type, a.get(columnPos), b.get(columnPos));
if (comparison != 0)
return comparison;

View File

@ -392,6 +392,49 @@ public class SelectOrderByTest extends CQLTester
row("A"));
}
@Test
public void testOrderByForInClauseWithNullValue() throws Throwable
{
createTable("CREATE TABLE %s (a int, b int, c int, s int static, d int, PRIMARY KEY (a, b, c))");
execute("INSERT INTO %s (a, b, c, d) VALUES (1, 1, 1, 1)");
execute("INSERT INTO %s (a, b, c, d) VALUES (1, 1, 2, 1)");
execute("INSERT INTO %s (a, b, c, d) VALUES (2, 2, 1, 1)");
execute("INSERT INTO %s (a, b, c, d) VALUES (2, 2, 2, 1)");
execute("UPDATE %s SET s = 1 WHERE a = 1");
execute("UPDATE %s SET s = 2 WHERE a = 2");
execute("UPDATE %s SET s = 3 WHERE a = 3");
assertRows(execute("SELECT a, b, c, d, s FROM %s WHERE a IN (1, 2, 3) ORDER BY b DESC"),
row(2, 2, 2, 1, 2),
row(2, 2, 1, 1, 2),
row(1, 1, 2, 1, 1),
row(1, 1, 1, 1, 1),
row(3, null, null, null, 3));
assertRows(execute("SELECT a, b, c, d, s FROM %s WHERE a IN (1, 2, 3) ORDER BY b ASC"),
row(3, null, null, null, 3),
row(1, 1, 1, 1, 1),
row(1, 1, 2, 1, 1),
row(2, 2, 1, 1, 2),
row(2, 2, 2, 1, 2));
assertRows(execute("SELECT a, b, c, d, s FROM %s WHERE a IN (1, 2, 3) ORDER BY b DESC , c DESC"),
row(2, 2, 2, 1, 2),
row(2, 2, 1, 1, 2),
row(1, 1, 2, 1, 1),
row(1, 1, 1, 1, 1),
row(3, null, null, null, 3));
assertRows(execute("SELECT a, b, c, d, s FROM %s WHERE a IN (1, 2, 3) ORDER BY b ASC, c ASC"),
row(3, null, null, null, 3),
row(1, 1, 1, 1, 1),
row(1, 1, 2, 1, 1),
row(2, 2, 1, 1, 2),
row(2, 2, 2, 1, 2));
}
/**
* Test reversed comparators
* migrated from cql_tests.py:TestCQL.reversed_comparator_test()