This is an automated email from the ASF dual-hosted git repository.

mck pushed a commit to branch cassandra-3.11
in repository https://gitbox.apache.org/repos/asf/cassandra.git

commit 3e24c0349a1f091c20602b899d72a447a17d57b9
Merge: 2473ee3 f8500ee
Author: Mick Semb Wever <[email protected]>
AuthorDate: Thu Jan 7 23:02:49 2021 +0100

    Merge branch 'cassandra-3.0' into cassandra-3.11

 CHANGES.txt                                        |   1 +
 doc/source/cql/appendices.rst                      |   9 +-
 .../cassandra/db/SinglePartitionReadCommand.java   |  37 +++-
 .../upgrade/CompactStorage2to3UpgradeTest.java     |   6 +-
 .../miscellaneous/SSTablesIteratedTest.java        | 236 ++++++++++++++++++++-
 .../cql3/validation/operations/UpdateTest.java     |  14 +-
 6 files changed, 278 insertions(+), 25 deletions(-)

diff --cc CHANGES.txt
index c9602f1,54456c1..35129a2
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,8 -1,6 +1,9 @@@
 -3.0.24:
 - * Fix skipping on pre-3.0 created compact storage sstables due to missing 
primary key liveness (CASSANDRA-16226)
 +3.11.10
   * Fix DecimalDeserializer#toString OOM (CASSANDRA-14925)
 + * Rate limit validation compactions using compaction_throughput_mb_per_sec 
(CASSANDRA-16161)
 + * SASI's `max_compaction_flush_memory_in_mb` settings over 100GB revert to 
default of 1GB (CASSANDRA-16071)
 +Merged from 3.0:
++ * Fix skipping on pre-3.0 created compact storage sstables due to missing 
primary key liveness (CASSANDRA-16226)
   * Extend the exclusion of replica filtering protection to other indices 
instead of just SASI (CASSANDRA-16311)
   * Synchronize transaction logs for JBOD (CASSANDRA-16225)
   * Fix the counting of cells per partition (CASSANDRA-16259)
diff --cc doc/source/cql/appendices.rst
index 480b78e,0000000..456170d
mode 100644,000000..100644
--- a/doc/source/cql/appendices.rst
+++ b/doc/source/cql/appendices.rst
@@@ -1,330 -1,0 +1,333 @@@
 +.. Licensed to the Apache Software Foundation (ASF) under one
 +.. or more contributor license agreements.  See the NOTICE file
 +.. distributed with this work for additional information
 +.. regarding copyright ownership.  The ASF licenses this file
 +.. to you under the Apache License, Version 2.0 (the
 +.. "License"); you may not use this file except in compliance
 +.. with the License.  You may obtain a copy of the License at
 +..
 +..     http://www.apache.org/licenses/LICENSE-2.0
 +..
 +.. Unless required by applicable law or agreed to in writing, software
 +.. distributed under the License is distributed on an "AS IS" BASIS,
 +.. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 +.. See the License for the specific language governing permissions and
 +.. limitations under the License.
 +
 +.. highlight:: cql
 +
 +Appendices
 +----------
 +
 +.. _appendix-A:
 +
 +Appendix A: CQL Keywords
 +~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +CQL distinguishes between *reserved* and *non-reserved* keywords.
 +Reserved keywords cannot be used as identifier, they are truly reserved
 +for the language (but one can enclose a reserved keyword by
 +double-quotes to use it as an identifier). Non-reserved keywords however
 +only have a specific meaning in certain context but can used as
 +identifier otherwise. The only *raison d’être* of these non-reserved
 +keywords is convenience: some keyword are non-reserved when it was
 +always easy for the parser to decide whether they were used as keywords
 +or not.
 +
 ++--------------------+-------------+
 +| Keyword            | Reserved?   |
 ++====================+=============+
 +| ``ADD``            | yes         |
 ++--------------------+-------------+
 +| ``AGGREGATE``      | no          |
 ++--------------------+-------------+
 +| ``ALL``            | no          |
 ++--------------------+-------------+
 +| ``ALLOW``          | yes         |
 ++--------------------+-------------+
 +| ``ALTER``          | yes         |
 ++--------------------+-------------+
 +| ``AND``            | yes         |
 ++--------------------+-------------+
 +| ``APPLY``          | yes         |
 ++--------------------+-------------+
 +| ``AS``             | no          |
 ++--------------------+-------------+
 +| ``ASC``            | yes         |
 ++--------------------+-------------+
 +| ``ASCII``          | no          |
 ++--------------------+-------------+
 +| ``AUTHORIZE``      | yes         |
 ++--------------------+-------------+
 +| ``BATCH``          | yes         |
 ++--------------------+-------------+
 +| ``BEGIN``          | yes         |
 ++--------------------+-------------+
 +| ``BIGINT``         | no          |
 ++--------------------+-------------+
 +| ``BLOB``           | no          |
 ++--------------------+-------------+
 +| ``BOOLEAN``        | no          |
 ++--------------------+-------------+
 +| ``BY``             | yes         |
 ++--------------------+-------------+
 +| ``CALLED``         | no          |
 ++--------------------+-------------+
 +| ``CLUSTERING``     | no          |
 ++--------------------+-------------+
 +| ``COLUMNFAMILY``   | yes         |
 ++--------------------+-------------+
 +| ``COMPACT``        | no          |
 ++--------------------+-------------+
 +| ``CONTAINS``       | no          |
 ++--------------------+-------------+
 +| ``COUNT``          | no          |
 ++--------------------+-------------+
 +| ``COUNTER``        | no          |
 ++--------------------+-------------+
 +| ``CREATE``         | yes         |
 ++--------------------+-------------+
 +| ``CUSTOM``         | no          |
 ++--------------------+-------------+
 +| ``DATE``           | no          |
 ++--------------------+-------------+
 +| ``DECIMAL``        | no          |
 ++--------------------+-------------+
 +| ``DELETE``         | yes         |
 ++--------------------+-------------+
 +| ``DESC``           | yes         |
 ++--------------------+-------------+
 +| ``DESCRIBE``       | yes         |
 ++--------------------+-------------+
 +| ``DISTINCT``       | no          |
 ++--------------------+-------------+
 +| ``DOUBLE``         | no          |
 ++--------------------+-------------+
 +| ``DROP``           | yes         |
 ++--------------------+-------------+
 +| ``ENTRIES``        | yes         |
 ++--------------------+-------------+
 +| ``EXECUTE``        | yes         |
 ++--------------------+-------------+
 +| ``EXISTS``         | no          |
 ++--------------------+-------------+
 +| ``FILTERING``      | no          |
 ++--------------------+-------------+
 +| ``FINALFUNC``      | no          |
 ++--------------------+-------------+
 +| ``FLOAT``          | no          |
 ++--------------------+-------------+
 +| ``FROM``           | yes         |
 ++--------------------+-------------+
 +| ``FROZEN``         | no          |
 ++--------------------+-------------+
 +| ``FULL``           | yes         |
 ++--------------------+-------------+
 +| ``FUNCTION``       | no          |
 ++--------------------+-------------+
 +| ``FUNCTIONS``      | no          |
 ++--------------------+-------------+
 +| ``GRANT``          | yes         |
 ++--------------------+-------------+
 +| ``IF``             | yes         |
 ++--------------------+-------------+
 +| ``IN``             | yes         |
 ++--------------------+-------------+
 +| ``INDEX``          | yes         |
 ++--------------------+-------------+
 +| ``INET``           | no          |
 ++--------------------+-------------+
 +| ``INFINITY``       | yes         |
 ++--------------------+-------------+
 +| ``INITCOND``       | no          |
 ++--------------------+-------------+
 +| ``INPUT``          | no          |
 ++--------------------+-------------+
 +| ``INSERT``         | yes         |
 ++--------------------+-------------+
 +| ``INT``            | no          |
 ++--------------------+-------------+
 +| ``INTO``           | yes         |
 ++--------------------+-------------+
 +| ``JSON``           | no          |
 ++--------------------+-------------+
 +| ``KEY``            | no          |
 ++--------------------+-------------+
 +| ``KEYS``           | no          |
 ++--------------------+-------------+
 +| ``KEYSPACE``       | yes         |
 ++--------------------+-------------+
 +| ``KEYSPACES``      | no          |
 ++--------------------+-------------+
 +| ``LANGUAGE``       | no          |
 ++--------------------+-------------+
 +| ``LIMIT``          | yes         |
 ++--------------------+-------------+
 +| ``LIST``           | no          |
 ++--------------------+-------------+
 +| ``LOGIN``          | no          |
 ++--------------------+-------------+
 +| ``MAP``            | no          |
 ++--------------------+-------------+
 +| ``MODIFY``         | yes         |
 ++--------------------+-------------+
 +| ``NAN``            | yes         |
 ++--------------------+-------------+
 +| ``NOLOGIN``        | no          |
 ++--------------------+-------------+
 +| ``NORECURSIVE``    | yes         |
 ++--------------------+-------------+
 +| ``NOSUPERUSER``    | no          |
 ++--------------------+-------------+
 +| ``NOT``            | yes         |
 ++--------------------+-------------+
 +| ``NULL``           | yes         |
 ++--------------------+-------------+
 +| ``OF``             | yes         |
 ++--------------------+-------------+
 +| ``ON``             | yes         |
 ++--------------------+-------------+
 +| ``OPTIONS``        | no          |
 ++--------------------+-------------+
 +| ``OR``             | yes         |
 ++--------------------+-------------+
 +| ``ORDER``          | yes         |
 ++--------------------+-------------+
 +| ``PASSWORD``       | no          |
 ++--------------------+-------------+
 +| ``PERMISSION``     | no          |
 ++--------------------+-------------+
 +| ``PERMISSIONS``    | no          |
 ++--------------------+-------------+
 +| ``PRIMARY``        | yes         |
 ++--------------------+-------------+
 +| ``RENAME``         | yes         |
 ++--------------------+-------------+
 +| ``REPLACE``        | yes         |
 ++--------------------+-------------+
 +| ``RETURNS``        | no          |
 ++--------------------+-------------+
 +| ``REVOKE``         | yes         |
 ++--------------------+-------------+
 +| ``ROLE``           | no          |
 ++--------------------+-------------+
 +| ``ROLES``          | no          |
 ++--------------------+-------------+
 +| ``SCHEMA``         | yes         |
 ++--------------------+-------------+
 +| ``SELECT``         | yes         |
 ++--------------------+-------------+
 +| ``SET``            | yes         |
 ++--------------------+-------------+
 +| ``SFUNC``          | no          |
 ++--------------------+-------------+
 +| ``SMALLINT``       | no          |
 ++--------------------+-------------+
 +| ``STATIC``         | no          |
 ++--------------------+-------------+
 +| ``STORAGE``        | no          |
 ++--------------------+-------------+
 +| ``STYPE``          | no          |
 ++--------------------+-------------+
 +| ``SUPERUSER``      | no          |
 ++--------------------+-------------+
 +| ``TABLE``          | yes         |
 ++--------------------+-------------+
 +| ``TEXT``           | no          |
 ++--------------------+-------------+
 +| ``TIME``           | no          |
 ++--------------------+-------------+
 +| ``TIMESTAMP``      | no          |
 ++--------------------+-------------+
 +| ``TIMEUUID``       | no          |
 ++--------------------+-------------+
 +| ``TINYINT``        | no          |
 ++--------------------+-------------+
 +| ``TO``             | yes         |
 ++--------------------+-------------+
 +| ``TOKEN``          | yes         |
 ++--------------------+-------------+
 +| ``TRIGGER``        | no          |
 ++--------------------+-------------+
 +| ``TRUNCATE``       | yes         |
 ++--------------------+-------------+
 +| ``TTL``            | no          |
 ++--------------------+-------------+
 +| ``TUPLE``          | no          |
 ++--------------------+-------------+
 +| ``TYPE``           | no          |
 ++--------------------+-------------+
 +| ``UNLOGGED``       | yes         |
 ++--------------------+-------------+
 +| ``UPDATE``         | yes         |
 ++--------------------+-------------+
 +| ``USE``            | yes         |
 ++--------------------+-------------+
 +| ``USER``           | no          |
 ++--------------------+-------------+
 +| ``USERS``          | no          |
 ++--------------------+-------------+
 +| ``USING``          | yes         |
 ++--------------------+-------------+
 +| ``UUID``           | no          |
 ++--------------------+-------------+
 +| ``VALUES``         | no          |
 ++--------------------+-------------+
 +| ``VARCHAR``        | no          |
 ++--------------------+-------------+
 +| ``VARINT``         | no          |
 ++--------------------+-------------+
 +| ``WHERE``          | yes         |
 ++--------------------+-------------+
 +| ``WITH``           | yes         |
 ++--------------------+-------------+
 +| ``WRITETIME``      | no          |
 ++--------------------+-------------+
 +
 +Appendix B: CQL Reserved Types
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
 +The following type names are not currently used by CQL, but are reserved
 +for potential future use. User-defined types may not use reserved type
 +names as their name.
 +
 ++-----------------+
 +| type            |
 ++=================+
 +| ``bitstring``   |
 ++-----------------+
 +| ``byte``        |
 ++-----------------+
 +| ``complex``     |
 ++-----------------+
 +| ``enum``        |
 ++-----------------+
 +| ``interval``    |
 ++-----------------+
 +| ``macaddr``     |
 ++-----------------+
 +
 +
 +Appendix C: Dropping Compact Storage
 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 +
- Starting version 4.0, Thrift and COMPACT STORAGE is no longer supported.
- 
- 'ALTER ... DROP COMPACT STORAGE' statement makes Compact Tables 
CQL-compatible,
++``ALTER ... DROP COMPACT STORAGE`` statement makes Compact Tables 
CQL-compatible,
 +exposing internal structure of Thrift/Compact Tables:
 +
 +- CQL-created Compact Tables that have no clustering columns, will expose an
 +  additional clustering column ``column1`` with ``UTF8Type``.
 +- CQL-created Compact Tables that had no regular columns, will expose a
 +  regular column ``value`` with ``BytesType``.
 +- For CQL-Created Compact Tables, all columns originally defined as
 +  ``regular`` will be come ``static``
 +- CQL-created Compact Tables that have clustering but have no regular
 +  columns will have an empty value column (of ``EmptyType``)
 +- SuperColumn Tables (can only be created through Thrift) will expose
 +  a compact value map with an empty name.
 +- Thrift-created Compact Tables will have types corresponding to their
 +  Thrift definition.
++- If a row was written while a table was still compact but it has no live
++  cells due to later row or cell deletions, it may continue to be simply 
++  left out of query results, as is the normal behavior for compact tables.
++  Rows written after a table is fully CQL-compatible, if they have no live
++  cells but a live primary key, may be present in query results with null 
values.
diff --cc 
test/distributed/org/apache/cassandra/distributed/upgrade/CompactStorage2to3UpgradeTest.java
index c7dbf99,4f5d1bc..127b85a
--- 
a/test/distributed/org/apache/cassandra/distributed/upgrade/CompactStorage2to3UpgradeTest.java
+++ 
b/test/distributed/org/apache/cassandra/distributed/upgrade/CompactStorage2to3UpgradeTest.java
@@@ -195,126 -198,125 +198,125 @@@ public class CompactStorage2to3UpgradeT
          final int additionalParititons = 5;
  
          new TestCase()
 -                .nodes(2)
 -                .upgrade(Versions.Major.v22, Versions.Major.v30)
 -                .setup(cluster -> {
 -                    cluster.schemaChange(String.format(
 -                            "CREATE TABLE %s.%s (key int, c1 int, c2 int, c3 
int, PRIMARY KEY (key, c1, c2)) WITH COMPACT STORAGE",
 -                            KEYSPACE, table));
 -                    ICoordinator coordinator = cluster.coordinator(1);
 -
 -                    for (int i = 1; i <= partitions; i++)
 -                    {
 -                        for (int j = 1; j <= rowsPerPartition; j++)
 -                        {
 -                            coordinator.execute(String.format("INSERT INTO 
%s.%s (key, c1, c2, c3) VALUES (%d, %d, 1, 1)",
 -                                    KEYSPACE, table, i, j), 
ConsistencyLevel.ALL);
 -                            coordinator.execute(String.format("INSERT INTO 
%s.%s (key, c1, c2, c3) VALUES (%d, %d, 2, 2)",
 -                                                              KEYSPACE, 
table, i, j), ConsistencyLevel.ALL);
 -                            coordinator.execute(String.format("INSERT INTO 
%s.%s (key, c1, c2, c3) VALUES (%d, %d, 3, 3)",
 -                                                              KEYSPACE, 
table, i, j), ConsistencyLevel.ALL);
 -                        }
 -                    }
 -
 -                })
 -                .runAfterClusterUpgrade(cluster -> {
 -                    for (int i = 1; i <= cluster.size(); i++)
 -                    {
 -                        NodeToolResult result = 
cluster.get(1).nodetoolResult("upgradesstables");
 -                        assertEquals("upgrade sstables failed for node " + i, 
0, result.getRc());
 -                    }
 -
 -                    // drop compact storage on only one node before 
performing writes
 -                    IMessageFilters.Filter filter = 
cluster.verbs().allVerbs().to(2).drop();
 -                    cluster.schemaChange(String.format("ALTER TABLE %s.%s 
DROP COMPACT STORAGE", KEYSPACE, table), 1);
 -                    filter.off();
 -
 -                    // add new partitions and delete some of the old ones
 -                    ICoordinator coordinator = cluster.coordinator(1);
 -                    for (int i = 0; i < additionalParititons; i++)
 -                    {
 -                        for (int j = 1; j <= rowsPerPartition; j++)
 -                        {
 -                            coordinator.execute(String.format("INSERT INTO 
%s.%s (key, c1, c2, c3) VALUES (%d, %d, 1, 1)",
 -                                    KEYSPACE, table, i, j), 
ConsistencyLevel.ALL);
 -                        }
 -                    }
 -
 -                    coordinator.execute(String.format("DELETE FROM %s.%s 
WHERE key = %d and c1 = %d",
 -                            KEYSPACE, table, 0, 3), ConsistencyLevel.ALL);
 -
 -                    coordinator.execute(String.format("DELETE FROM %s.%s 
WHERE key = %d",
 -                            KEYSPACE, table, 1), ConsistencyLevel.ALL);
 -
 -                    coordinator.execute(String.format("DELETE FROM %s.%s 
WHERE key = %d and c1 = %d and c2 = %d",
 -                            KEYSPACE, table, 7, 2, 2), ConsistencyLevel.ALL);
 -
 -                    coordinator.execute(String.format("DELETE FROM %s.%s 
WHERE key = %d and c1 = %d and c2 = %d",
 -                            KEYSPACE, table, 7, 6, 1), ConsistencyLevel.ALL);
 -
 -                    coordinator.execute(String.format("DELETE FROM %s.%s 
WHERE key = %d and c1 = %d and c2 = %d",
 -                                                      KEYSPACE, table, 4, 1, 
1), ConsistencyLevel.ALL);
 -
 -                    coordinator.execute(String.format("DELETE c3 FROM %s.%s 
WHERE key = %d and c1 = %d and c2 = %d",
 -                            KEYSPACE, table, 8, 1, 3), ConsistencyLevel.ALL);
 -
 -                    coordinator.execute(String.format("DELETE FROM %s.%s 
WHERE key = %d and c1 = %d and c2 > 1",
 -                                                      KEYSPACE, table, 6, 2, 
4), ConsistencyLevel.ALL);
 -
 -                    ResultsRecorder recorder = new ResultsRecorder();
 -                    runQueries(coordinator, recorder, new String[] {
 -                            String.format("SELECT * FROM %s.%s", KEYSPACE, 
table),
 -
 -                            String.format("SELECT * FROM %s.%s WHERE key = %d 
and c1 = %d",
 -                                    KEYSPACE, table, partitions - 3, 
rowsPerPartition - 2),
 -
 -                            String.format("SELECT * FROM %s.%s WHERE key = %d 
and c1 = %d",
 -                                    KEYSPACE, table, partitions - 1, 
rowsPerPartition - 5),
 -
 -
 -                            String.format("SELECT * FROM %s.%s WHERE key = %d 
and c1 > %d",
 -                                    KEYSPACE, table, partitions - 8, 
rowsPerPartition - 3),
 -
 -                            String.format("SELECT * FROM %s.%s WHERE key = 
%d",
 -                                    KEYSPACE, table, 7),
 -
 -                            String.format("SELECT * FROM %s.%s WHERE key = %d 
and c1 = %d",
 -                                    KEYSPACE, table, 7, 2),
 -
 -                            String.format("SELECT * FROM %s.%s WHERE key = %d 
and c1 = %d",
 -                                    KEYSPACE, table, 8, 1),
 -
 -                            String.format("SELECT c1, c2 FROM %s.%s WHERE key 
= %d and c1 = %d",
 -                                    KEYSPACE, table, 8, 1),
 -
 -                            String.format("SELECT c1, c2 FROM %s.%s WHERE key 
= %d and c1 = %d",
 -                                          KEYSPACE, table, 8, 1),
 -
 -                            String.format("SELECT c1, c2 FROM %s.%s WHERE key 
= %d and c1 = %d",
 -                                          KEYSPACE, table, 4, 1),
 -
 -                            String.format("SELECT c1, c2 FROM %s.%s WHERE key 
= %d",
 -                                          KEYSPACE, table, 6),
 -
 -                            String.format("SELECT * FROM %s.%s WHERE key = %d 
and c1 > %d",
 -                                    KEYSPACE, table, 0, 1),
 +        .nodes(2)
 +        .upgrade(Versions.Major.v22, Versions.Major.v3X)
 +        .setup(cluster -> {
 +            cluster.schemaChange(String.format(
 +            "CREATE TABLE %s.%s (key int, c1 int, c2 int, c3 int, PRIMARY KEY 
(key, c1, c2)) WITH COMPACT STORAGE",
 +            KEYSPACE, table));
 +            ICoordinator coordinator = cluster.coordinator(1);
 +
 +            for (int i = 1; i <= partitions; i++)
 +            {
 +                for (int j = 1; j <= rowsPerPartition; j++)
 +                {
 +                    coordinator.execute(String.format("INSERT INTO %s.%s 
(key, c1, c2, c3) VALUES (%d, %d, 1, 1)",
 +                                                      KEYSPACE, table, i, j), 
ConsistencyLevel.ALL);
 +                    coordinator.execute(String.format("INSERT INTO %s.%s 
(key, c1, c2, c3) VALUES (%d, %d, 2, 2)",
 +                                                      KEYSPACE, table, i, j), 
ConsistencyLevel.ALL);
 +                    coordinator.execute(String.format("INSERT INTO %s.%s 
(key, c1, c2, c3) VALUES (%d, %d, 3, 3)",
 +                                                      KEYSPACE, table, i, j), 
ConsistencyLevel.ALL);
 +                }
 +            }
 +
 +        })
 +        .runAfterClusterUpgrade(cluster -> {
 +            for (int i = 1; i <= cluster.size(); i++)
 +            {
 +                NodeToolResult result = 
cluster.get(1).nodetoolResult("upgradesstables");
 +                assertEquals("upgrade sstables failed for node " + i, 0, 
result.getRc());
 +            }
 +
 +            // drop compact storage on only one node before performing writes
 +            IMessageFilters.Filter filter = 
cluster.verbs().allVerbs().to(2).drop();
 +            cluster.schemaChange(String.format("ALTER TABLE %s.%s DROP 
COMPACT STORAGE", KEYSPACE, table), 1);
 +            filter.off();
 +
 +            // add new partitions and delete some of the old ones
 +            ICoordinator coordinator = cluster.coordinator(1);
 +            for (int i = 0; i < additionalParititons; i++)
 +            {
 +                for (int j = 1; j <= rowsPerPartition; j++)
 +                {
 +                    coordinator.execute(String.format("INSERT INTO %s.%s 
(key, c1, c2, c3) VALUES (%d, %d, 1, 1)",
 +                                                      KEYSPACE, table, i, j), 
ConsistencyLevel.ALL);
 +                }
 +            }
 +
 +            coordinator.execute(String.format("DELETE FROM %s.%s WHERE key = 
%d and c1 = %d",
 +                                              KEYSPACE, table, 0, 3), 
ConsistencyLevel.ALL);
 +
 +            coordinator.execute(String.format("DELETE FROM %s.%s WHERE key = 
%d",
 +                                              KEYSPACE, table, 1), 
ConsistencyLevel.ALL);
 +
 +            coordinator.execute(String.format("DELETE FROM %s.%s WHERE key = 
%d and c1 = %d and c2 = %d",
 +                                              KEYSPACE, table, 7, 2, 2), 
ConsistencyLevel.ALL);
 +
 +            coordinator.execute(String.format("DELETE FROM %s.%s WHERE key = 
%d and c1 = %d and c2 = %d",
 +                                              KEYSPACE, table, 7, 6, 1), 
ConsistencyLevel.ALL);
 +
 +            coordinator.execute(String.format("DELETE FROM %s.%s WHERE key = 
%d and c1 = %d and c2 = %d",
 +                                              KEYSPACE, table, 4, 1, 1), 
ConsistencyLevel.ALL);
 +
 +            coordinator.execute(String.format("DELETE c3 FROM %s.%s WHERE key 
= %d and c1 = %d and c2 = %d",
 +                                              KEYSPACE, table, 8, 1, 3), 
ConsistencyLevel.ALL);
 +
 +            coordinator.execute(String.format("DELETE FROM %s.%s WHERE key = 
%d and c1 = %d and c2 > 1",
 +                                              KEYSPACE, table, 6, 2, 4), 
ConsistencyLevel.ALL);
 +
 +            ResultsRecorder recorder = new ResultsRecorder();
 +            runQueries(coordinator, recorder, new String[] {
 +            String.format("SELECT * FROM %s.%s", KEYSPACE, table),
 +
 +            String.format("SELECT * FROM %s.%s WHERE key = %d and c1 = %d",
 +                          KEYSPACE, table, partitions - 3, rowsPerPartition - 
2),
  
 -                            String.format("SELECT * FROM %s.%s WHERE key = 
%d",
 -                                    KEYSPACE, table, partitions - 
(additionalParititons - 2)),
 +            String.format("SELECT * FROM %s.%s WHERE key = %d and c1 = %d",
 +                          KEYSPACE, table, partitions - 1, rowsPerPartition - 
5),
  
 -                            String.format("SELECT * FROM %s.%s WHERE key = %d 
and c1 > %d",
 -                                    KEYSPACE, table, partitions - 
(additionalParititons - 3), 4)
  
 -                    });
 +            String.format("SELECT * FROM %s.%s WHERE key = %d and c1 > %d",
 +                          KEYSPACE, table, partitions - 8, rowsPerPartition - 
3),
  
 -                    // drop compact storage on remaining node and check result
 -                    cluster.schemaChange(String.format("ALTER TABLE %s.%s 
DROP COMPACT STORAGE", KEYSPACE, table), 2);
 -                    recorder.validateResults(cluster, 1);
 -                    recorder.validateResults(cluster, 2);
 -                }).run();
 +            String.format("SELECT * FROM %s.%s WHERE key = %d",
 +                          KEYSPACE, table, 7),
 +
 +            String.format("SELECT * FROM %s.%s WHERE key = %d and c1 = %d",
 +                          KEYSPACE, table, 7, 2),
 +
 +            String.format("SELECT * FROM %s.%s WHERE key = %d and c1 = %d",
 +                          KEYSPACE, table, 8, 1),
 +
 +            String.format("SELECT c1, c2 FROM %s.%s WHERE key = %d and c1 = 
%d",
 +                          KEYSPACE, table, 8, 1),
 +
 +            String.format("SELECT c1, c2 FROM %s.%s WHERE key = %d and c1 = 
%d",
 +                          KEYSPACE, table, 8, 1),
 +
 +            String.format("SELECT c1, c2 FROM %s.%s WHERE key = %d and c1 = 
%d",
 +                          KEYSPACE, table, 4, 1),
 +
 +            String.format("SELECT c1, c2 FROM %s.%s WHERE key = %d",
 +                          KEYSPACE, table, 6),
 +
 +            String.format("SELECT * FROM %s.%s WHERE key = %d and c1 > %d",
 +                          KEYSPACE, table, 0, 1),
 +
 +            String.format("SELECT * FROM %s.%s WHERE key = %d",
 +                          KEYSPACE, table, partitions - (additionalParititons 
- 2)),
 +
 +            String.format("SELECT * FROM %s.%s WHERE key = %d and c1 > %d",
 +                          KEYSPACE, table, partitions - (additionalParititons 
- 3), 4)
 +
 +            });
 +
 +            // drop compact storage on remaining node and check result
 +            cluster.schemaChange(String.format("ALTER TABLE %s.%s DROP 
COMPACT STORAGE", KEYSPACE, table), 2);
 +            recorder.validateResults(cluster, 1);
 +            recorder.validateResults(cluster, 2);
 +        }).run();
      }
  
- 
      private void runQueries(ICoordinator coordinator, ResultsRecorder helper, 
String[] queries)
      {
          for (String query : queries)
diff --cc 
test/unit/org/apache/cassandra/cql3/validation/miscellaneous/SSTablesIteratedTest.java
index d363ecf,599711e..72d2909
--- 
a/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/SSTablesIteratedTest.java
+++ 
b/test/unit/org/apache/cassandra/cql3/validation/miscellaneous/SSTablesIteratedTest.java
@@@ -22,8 -22,6 +22,7 @@@ package org.apache.cassandra.cql3.valid
  
  import org.junit.Test;
  
- import static org.junit.Assert.assertEquals;
 +import org.apache.cassandra.config.DatabaseDescriptor;
  import org.apache.cassandra.cql3.CQLTester;
  import org.apache.cassandra.cql3.UntypedResultSet;
  import org.apache.cassandra.db.ColumnFamilyStore;
@@@ -136,422 -136,231 +137,651 @@@ public class SSTablesIteratedTest exten
      }
  
      @Test
 +    public void testSSTablesOnlyASC() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col ASC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        flush();
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 1, row(1, 10, 
"10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 2, row(1, 10, 
"10"), row(1, 20, "20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 3, row(1, 10, 
"10"), row(1, 20, "20"), row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 3, row(1, 10, "10"), 
row(1, 20, "20"), row(1, 30, "30"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
1, row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
1, row(1, 10, "10"));
 +    }
 +
 +    @Test
 +    public void testMixedMemtableSStablesASC() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col ASC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 0, row(1, 10, 
"10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 1, row(1, 10, 
"10"), row(1, 20, "20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 2, row(1, 10, 
"10"), row(1, 20, "20"), row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 2, row(1, 10, "10"), 
row(1, 20, "20"), row(1, 30, "30"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
1, row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
0, row(1, 10, "10"));
 +    }
 +
 +    @Test
 +    public void testOverlappingSStablesASC() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col ASC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 1, row(1, 10, 
"10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 2, row(1, 10, 
"10"), row(1, 20, "20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 2, row(1, 10, 
"10"), row(1, 20, "20"), row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 2, row(1, 10, "10"), 
row(1, 20, "20"), row(1, 30, "30"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
1, row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
1, row(1, 10, "10"));
 +    }
 +
 +    @Test
 +    public void testSSTablesOnlyDESC() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col DESC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        flush();
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 1, row(1, 30, 
"30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 2, row(1, 30, 
"30"), row(1, 20, "20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 3, row(1, 30, 
"30"), row(1, 20, "20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 3, row(1, 30, "30"), 
row(1, 20, "20"), row(1, 10, "10"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
1, row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
1, row(1, 30, "30"));
 +    }
 +
 +    @Test
 +    public void testMixedMemtableSStablesDESC() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col DESC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 0, row(1, 30, 
"30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 1, row(1, 30, 
"30"), row(1, 20, "20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 2, row(1, 30, 
"30"), row(1, 20, "20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 2, row(1, 30, "30"), 
row(1, 20, "20"), row(1, 10, "10"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
0, row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
0, row(1, 30, "30"));
 +    }
 +
 +    @Test
 +    public void testOverlappingSStablesDESC() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col DESC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 1, row(1, 30, 
"30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 2, row(1, 30, 
"30"), row(1, 20, "20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 2, row(1, 30, 
"30"), row(1, 20, "20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 2, row(1, 30, "30"), 
row(1, 20, "20"), row(1, 10, "10"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
1, row(1, 30, "30"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
1, row(1, 30, "30"));
 +    }
 +
 +    @Test
 +    public void testDeletionOnDifferentSSTables() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col DESC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        flush();
 +
 +        execute("DELETE FROM %s WHERE id=1 and col=30");
 +        flush();
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 3, row(1, 20, 
"20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 4, row(1, 20, 
"20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 4, row(1, 20, 
"20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 4, row(1, 20, "20"), 
row(1, 10, "10"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
2);
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
3, row(1, 20, "20"));
 +    }
 +
 +    @Test
 +    public void testDeletionOnSameSSTable() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col DESC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        execute("DELETE FROM %s WHERE id=1 and col=30");
 +        flush();
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 2, row(1, 20, 
"20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 3, row(1, 20, 
"20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 3, row(1, 20, 
"20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 3, row(1, 20, "20"), 
row(1, 10, "10"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
1);
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
2, row(1, 20, "20"));
 +    }
 +
 +    @Test
 +    public void testDeletionOnMemTable() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col DESC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        execute("DELETE FROM %s WHERE id=1 and col=30");
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 1, row(1, 20, 
"20"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 2, row(1, 20, 
"20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 3", 2, row(1, 20, 
"20"), row(1, 10, "10"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 2, row(1, 20, "20"), 
row(1, 10, "10"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 25 LIMIT 1", 
0);
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col < 40 LIMIT 1", 
1, row(1, 20, "20"));
 +    }
 +
 +    @Test
 +    public void testDeletionOnIndexedSSTableDESC() throws Throwable
 +    {
 +        testDeletionOnIndexedSSTableDESC(true);
 +        testDeletionOnIndexedSSTableDESC(false);
 +    }
 +
 +    private void testDeletionOnIndexedSSTableDESC(boolean deleteWithRange) 
throws Throwable
 +    {
 +        // reduce the column index size so that columns get indexed during 
flush
 +        DatabaseDescriptor.setColumnIndexSize(1);
 +
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col DESC)");
 +
 +        for (int i = 1; i <= 1000; i++)
 +        {
 +            execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, i, 
Integer.toString(i));
 +        }
 +        flush();
 +
 +        Object[][] allRows = new Object[1000][];
 +        for (int i = 1001; i <= 2000; i++)
 +        {
 +            execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, i, 
Integer.toString(i));
 +            allRows[2000 - i] = row(1, i, Integer.toString(i));
 +        }
 +
 +        if (deleteWithRange)
 +        {
 +            execute("DELETE FROM %s WHERE id=1 and col <= ?", 1000);
 +        }
 +        else
 +        {
 +            for (int i = 1; i <= 1000; i++)
 +                execute("DELETE FROM %s WHERE id=1 and col = ?", i);
 +        }
 +        flush();
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 1, row(1, 
2000, "2000"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 1, row(1, 
2000, "2000"), row(1, 1999, "1999"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 2, allRows);
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 1000 LIMIT 1", 
1, row(1, 2000, "2000"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col <= 2000 LIMIT 
1", 1, row(1, 2000, "2000"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 1000", 1, 
allRows);
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col <= 2000", 2, 
allRows);
 +    }
 +
 +    @Test
 +    public void testDeletionOnIndexedSSTableASC() throws Throwable
 +    {
 +        testDeletionOnIndexedSSTableASC(true);
 +        testDeletionOnIndexedSSTableASC(false);
 +    }
 +
 +    private void testDeletionOnIndexedSSTableASC(boolean deleteWithRange) 
throws Throwable
 +    {
 +        // reduce the column index size so that columns get indexed during 
flush
 +        DatabaseDescriptor.setColumnIndexSize(1);
 +
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col ASC)");
 +
 +        for (int i = 1; i <= 1000; i++)
 +        {
 +            execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, i, 
Integer.toString(i));
 +        }
 +        flush();
 +
 +        Object[][] allRows = new Object[1000][];
 +        for (int i = 1001; i <= 2000; i++)
 +        {
 +            execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, i, 
Integer.toString(i));
 +            allRows[i - 1001] = row(1, i, Integer.toString(i));
 +        }
 +        flush();
 +
 +        if (deleteWithRange)
 +        {
 +            execute("DELETE FROM %s WHERE id =1 and col <= ?", 1000);
 +        }
 +        else
 +        {
 +            for (int i = 1; i <= 1000; i++)
 +                execute("DELETE FROM %s WHERE id=1 and col = ?", i);
 +        }
 +        flush();
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 3, row(1, 
1001, "1001"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 3, row(1, 
1001, "1001"), row(1, 1002, "1002"));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 3, allRows);
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 1000 LIMIT 1", 
2, row(1, 1001, "1001"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col <= 2000 LIMIT 
1", 3, row(1, 1001, "1001"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 1000", 2, 
allRows);
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col <= 2000", 3, 
allRows);
 +    }
 +
 +    @Test
 +    public void testDeletionOnOverlappingIndexedSSTable() throws Throwable
 +    {
 +        testDeletionOnOverlappingIndexedSSTable(true);
 +        testDeletionOnOverlappingIndexedSSTable(false);
 +    }
 +
 +    private void testDeletionOnOverlappingIndexedSSTable(boolean 
deleteWithRange) throws Throwable
 +    {
 +        // reduce the column index size so that columns get indexed during 
flush
 +        DatabaseDescriptor.setColumnIndexSize(1);
 +
 +        createTable("CREATE TABLE %s (id int, col int, val1 text, val2 text, 
PRIMARY KEY (id, col)) WITH CLUSTERING ORDER BY (col ASC)");
 +
 +        for (int i = 1; i <= 500; i++)
 +        {
 +            if (i % 2 == 0)
 +                execute("INSERT INTO %s (id, col, val1) VALUES (?, ?, ?)", 1, 
i, Integer.toString(i));
 +            else
 +                execute("INSERT INTO %s (id, col, val1, val2) VALUES (?, ?, 
?, ?)", 1, i, Integer.toString(i), Integer.toString(i));
 +        }
 +
 +        for (int i = 1001; i <= 1500; i++)
 +        {
 +            if (i % 2 == 0)
 +                execute("INSERT INTO %s (id, col, val1) VALUES (?, ?, ?)", 1, 
i, Integer.toString(i));
 +            else
 +                execute("INSERT INTO %s (id, col, val1, val2) VALUES (?, ?, 
?, ?)", 1, i, Integer.toString(i), Integer.toString(i));
 +        }
 +
 +        flush();
 +
 +        for (int i = 501; i <= 1000; i++)
 +        {
 +            if (i % 2 == 0)
 +                execute("INSERT INTO %s (id, col, val1) VALUES (?, ?, ?)", 1, 
i, Integer.toString(i));
 +            else
 +                execute("INSERT INTO %s (id, col, val1, val2) VALUES (?, ?, 
?, ?)", 1, i, Integer.toString(i), Integer.toString(i));
 +        }
 +
 +        for (int i = 1501; i <= 2000; i++)
 +        {
 +            if (i % 2 == 0)
 +                execute("INSERT INTO %s (id, col, val1) VALUES (?, ?, ?)", 1, 
i, Integer.toString(i));
 +            else
 +                execute("INSERT INTO %s (id, col, val1, val2) VALUES (?, ?, 
?, ?)", 1, i, Integer.toString(i), Integer.toString(i));
 +        }
 +
 +        if (deleteWithRange)
 +        {
 +            execute("DELETE FROM %s WHERE id=1 and col > ? and col <= ?", 
250, 750);
 +        }
 +        else
 +        {
 +            for (int i = 251; i <= 750; i++)
 +                execute("DELETE FROM %s WHERE id=1 and col = ?", i);
 +        }
 +
 +        flush();
 +
 +        Object[][] allRows = new Object[1500][]; // non deleted rows
 +        for (int i = 1; i <= 2000; i++)
 +        {
 +            if (i > 250 && i <= 750)
 +                continue; // skip deleted records
 +
 +            int idx = (i <= 250 ? i - 1 : i - 501);
 +
 +            if (i % 2 == 0)
 +                allRows[idx] = row(1, i, Integer.toString(i), null);
 +            else
 +                allRows[idx] = row(1, i, Integer.toString(i), 
Integer.toString(i));
 +        }
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 1", 2, row(1, 1, 
"1", "1"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 LIMIT 2", 2, row(1, 1, 
"1", "1"), row(1, 2, "2", null));
 +
 +        executeAndCheck("SELECT * FROM %s WHERE id=1", 2, allRows);
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 1000 LIMIT 1", 
2, row(1, 1001, "1001", "1001"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col <= 2000 LIMIT 
1", 2, row(1, 1, "1", "1"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col > 500 LIMIT 1", 
2, row(1, 751, "751", "751"));
 +        executeAndCheck("SELECT * FROM %s WHERE id=1 AND col <= 500 LIMIT 1", 
2, row(1, 1, "1", "1"));
 +    }
 +
 +    @Test
 +    public void testMultiplePartitionsDESC() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (id int, col int, val text, PRIMARY KEY 
(id, col)) WITH CLUSTERING ORDER BY (col DESC)");
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 10, 
"10");
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 2, 10, 
"10");
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 3, 10, 
"10");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 20, 
"20");
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 2, 20, 
"20");
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 3, 20, 
"20");
 +        flush();
 +
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 1, 30, 
"30");
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 2, 30, 
"30");
 +        execute("INSERT INTO %s (id, col, val) VALUES (?, ?, ?)", 3, 30, 
"30");
 +        flush();
 +
 +        for (int i = 1; i <= 3; i++)
 +        {
 +            String base = "SELECT * FROM %s ";
 +
 +            executeAndCheck(base + String.format("WHERE id=%d LIMIT 1", i), 
1, row(i, 30, "30"));
 +            executeAndCheck(base + String.format("WHERE id=%d LIMIT 2", i), 
2, row(i, 30, "30"), row(i, 20, "20"));
 +            executeAndCheck(base + String.format("WHERE id=%d LIMIT 3", i), 
3, row(i, 30, "30"), row(i, 20, "20"), row(i, 10, "10"));
 +            executeAndCheck(base + String.format("WHERE id=%d", i), 3, row(i, 
30, "30"), row(i, 20, "20"), row(i, 10, "10"));
 +
 +            executeAndCheck(base + String.format("WHERE id=%d AND col > 25 
LIMIT 1", i), 1, row(i, 30, "30"));
 +            executeAndCheck(base + String.format("WHERE id=%d AND col < 40 
LIMIT 1", i), 1, row(i, 30, "30"));
 +        }
 +    }
++
++    @Test
+     public void testNonCompactTableRowDeletion() throws Throwable
+     {
+         createTable("CREATE TABLE %s (pk int, ck int, v text, PRIMARY KEY 
(pk, ck))");
+ 
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 1, '1')");
+         flush();
+ 
+         execute("DELETE FROM %s WHERE pk = 1 AND ck = 1");
+         flush();
+ 
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 1", 2);
+     }
+ 
+     @Test
+     public void testNonCompactTableRangeDeletion() throws Throwable
+     {
+         createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY 
(a, b, c))");
+ 
+         execute("INSERT INTO %s (a, b, c, d) VALUES (?, ?, ?, ?)", 1, 1, 1, 
1);
+         flush();
+ 
+         execute("DELETE FROM %s WHERE a=? AND b=?", 1, 1);
+         flush();
+ 
+         executeAndCheck("SELECT * FROM %s WHERE a=1 AND b=1 AND c=1", 2);
+     }
+ 
+     @Test
+     public void testNonCompactTableCellsDeletion() throws Throwable
+     {
+         createTable("CREATE TABLE %s (pk int, ck int, v1 text, v2 text, 
PRIMARY KEY (pk, ck))");
+ 
+         execute("INSERT INTO %s (pk, ck, v1, v2) VALUES (1, 1, '1', '1')");
+         flush();
+ 
+         execute("DELETE v1 FROM %s WHERE pk = 1 AND ck = 1");
+         execute("DELETE v2 FROM %s WHERE pk = 1 AND ck = 1");
+         flush();
+ 
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 1", 2, row(1, 
1, null, null));
+     }
+ 
+     @Test
+     public void testCompactTableSkipping() throws Throwable
+     {
+         createTable("CREATE TABLE %s (pk int, ck int, v text, PRIMARY KEY 
(pk, ck)) WITH COMPACT STORAGE");
+ 
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 1, '1') USING 
TIMESTAMP 1000000");
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 50, '2') USING 
TIMESTAMP 1000001");
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 100, '3') USING 
TIMESTAMP 1000002");
+         flush();
+ 
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 2, '4') USING 
TIMESTAMP 2000000");
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 51, '5') USING 
TIMESTAMP 2000001");
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 101, '6') USING 
TIMESTAMP 2000002");
+         flush();
+ 
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 51", 1, 
row(1, 51, "5"));
+ 
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 51", 1, 
row(1, 51, "5"));
+     }
+ 
+     @Test
+     public void testCompactTableSkippingPkOnly() throws Throwable
+     {
+         createTable("CREATE TABLE %s (pk int, ck int, PRIMARY KEY (pk, ck)) 
WITH COMPACT STORAGE");
+ 
+         execute("INSERT INTO %s (pk, ck) VALUES (1, 1) USING TIMESTAMP 
1000000");
+         execute("INSERT INTO %s (pk, ck) VALUES (1, 50) USING TIMESTAMP 
1000001");
+         execute("INSERT INTO %s (pk, ck) VALUES (1, 100) USING TIMESTAMP 
1000002");
+         flush();
+ 
+         execute("INSERT INTO %s (pk, ck) VALUES (1, 2) USING TIMESTAMP 
2000000");
+         execute("INSERT INTO %s (pk, ck) VALUES (1, 51) USING TIMESTAMP 
2000001");
+         execute("INSERT INTO %s (pk, ck) VALUES (1, 101) USING TIMESTAMP 
2000002");
+         flush();
+ 
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 51", 1, 
row(1, 51));
+ 
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 51", 1, 
row(1, 51));
+     }
+ 
+     @Test
+     public void testCompactTableCellDeletion() throws Throwable
+     {
+         createTable("CREATE TABLE %s (pk int, ck int, v text, PRIMARY KEY 
(pk, ck)) WITH COMPACT STORAGE");
+ 
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 1, '1')");
+         flush();
+ 
+         execute("DELETE v FROM %s WHERE pk = 1 AND ck = 1");
+         flush();
+ 
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 1", 1);
+ 
+         // Dropping compact storage forces us to hit an extra SSTable, since 
we can't rely on the isDense flag
+         // to determine that a row with a complete set of column deletes is 
complete.
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 1", 2);
+     }
+ 
+     @Test
+     public void testCompactTableRowDeletion() throws Throwable
+     {
+         createTable("CREATE TABLE %s (pk int, ck int, v text, PRIMARY KEY 
(pk, ck)) WITH COMPACT STORAGE");
+ 
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 1, '1')");
+         flush();
+ 
+         execute("DELETE FROM %s WHERE pk = 1 AND ck = 1");
+         flush();
+ 
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 1", 1);
+ 
+         // Dropping compact storage forces us to hit an extra SSTable, since 
we can't rely on the isDense flag
+         // to determine that a row with a complete set of column deletes is 
complete.
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 1", 2);
+     }
+ 
+     @Test
+     public void testCompactTableRangeDeletion() throws Throwable
+     {
+         createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY 
(a, b, c)) WITH COMPACT STORAGE");
+ 
+         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 (?, ?, ?, ?)", 1, 2, 1, 
1);
+         flush();
+ 
+         execute("DELETE FROM %s WHERE a=? AND b=?", 1, 1);
+         flush();
+ 
+         // Even with a compact table, we can't short-circuit for a range 
deletion rather than a cell tombstone.
+         executeAndCheck("SELECT * FROM %s WHERE a=1 AND b=1 AND c=1", 2);
+ 
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE a=1 AND b=1 AND c=1", 2);
+     }
+ 
+     @Test
+     public void testCompactTableRangeOverRowDeletion() throws Throwable
+     {
+         createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY 
(a, b, c)) WITH COMPACT STORAGE");
+ 
+         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 (?, ?, ?, ?)", 1, 2, 1, 
1);
+         flush();
+ 
+         execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 1, 1, 1);
+         flush();
+ 
+         execute("DELETE FROM %s WHERE a=? AND b=?", 1, 1);
+         flush();
+ 
+         // The range delete will subsume the row delete, and the latter will 
not factor into skipping decisions.
+         executeAndCheck("SELECT * FROM %s WHERE a=1 AND b=1 AND c=1", 3);
+ 
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE a=1 AND b=1 AND c=1", 3);
+     }
+ 
+     @Test
+     public void testCompactTableRowOverRangeDeletion() throws Throwable
+     {
+         createTable("CREATE TABLE %s (a int, b int, c int, d int, PRIMARY KEY 
(a, b, c)) WITH COMPACT STORAGE");
+ 
+         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 (?, ?, ?, ?)", 1, 2, 1, 
1);
+         flush();
+ 
+         execute("DELETE FROM %s WHERE a=? AND b=?", 1, 1);
+         flush();
+ 
+         execute("DELETE FROM %s WHERE a=? AND b=? AND c=?", 1, 1, 1);
+         flush();
+ 
+         // The row delete provides a tombstone, which is enough information 
to short-circuit after the first SSTable.
+         executeAndCheck("SELECT * FROM %s WHERE a=1 AND b=1 AND c=1", 1);
+ 
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE a=1 AND b=1 AND c=1", 3);
+     }
+ 
+     @Test
+     public void testCompactTableCellUpdate() throws Throwable
+     {
+         createTable("CREATE TABLE %s (pk int, ck int, v text, PRIMARY KEY 
(pk, ck)) WITH COMPACT STORAGE");
+ 
+         execute("INSERT INTO %s (pk, ck, v) VALUES (1, 1, '1')");
+         flush();
+ 
+         execute("UPDATE %s SET v = '2' WHERE pk = 1 AND ck = 1");
+         flush();
+ 
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 1", 1, row(1, 
1, "2"));
+ 
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 1", 1, row(1, 
1, "2"));
+     }
+ 
+     @Test
+     public void testCompactTableDeleteOverlappingSSTables() throws Throwable
+     {
+         createTable("CREATE TABLE %s (pk int, ck int, PRIMARY KEY (pk, ck)) 
WITH COMPACT STORAGE");
+ 
+         execute("INSERT INTO %s (pk, ck) VALUES (1, 51) USING TIMESTAMP 
1000002");
+         flush();
+         execute("DELETE FROM %s WHERE pk = 1 AND ck = 51");
+         flush();
+ 
+         execute("INSERT INTO %s (pk, ck) VALUES (1, 51) USING TIMESTAMP 
1000001");
+         execute("INSERT INTO %s (pk, ck) VALUES (2, 51)");
+         flush();
+ 
+         // If it weren't for the write to pk = 2, ck = 51, we could skip the 
third SSTable too and hit only one here.
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 51", 2);
+ 
+         // Dropping compact storage forces us to hit an extra SSTable, since 
we can't rely on the isDense flag
+         // to determine that a row with a complete set of column deletes is 
complete.
+         execute("ALTER TABLE %s DROP COMPACT STORAGE");
+         executeAndCheck("SELECT * FROM %s WHERE pk = 1 AND ck = 51", 3);
+     }
  }
diff --cc 
test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java
index 1a8b49b,42a8560..c9c8051
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java
@@@ -20,20 -20,16 +20,20 @@@ package org.apache.cassandra.cql3.valid
  
  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.Attributes;
  import org.apache.cassandra.cql3.CQLTester;
 +import org.apache.cassandra.cql3.UntypedResultSet;
 +import org.apache.cassandra.cql3.UntypedResultSet.Row;
  import org.apache.cassandra.db.ColumnFamilyStore;
  import org.apache.cassandra.db.Keyspace;
  import org.apache.cassandra.utils.ByteBufferUtil;
  
 +import static org.apache.commons.lang3.StringUtils.isEmpty;
 +import static org.junit.Assert.assertTrue;
++import static org.junit.Assert.assertEquals;
 +
  public class UpdateTest extends CQLTester
  {
      @Test
@@@ -497,62 -493,6 +497,62 @@@
          assertRows(execute("SELECT l FROM %s WHERE k = 0"), row(list("v1", 
"v4", "v3")));
      }
  
 +    @Test
 +    public void testUpdateWithDefaultTtl() throws Throwable
 +    {
 +        final int secondsPerMinute = 60;
 +        createTable("CREATE TABLE %s (a int PRIMARY KEY, b int) WITH 
default_time_to_live = " + (10 * secondsPerMinute));
 +
 +        execute("UPDATE %s SET b = 1 WHERE a = 1");
 +        UntypedResultSet resultSet = execute("SELECT ttl(b) FROM %s WHERE a = 
1");
-         Assert.assertEquals(1, resultSet.size());
++        assertEquals(1, resultSet.size());
 +        Row row = resultSet.one();
-         Assert.assertTrue(row.getInt("ttl(b)") >= (9 * secondsPerMinute));
++        assertTrue(row.getInt("ttl(b)") >= (9 * secondsPerMinute));
 +
 +        execute("UPDATE %s USING TTL ? SET b = 3 WHERE a = 1", 0);
 +        assertRows(execute("SELECT ttl(b) FROM %s WHERE a = 1"), row(new 
Object[]{null}));
 +
 +        execute("UPDATE %s SET b = 3 WHERE a = 1");
 +        resultSet = execute("SELECT ttl(b) FROM %s WHERE a = 1");
-         Assert.assertEquals(1, resultSet.size());
++        assertEquals(1, resultSet.size());
 +        row = resultSet.one();
-         Assert.assertTrue(row.getInt("ttl(b)") >= (9 * secondsPerMinute));
++        assertTrue(row.getInt("ttl(b)") >= (9 * secondsPerMinute));
 +
 +        execute("UPDATE %s USING TTL ? SET b = 2 WHERE a = 2", unset());
 +        resultSet = execute("SELECT ttl(b) FROM %s WHERE a = 2");
-         Assert.assertEquals(1, resultSet.size());
++        assertEquals(1, resultSet.size());
 +        row = resultSet.one();
-         Assert.assertTrue(row.getInt("ttl(b)") >= (9 * secondsPerMinute));
++        assertTrue(row.getInt("ttl(b)") >= (9 * secondsPerMinute));
 +
 +        execute("UPDATE %s USING TTL ? SET b = ? WHERE a = ?", null, 3, 3);
 +        assertRows(execute("SELECT ttl(b) FROM %s WHERE a = 3"), row(new 
Object[] { null }));
 +    }
 +
 +    @Test
 +    public void testUpdateWithTtl() throws Throwable
 +    {
 +        createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)");
 +
 +        execute("INSERT INTO %s (k, v) VALUES (1, 1) USING TTL ?", 3600);
 +        execute("INSERT INTO %s (k, v) VALUES (2, 2) USING TTL ?", 3600);
 +
 +        // test with unset
 +        execute("UPDATE %s USING TTL ? SET v = ? WHERE k = ?", unset(), 1, 
1); // treat as 'unlimited'
 +        assertRows(execute("SELECT ttl(v) FROM %s WHERE k = 1"), row(new 
Object[] { null }));
 +
 +        // test with null
 +        execute("UPDATE %s USING TTL ? SET v = ? WHERE k = ?", unset(), 2, 2);
 +        assertRows(execute("SELECT k, v, TTL(v) FROM %s WHERE k = 2"), row(2, 
2, null));
 +
 +        // test error handling
 +        assertInvalidMessage("A TTL must be greater or equal to 0, but was 
-5",
 +                             "UPDATE %s USING TTL ? SET v = ? WHERE k = ?", 
-5, 1, 1);
 +
 +        assertInvalidMessage("ttl is too large.",
 +                             "UPDATE %s USING TTL ? SET v = ? WHERE k = ?",
 +                             Attributes.MAX_TTL + 1, 1, 1);
 +    }
 +
      /**
       * Test for CASSANDRA-12829
       */


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to