Repository: cassandra Updated Branches: refs/heads/trunk d1bd71c4e -> e83f9e69e
Allow TTL with null value on insert and update patch by Russell Spitzer; reviewed by Benjamin Lerer for CASSANDRA-12216 Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/e83f9e69 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/e83f9e69 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/e83f9e69 Branch: refs/heads/trunk Commit: e83f9e69e2c4abd295645eaf0289772a15eb4a85 Parents: d1bd71c Author: Russell Spitzer <[email protected]> Authored: Tue Aug 16 16:36:13 2016 +0200 Committer: Benjamin Lerer <[email protected]> Committed: Tue Aug 16 16:36:13 2016 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + NEWS.txt | 1 + doc/source/cql/changes.rst | 2 ++ doc/source/cql/dml.rst | 3 +- .../org/apache/cassandra/cql3/Attributes.java | 2 +- .../apache/cassandra/cql3/QueryProcessor.java | 2 +- .../cql3/validation/operations/InsertTest.java | 27 ++++++++++++++---- .../cql3/validation/operations/UpdateTest.java | 30 ++++++++++++++++++++ 8 files changed, 59 insertions(+), 9 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/e83f9e69/CHANGES.txt ---------------------------------------------------------------------- diff --git a/CHANGES.txt b/CHANGES.txt index 7b29394..700dd48 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1,4 +1,5 @@ 3.10 + * Allow TTL with null value on insert and update (CASSANDRA-12216) * Make decommission operation resumable (CASSANDRA-12008) * Add support to one-way targeted repair (CASSANDRA-9876) * Remove clientutil jar (CASSANDRA-11635) http://git-wip-us.apache.org/repos/asf/cassandra/blob/e83f9e69/NEWS.txt ---------------------------------------------------------------------- diff --git a/NEWS.txt b/NEWS.txt index 9bdeec1..9cfc58b 100644 --- a/NEWS.txt +++ b/NEWS.txt @@ -58,6 +58,7 @@ New features and org.apache.cassandra.metrics:type=Client,name=AuthFailure respectively. - Add support to "unset" JSON fields in prepared statements by specifying DEFAULT UNSET. See CASSANDRA-11424 for details + - Allow TTL with null value on insert and update. It will be treated as equivalent to inserting a 0. Upgrading --------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/e83f9e69/doc/source/cql/changes.rst ---------------------------------------------------------------------- diff --git a/doc/source/cql/changes.rst b/doc/source/cql/changes.rst index 7d7c2b9..4f71748 100644 --- a/doc/source/cql/changes.rst +++ b/doc/source/cql/changes.rst @@ -26,6 +26,8 @@ The following describes the changes in each version of CQL. - Support for ``GROUP BY`` (:jira:`10707`). - Adds a ``DEFAULT UNSET`` option for ``INSERT JSON`` to ignore omitted columns (:jira:`11424`). +- Allows ``null`` as a legal value for TTL on insert and update. It will be treated as equivalent to +inserting a 0 (:jira:`12216`). 3.4.2 ^^^^^ http://git-wip-us.apache.org/repos/asf/cassandra/blob/e83f9e69/doc/source/cql/dml.rst ---------------------------------------------------------------------- diff --git a/doc/source/cql/dml.rst b/doc/source/cql/dml.rst index ad878a9..1b0f80b 100644 --- a/doc/source/cql/dml.rst +++ b/doc/source/cql/dml.rst @@ -420,7 +420,8 @@ parameters: automatically removed from the database after the specified time. Note that the TTL concerns the inserted values, not the columns themselves. This means that any subsequent update of the column will also reset the TTL (to whatever TTL is specified in that update). By default, values never expire. A TTL of 0 is equivalent to no TTL. If the table has a - default_time_to_live, a TTL of 0 will remove the TTL for the inserted or updated values. + default_time_to_live, a TTL of 0 will remove the TTL for the inserted or updated values. A TTL of ``null`` is equivalent + to inserting with a TTL of 0. .. _delete_statement: http://git-wip-us.apache.org/repos/asf/cassandra/blob/e83f9e69/src/java/org/apache/cassandra/cql3/Attributes.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/Attributes.java b/src/java/org/apache/cassandra/cql3/Attributes.java index 534a2a0..60671a1 100644 --- a/src/java/org/apache/cassandra/cql3/Attributes.java +++ b/src/java/org/apache/cassandra/cql3/Attributes.java @@ -99,7 +99,7 @@ public class Attributes ByteBuffer tval = timeToLive.bindAndGet(options); if (tval == null) - throw new InvalidRequestException("Invalid null value of TTL"); + return 0; if (tval == ByteBufferUtil.UNSET_BYTE_BUFFER) return defaultTimeToLive; http://git-wip-us.apache.org/repos/asf/cassandra/blob/e83f9e69/src/java/org/apache/cassandra/cql3/QueryProcessor.java ---------------------------------------------------------------------- diff --git a/src/java/org/apache/cassandra/cql3/QueryProcessor.java b/src/java/org/apache/cassandra/cql3/QueryProcessor.java index 4e7323e..899b36d 100644 --- a/src/java/org/apache/cassandra/cql3/QueryProcessor.java +++ b/src/java/org/apache/cassandra/cql3/QueryProcessor.java @@ -57,7 +57,7 @@ import org.apache.cassandra.utils.*; public class QueryProcessor implements QueryHandler { - public static final CassandraVersion CQL_VERSION = new CassandraVersion("3.4.2"); + public static final CassandraVersion CQL_VERSION = new CassandraVersion("3.4.3"); public static final QueryProcessor instance = new QueryProcessor(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/e83f9e69/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java ---------------------------------------------------------------------- diff --git a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java index 9adcb62..488e1c7 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/InsertTest.java @@ -21,6 +21,7 @@ package org.apache.cassandra.cql3.validation.operations; import org.junit.Assert; import org.junit.Test; +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; @@ -52,13 +53,24 @@ public class InsertTest extends CQLTester } @Test - public void testInsertTtlWithUnset() throws Throwable + public void testInsertWithTtl() throws Throwable { - createTable("CREATE TABLE %s (k int PRIMARY KEY, i int)"); - execute("INSERT INTO %s (k, i) VALUES (1, 1) USING TTL ?", unset()); // treat as 'unlimited' - assertRows(execute("SELECT ttl(i) FROM %s"), - row(new Object[]{ null }) - ); + createTable("CREATE TABLE %s (k int PRIMARY KEY, v int)"); + + // test with unset + execute("INSERT INTO %s (k, v) VALUES (1, 1) USING TTL ?", unset()); // treat as 'unlimited' + assertRows(execute("SELECT ttl(v) FROM %s"), row(new Object[]{ null })); + + // test with null + execute("INSERT INTO %s (k, v) VALUES (?, ?) USING TTL ?", 1, 1, null); + assertRows(execute("SELECT k, v, TTL(v) FROM %s"), row(1, 1, null)); + + // test error handling + assertInvalidMessage("A TTL must be greater or equal to 0, but was -5", + "INSERT INTO %s (k, v) VALUES (?, ?) USING TTL ?", 1, 1, -5); + + assertInvalidMessage("ttl is too large.", + "INSERT INTO %s (k, v) VALUES (?, ?) USING TTL ?", 1, 1, Attributes.MAX_TTL + 1); } @Test @@ -314,6 +326,9 @@ public class InsertTest extends CQLTester Assert.assertEquals(1, resultSet.size()); row = resultSet.one(); Assert.assertTrue(row.getInt("ttl(b)") >= (9 * secondsPerMinute)); + + execute("INSERT INTO %s (a, b) VALUES (?, ?) USING TTL ?", 4, 4, null); + assertRows(execute("SELECT ttl(b) FROM %s WHERE a = 4"), row(new Object[]{null})); } @Test http://git-wip-us.apache.org/repos/asf/cassandra/blob/e83f9e69/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 9c42fc2..494abaa 100644 --- a/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java +++ b/test/unit/org/apache/cassandra/cql3/validation/operations/UpdateTest.java @@ -24,6 +24,8 @@ import org.junit.Assert; import org.junit.Test; import static org.apache.commons.lang3.StringUtils.isEmpty; + +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; @@ -550,5 +552,33 @@ public class UpdateTest extends CQLTester Assert.assertEquals(1, resultSet.size()); row = resultSet.one(); Assert.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); } }
