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);
     }
 }

Reply via email to