Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id D3958200C4C for ; Mon, 20 Mar 2017 12:40:51 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id CFA6B160B81; Mon, 20 Mar 2017 11:40:51 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id CC664160B76 for ; Mon, 20 Mar 2017 12:40:50 +0100 (CET) Received: (qmail 51767 invoked by uid 500); 20 Mar 2017 11:40:49 -0000 Mailing-List: contact commits-help@cassandra.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cassandra.apache.org Delivered-To: mailing list commits@cassandra.apache.org Received: (qmail 51392 invoked by uid 99); 20 Mar 2017 11:40:48 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 20 Mar 2017 11:40:48 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id A89D5DFE8F; Mon, 20 Mar 2017 11:40:48 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: blerer@apache.org To: commits@cassandra.apache.org Date: Mon, 20 Mar 2017 11:40:50 -0000 Message-Id: <7eb5f8f5e08848c5b0473cc556799747@git.apache.org> In-Reply-To: <08341a6aeea4492dbf7b89cf689ce2b6@git.apache.org> References: <08341a6aeea4492dbf7b89cf689ce2b6@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [3/6] cassandra git commit: Fix CONTAINS filtering for null collections archived-at: Mon, 20 Mar 2017 11:40:52 -0000 Fix CONTAINS filtering for null collections patch by Mikkel Andersen; reviewed by Benjamin Lerer for CASSANDRA-13246 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/0eebc6e6 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/0eebc6e6 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/0eebc6e6 Branch: refs/heads/trunk Commit: 0eebc6e6b7cd7fc801579e57701608e7bf155ee0 Parents: 1dcb313 Author: Mikkel Andersen Authored: Mon Mar 20 12:15:34 2017 +0100 Committer: Benjamin Lerer Committed: Mon Mar 20 12:22:40 2017 +0100 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../apache/cassandra/db/filter/RowFilter.java | 21 ++++++---- src/java/org/apache/cassandra/db/rows/Row.java | 2 +- .../validation/entities/SecondaryIndexTest.java | 39 ++++++++++++++++++ .../cql3/validation/operations/SelectTest.java | 43 ++++++++++++++++++++ 5 files changed, 96 insertions(+), 10 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/0eebc6e6/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 97d8561..10402f3 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.13 + * Fix CONTAINS filtering for null collections (CASSANDRA-13246) * Applying: Use a unique metric reservoir per test run when using Cassandra-wide metrics residing in MBeans (CASSANDRA-13216) * Propagate row deletions in 2i tables on upgrade (CASSANDRA-13320) * Slice.isEmpty() returns false for some empty slices (CASSANDRA-13305) http://git-wip-us.apache.org/repos/asf/cassandra/blob/0eebc6e6/src/java/org/apache/cassandra/db/filter/RowFilter.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/filter/RowFilter.java b/src/java/org/apache/cassandra/db/filter/RowFilter.java index 11cfb87..5ffe2ab 100644 --- a/src/java/org/apache/cassandra/db/filter/RowFilter.java +++ b/src/java/org/apache/cassandra/db/filter/RowFilter.java @@ -670,17 +670,20 @@ public abstract class RowFilter implements Iterable if (column.isComplex()) { ComplexColumnData complexData = row.getComplexColumnData(column); - for (Cell cell : complexData) + if (complexData != null) { - if (type.kind == CollectionType.Kind.SET) + for (Cell cell : complexData) { - if (type.nameComparator().compare(cell.path().get(0), value) == 0) - return true; - } - else - { - if (type.valueComparator().compare(cell.value(), value) == 0) - return true; + if (type.kind == CollectionType.Kind.SET) + { + if (type.nameComparator().compare(cell.path().get(0), value) == 0) + return true; + } + else + { + if (type.valueComparator().compare(cell.value(), value) == 0) + return true; + } } } return false; http://git-wip-us.apache.org/repos/asf/cassandra/blob/0eebc6e6/src/java/org/apache/cassandra/db/rows/Row.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/db/rows/Row.java b/src/java/org/apache/cassandra/db/rows/Row.java index 74d8664..a61f365 100644 --- a/src/java/org/apache/cassandra/db/rows/Row.java +++ b/src/java/org/apache/cassandra/db/rows/Row.java @@ -129,7 +129,7 @@ public interface Row extends Unfiltered, Collection * The returned object groups all the cells for the column, as well as it's complex deletion (if relevant). * * @param c the complex column for which to return the complex data. - * @return the data for {@code c} or {@code null} is the row has no data for this column. + * @return the data for {@code c} or {@code null} if the row has no data for this column. */ public ComplexColumnData getComplexColumnData(ColumnDefinition c); http://git-wip-us.apache.org/repos/asf/cassandra/blob/0eebc6e6/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java index 0cf13bd..5d43bd2 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/entities/SecondaryIndexTest.java @@ -420,6 +420,45 @@ public class SecondaryIndexTest extends CQLTester assertEmpty(execute("SELECT k, v FROM %s WHERE m CONTAINS 4")); } + @Test + public void testSelectOnMultiIndexOnCollectionsWithNull() throws Throwable + { + createTable(" CREATE TABLE %s ( k int, v int, x text, l list, s set, m map, PRIMARY KEY (k, v))"); + + createIndex("CREATE INDEX ON %s (x)"); + createIndex("CREATE INDEX ON %s (v)"); + createIndex("CREATE INDEX ON %s (s)"); + createIndex("CREATE INDEX ON %s (m)"); + + + execute("INSERT INTO %s (k, v, x, l, s, m) VALUES (0, 0, 'x', [1, 2], {'a'}, {'a' : 1})"); + execute("INSERT INTO %s (k, v, x, l, s, m) VALUES (0, 1, 'x', [3, 4], {'b', 'c'}, {'a' : 1, 'b' : 2})"); + execute("INSERT INTO %s (k, v, x, l, s, m) VALUES (0, 2, 'x', [1], {'a', 'c'}, {'c' : 3})"); + execute("INSERT INTO %s (k, v, x, l, s, m) VALUES (1, 0, 'x', [1, 2, 4], {}, {'b' : 1})"); + execute("INSERT INTO %s (k, v, x, l, s, m) VALUES (1, 1, 'x', [4, 5], {'d'}, {'a' : 1, 'b' : 3})"); + execute("INSERT INTO %s (k, v, x, l, s, m) VALUES (1, 2, 'x', null, null, null)"); + + beforeAndAfterFlush(() -> { + // lists + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND l CONTAINS 1 ALLOW FILTERING"), row(1, 0), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND k = 0 AND l CONTAINS 1 ALLOW FILTERING"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND l CONTAINS 2 ALLOW FILTERING"), row(1, 0), row(0, 0)); + assertEmpty(execute("SELECT k, v FROM %s WHERE x = 'x' AND l CONTAINS 6 ALLOW FILTERING")); + + // sets + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND s CONTAINS 'a' ALLOW FILTERING" ), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND k = 0 AND s CONTAINS 'a' ALLOW FILTERING"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND s CONTAINS 'd' ALLOW FILTERING"), row(1, 1)); + assertEmpty(execute("SELECT k, v FROM %s WHERE x = 'x' AND s CONTAINS 'e' ALLOW FILTERING")); + + // maps + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND m CONTAINS 1 ALLOW FILTERING"), row(1, 0), row(1, 1), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND k = 0 AND m CONTAINS 1 ALLOW FILTERING"), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE x = 'x' AND m CONTAINS 2 ALLOW FILTERING"), row(0, 1)); + assertEmpty(execute("SELECT k, v FROM %s WHERE x = 'x' AND m CONTAINS 4 ALLOW FILTERING")); + }); + } + /** * Migrated from cql_tests.py:TestCQL.map_keys_indexing() */ http://git-wip-us.apache.org/repos/asf/cassandra/blob/0eebc6e6/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java ---------------------------------------------------------------------- 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 a5f153e..f40ae4b 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/SelectTest.java @@ -2923,4 +2923,47 @@ public class SelectTest extends CQLTester }); } } + + @Test + public void testFilteringOnCollectionsWithNull() throws Throwable + { + createTable(" CREATE TABLE %s ( k int, v int, l list, s set, m map, PRIMARY KEY (k, v))"); + + createIndex("CREATE INDEX ON %s (v)"); + createIndex("CREATE INDEX ON %s (s)"); + createIndex("CREATE INDEX ON %s (m)"); + + + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 0, [1, 2], {'a'}, {'a' : 1})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 1, [3, 4], {'b', 'c'}, {'a' : 1, 'b' : 2})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (0, 2, [1], {'a', 'c'}, {'c' : 3})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 0, [1, 2, 4], {}, {'b' : 1})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 1, [4, 5], {'d'}, {'a' : 1, 'b' : 3})"); + execute("INSERT INTO %s (k, v, l, s, m) VALUES (1, 2, null, null, null)"); + + beforeAndAfterFlush(() -> { + // lists + assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 1 ALLOW FILTERING"), row(1, 0), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND l CONTAINS 1 ALLOW FILTERING"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE l CONTAINS 2 ALLOW FILTERING"), row(1, 0), row(0, 0)); + assertEmpty(execute("SELECT k, v FROM %s WHERE l CONTAINS 6 ALLOW FILTERING")); + + // sets + assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'a' ALLOW FILTERING" ), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND s CONTAINS 'a' ALLOW FILTERING"), row(0, 0), row(0, 2)); + assertRows(execute("SELECT k, v FROM %s WHERE s CONTAINS 'd' ALLOW FILTERING"), row(1, 1)); + assertEmpty(execute("SELECT k, v FROM %s WHERE s CONTAINS 'e' ALLOW FILTERING")); + + // maps + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS 1 ALLOW FILTERING"), row(1, 0), row(1, 1), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS 1 ALLOW FILTERING"), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS 2 ALLOW FILTERING"), row(0, 1)); + assertEmpty(execute("SELECT k, v FROM %s WHERE m CONTAINS 4 ALLOW FILTERING")); + + assertRows(execute("SELECT k, v FROM %s WHERE m CONTAINS KEY 'a' ALLOW FILTERING"), row(1, 1), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS KEY 'a' ALLOW FILTERING"), row(0, 0), row(0, 1)); + assertRows(execute("SELECT k, v FROM %s WHERE k = 0 AND m CONTAINS KEY 'c' ALLOW FILTERING"), row(0, 2)); + }); + } + }