Repository: cassandra Updated Branches: refs/heads/cassandra-3.0 dab0e31ba -> fb606dd41
Fix UPDATE queries with empty IN restrictions patch by Benjamin Lerer; reviewed by Alex Petrov for CASSANDRA-13152 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/fb606dd4 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/fb606dd4 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/fb606dd4 Branch: refs/heads/cassandra-3.0 Commit: fb606dd41c9f14324749efc1344421237c36a6db Parents: dab0e31 Author: Benjamin Lerer <[email protected]> Authored: Tue Feb 7 10:35:48 2017 +0100 Committer: Benjamin Lerer <[email protected]> Committed: Tue Feb 7 10:35:48 2017 +0100 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../cql3/statements/ModificationStatement.java | 4 ++ .../cql3/validation/operations/DeleteTest.java | 54 ++++++++++++++++++++ .../cql3/validation/operations/UpdateTest.java | 53 ++++++++++++++++++- 4 files changed, 111 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/fb606dd4/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 1a90b1f..4387019 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.0.11 + * Fix UPDATE queries with empty IN restrictions (CASSANDRA-13152) * Abort or retry on failed hints delivery (CASSANDRA-13124) * Fix handling of partition with partition-level deletion plus live rows in sstabledump (CASSANDRA-13177) http://git-wip-us.apache.org/repos/asf/cassandra/blob/fb606dd4/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java index acfa16b..1722f02 100644 --- a/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java +++ b/src/java/org/apache/cassandra/cql3/statements/ModificationStatement.java @@ -657,6 +657,10 @@ public abstract class ModificationStatement implements CQLStatement { NavigableSet<Clustering> clusterings = createClustering(options); + // If some of the restrictions were unspecified (e.g. empty IN restrictions) we do not need to do anything. + if (restrictions.hasClusteringColumnsRestriction() && clusterings.isEmpty()) + return; + UpdateParameters params = makeUpdateParameters(keys, clusterings, options, local, now); for (ByteBuffer key : keys) http://git-wip-us.apache.org/repos/asf/cassandra/blob/fb606dd4/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java index 18a6ca3..09098ac 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/DeleteTest.java @@ -28,11 +28,14 @@ import org.apache.commons.lang3.StringUtils; import org.junit.Test; import org.apache.cassandra.cql3.CQLTester; +import org.apache.cassandra.db.ColumnFamilyStore; +import org.apache.cassandra.db.Keyspace; import static org.apache.cassandra.utils.ByteBufferUtil.EMPTY_BYTE_BUFFER; import static org.apache.cassandra.utils.ByteBufferUtil.bytes; import static org.apache.commons.lang3.StringUtils.isEmpty; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; public class DeleteTest extends CQLTester { @@ -1247,4 +1250,55 @@ public class DeleteTest extends CQLTester row(1, 1, 1, 3, 3), row(1, 1, 1, 4, 4)); } + + /** + * Test for CASSANDRA-13152 + */ + @Test + public void testThatDeletesWithEmptyInRestrictionDoNotCreateMutations() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a,b))"); + + execute("DELETE FROM %s WHERE a IN ();"); + execute("DELETE FROM %s WHERE a IN () AND b IN ();"); + execute("DELETE FROM %s WHERE a IN () AND b = 1;"); + execute("DELETE FROM %s WHERE a = 1 AND b IN ();"); + + assertTrue("The memtable should be empty but is not", isMemtableEmpty()); + + createTable("CREATE TABLE %s (a int, b int, c int, d int, s int static, PRIMARY KEY ((a,b), c))"); + + execute("DELETE FROM %s WHERE a = 1 AND b = 1 AND c IN ();"); + execute("DELETE FROM %s WHERE a = 1 AND b IN () AND c IN ();"); + execute("DELETE FROM %s WHERE a IN () AND b IN () AND c IN ();"); + execute("DELETE FROM %s WHERE a IN () AND b = 1 AND c IN ();"); + execute("DELETE FROM %s WHERE a IN () AND b IN () AND c = 1;"); + + assertTrue("The memtable should be empty but is not", isMemtableEmpty()); + + createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY ((a,b), c, d))"); + + execute("DELETE FROM %s WHERE a = 1 AND b = 1 AND c IN ();"); + execute("DELETE FROM %s WHERE a = 1 AND b = 1 AND c = 1 AND d IN ();"); + execute("DELETE FROM %s WHERE a = 1 AND b = 1 AND c IN () AND d IN ();"); + execute("DELETE FROM %s WHERE a = 1 AND b IN () AND c IN () AND d IN ();"); + execute("DELETE FROM %s WHERE a IN () AND b IN () AND c IN () AND d IN ();"); + execute("DELETE FROM %s WHERE a IN () AND b IN () AND c IN () AND d = 1;"); + execute("DELETE FROM %s WHERE a IN () AND b IN () AND c = 1 AND d = 1;"); + execute("DELETE FROM %s WHERE a IN () AND b IN () AND c = 1 AND d IN ();"); + execute("DELETE FROM %s WHERE a IN () AND b = 1"); + + assertTrue("The memtable should be empty but is not", isMemtableEmpty()); + } + + /** + * Checks if the memtable is empty or not + * @return {@code true} if the memtable is empty, {@code false} otherwise. + */ + private boolean isMemtableEmpty() + { + Keyspace keyspace = Keyspace.open(KEYSPACE); + ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(currentTable()); + return cfs.metric.allMemtablesLiveDataSize.getValue() == 0; + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/fb606dd4/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java index 0d81fa3..a49f828 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java @@ -20,11 +20,15 @@ package org.apache.cassandra.cql3.validation.operations; import java.util.Arrays; +import org.junit.Assert; import org.junit.Test; import static org.apache.commons.lang3.StringUtils.isEmpty; +import static org.junit.Assert.assertTrue; + import org.apache.cassandra.cql3.CQLTester; -import org.apache.cassandra.utils.ByteBufferUtil; +import org.apache.cassandra.db.ColumnFamilyStore; +import org.apache.cassandra.db.Keyspace; public class UpdateTest extends CQLTester { @@ -557,4 +561,51 @@ public class UpdateTest extends CQLTester row(1,1,1,3,3), row(1,1,1,4,4)); } + + /** + * Test for CASSANDRA-13152 + */ + @Test + public void testThatUpdatesWithEmptyInRestrictionDoNotCreateMutations() throws Throwable + { + createTable("CREATE TABLE %s (a int, b int, c int, PRIMARY KEY (a,b))"); + + execute("UPDATE %s SET c = 100 WHERE a IN () AND b = 1;"); + execute("UPDATE %s SET c = 100 WHERE a = 1 AND b IN ();"); + + assertTrue("The memtable should be empty but is not", isMemtableEmpty()); + + createTable("CREATE TABLE %s (a int, b int, c int, d int, s int static, PRIMARY KEY ((a,b), c))"); + + execute("UPDATE %s SET d = 100 WHERE a = 1 AND b = 1 AND c IN ();"); + execute("UPDATE %s SET d = 100 WHERE a = 1 AND b IN () AND c IN ();"); + execute("UPDATE %s SET d = 100 WHERE a IN () AND b IN () AND c IN ();"); + execute("UPDATE %s SET d = 100 WHERE a IN () AND b IN () AND c = 1;"); + execute("UPDATE %s SET d = 100 WHERE a IN () AND b = 1 AND c IN ();"); + + assertTrue("The memtable should be empty but is not", isMemtableEmpty()); + + createTable("CREATE TABLE %s (a int, b int, c int, d int, e int, PRIMARY KEY ((a,b), c, d))"); + + execute("UPDATE %s SET e = 100 WHERE a = 1 AND b = 1 AND c = 1 AND d IN ();"); + execute("UPDATE %s SET e = 100 WHERE a = 1 AND b = 1 AND c IN () AND d IN ();"); + execute("UPDATE %s SET e = 100 WHERE a = 1 AND b IN () AND c IN () AND d IN ();"); + execute("UPDATE %s SET e = 100 WHERE a IN () AND b IN () AND c IN () AND d IN ();"); + execute("UPDATE %s SET e = 100 WHERE a IN () AND b IN () AND c IN () AND d = 1;"); + execute("UPDATE %s SET e = 100 WHERE a IN () AND b IN () AND c = 1 AND d = 1;"); + execute("UPDATE %s SET e = 100 WHERE a IN () AND b IN () AND c = 1 AND d IN ();"); + + assertTrue("The memtable should be empty but is not", isMemtableEmpty()); + } + + /** + * Checks if the memtable is empty or not + * @return {@code true} if the memtable is empty, {@code false} otherwise. + */ + private boolean isMemtableEmpty() + { + Keyspace keyspace = Keyspace.open(KEYSPACE); + ColumnFamilyStore cfs = keyspace.getColumnFamilyStore(currentTable()); + return cfs.metric.allMemtablesLiveDataSize.getValue() == 0; + } }
