Updated Branches:
  refs/heads/cassandra-1.2 128177c41 -> cf84ea718

Add support for nulls in CQL3

patch by michalm & slebresne; reviewed by iamaleksey for CASSANDRA-3783


Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/cf84ea71
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/cf84ea71
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/cf84ea71

Branch: refs/heads/cassandra-1.2
Commit: cf84ea718f84da3071cce0e66d6a9dc753ea4952
Parents: 128177c
Author: Sylvain Lebresne <[email protected]>
Authored: Thu Apr 4 19:07:32 2013 +0200
Committer: Sylvain Lebresne <[email protected]>
Committed: Thu Apr 4 19:07:32 2013 +0200

----------------------------------------------------------------------
 CHANGES.txt                                       |    1 +
 src/java/org/apache/cassandra/cql3/Constants.java |   32 ++++++++++++++
 src/java/org/apache/cassandra/cql3/Cql.g          |    3 +
 src/java/org/apache/cassandra/cql3/Lists.java     |   36 ++++++++++-----
 src/java/org/apache/cassandra/cql3/Maps.java      |   19 ++++----
 src/java/org/apache/cassandra/cql3/Sets.java      |    5 ++-
 src/java/org/apache/cassandra/cql3/Term.java      |    3 +-
 7 files changed, 76 insertions(+), 23 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cassandra/blob/cf84ea71/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 58ba39a..05a1188 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -19,6 +19,7 @@
  * Fix NPE during cql3 select with token() (CASSANDRA-5404)
  * IndexHelper.skipBloomFilters won't skip non-SHA filters (CASSANDRA-5385)
  * cqlsh: Print maps ordered by key, sort sets (CASSANDRA-5413)
+ * Add null syntax support in CQL3 for inserts (CASSANDRA-3783)
 Merged from 1.1:
  * cli: Quote ks and cf names in schema output when needed (CASSANDRA-5052)
  * Fix bad default for min/max timestamp in SSTableMetadata (CASSANDRA-5372)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cf84ea71/src/java/org/apache/cassandra/cql3/Constants.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Constants.java 
b/src/java/org/apache/cassandra/cql3/Constants.java
index f630869..9366e7d 100644
--- a/src/java/org/apache/cassandra/cql3/Constants.java
+++ b/src/java/org/apache/cassandra/cql3/Constants.java
@@ -49,6 +49,38 @@ public abstract class Constants
         STRING, INTEGER, UUID, FLOAT, BOOLEAN, HEX;
     }
 
+    public static final Term.Raw NULL_LITERAL = new Term.Raw()
+    {
+        private final Term.Terminal NULL_VALUE = new Value(null)
+        {
+            @Override
+            public Terminal bind(List<ByteBuffer> values)
+            {
+                // We return null because that makes life easier for 
collections
+                return null;
+            }
+        };
+
+        public Term prepare(ColumnSpecification receiver) throws 
InvalidRequestException
+        {
+            if (!isAssignableTo(receiver))
+                throw new InvalidRequestException("Invalid null value for 
counter increment/decrement");
+
+            return NULL_VALUE;
+        }
+
+        public boolean isAssignableTo(ColumnSpecification receiver)
+        {
+            return !(receiver.type instanceof CounterColumnType);
+        }
+
+        @Override
+        public String toString()
+        {
+            return null;
+        }
+    };
+
     public static class Literal implements Term.Raw
     {
         private final Type type;

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cf84ea71/src/java/org/apache/cassandra/cql3/Cql.g
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Cql.g 
b/src/java/org/apache/cassandra/cql3/Cql.g
index fb38fff..0c2113f 100644
--- a/src/java/org/apache/cassandra/cql3/Cql.g
+++ b/src/java/org/apache/cassandra/cql3/Cql.g
@@ -704,6 +704,7 @@ collection_literal returns [Term.Raw value]
 value returns [Term.Raw value]
     : c=constant           { $value = c; }
     | l=collection_literal { $value = l; }
+    | K_NULL               { $value = Constants.NULL_LITERAL; }
     | QMARK                { $value = new 
AbstractMarker.Raw(++currentBindMarkerIdx); }
     ;
 
@@ -961,6 +962,8 @@ K_TIMEUUID:    T I M E U U I D;
 K_TOKEN:       T O K E N;
 K_WRITETIME:   W R I T E T I M E;
 
+K_NULL:        N U L L;
+
 K_MAP:         M A P;
 K_LIST:        L I S T;
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cf84ea71/src/java/org/apache/cassandra/cql3/Lists.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Lists.java 
b/src/java/org/apache/cassandra/cql3/Lists.java
index 78db936..36694e5 100644
--- a/src/java/org/apache/cassandra/cql3/Lists.java
+++ b/src/java/org/apache/cassandra/cql3/Lists.java
@@ -81,6 +81,9 @@ public abstract class Lists
                 // We don't allow prepared marker in collections, nor nested 
collections
                 assert t instanceof Constants.Value;
                 ByteBuffer bytes = ((Constants.Value)t).bytes;
+                if (bytes == null)
+                    throw new InvalidRequestException("null is not supported 
inside collections");
+
                 // We don't support value > 64K because the serialization 
format encode the length as an unsigned short.
                 if (bytes.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
                     throw new InvalidRequestException(String.format("List 
value is too long. List values are limited to %d bytes but %d bytes value 
provided",
@@ -255,24 +258,33 @@ public abstract class Lists
 
         public void execute(ByteBuffer rowKey, ColumnFamily cf, 
ColumnNameBuilder prefix, UpdateParameters params) throws 
InvalidRequestException
         {
-            Term.Terminal index = idx.bind(params.variables);
-            Term.Terminal value = t.bind(params.variables);
-            assert index instanceof Constants.Value && value instanceof 
Constants.Value;
+            ByteBuffer index = idx.bindAndGet(params.variables);
+            ByteBuffer value = t.bindAndGet(params.variables);
+
+            if (index == null)
+                throw new InvalidRequestException("Invalid null value for list 
index");
 
             List<Pair<ByteBuffer, IColumn>> existingList = 
params.getPrefetchedList(rowKey, columnName.key);
-            int idx = ByteBufferUtil.toInt(((Constants.Value)index).bytes);
+            int idx = ByteBufferUtil.toInt(index);
             if (idx < 0 || idx >= existingList.size())
                 throw new InvalidRequestException(String.format("List index %d 
out of bound, list has size %d", idx, existingList.size()));
 
-            ByteBuffer bytes = ((Constants.Value)value).bytes;
-            // We don't support value > 64K because the serialization format 
encode the length as an unsigned short.
-            if (bytes.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
-                throw new InvalidRequestException(String.format("List value is 
too long. List values are limited to %d bytes but %d bytes value provided",
-                                                                
FBUtilities.MAX_UNSIGNED_SHORT,
-                                                                
bytes.remaining()));
-
             ByteBuffer elementName = existingList.get(idx).right.name();
-            cf.addColumn(params.makeColumn(elementName, bytes));
+
+            if (value == null)
+            {
+                cf.addColumn(params.makeTombstone(elementName));
+            }
+            else
+            {
+                // We don't support value > 64K because the serialization 
format encode the length as an unsigned short.
+                if (value.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
+                    throw new InvalidRequestException(String.format("List 
value is too long. List values are limited to %d bytes but %d bytes value 
provided",
+                                                                    
FBUtilities.MAX_UNSIGNED_SHORT,
+                                                                    
value.remaining()));
+
+                cf.addColumn(params.makeColumn(elementName, value));
+            }
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cf84ea71/src/java/org/apache/cassandra/cql3/Maps.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Maps.java 
b/src/java/org/apache/cassandra/cql3/Maps.java
index a2eb761..875dc47 100644
--- a/src/java/org/apache/cassandra/cql3/Maps.java
+++ b/src/java/org/apache/cassandra/cql3/Maps.java
@@ -81,12 +81,16 @@ public abstract class Maps
 
                 // We don't support values > 64K because the serialization 
format encode the length as an unsigned short.
                 ByteBuffer keyBytes = ((Constants.Value)k).bytes;
+                if (keyBytes == null)
+                    throw new InvalidRequestException("null is not supported 
inside collections");
                 if (keyBytes.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
                     throw new InvalidRequestException(String.format("Map key 
is too long. Map keys are limited to %d bytes but %d bytes keys provided",
                                                                     
FBUtilities.MAX_UNSIGNED_SHORT,
                                                                     
keyBytes.remaining()));
 
                 ByteBuffer valueBytes = ((Constants.Value)v).bytes;
+                if (valueBytes == null)
+                    throw new InvalidRequestException("null is not supported 
inside collections");
                 if (valueBytes.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
                     throw new InvalidRequestException(String.format("Map value 
is too long. Map values are limited to %d bytes but %d bytes value provided",
                                                                     
FBUtilities.MAX_UNSIGNED_SHORT,
@@ -231,14 +235,12 @@ public abstract class Maps
 
         public void execute(ByteBuffer rowKey, ColumnFamily cf, 
ColumnNameBuilder prefix, UpdateParameters params) throws 
InvalidRequestException
         {
-            Term.Terminal key = k.bind(params.variables);
-            Term.Terminal value = t.bind(params.variables);
+            ByteBuffer key = k.bindAndGet(params.variables);
+            ByteBuffer value = t.bindAndGet(params.variables);
             if (key == null)
                 throw new InvalidRequestException("Invalid null map key");
-            assert key instanceof Constants.Value;
-            assert value == null || value instanceof Constants.Value;
 
-            ByteBuffer cellName = 
prefix.add(columnName.key).add(((Constants.Value)key).bytes).build();
+            ByteBuffer cellName = prefix.add(columnName.key).add(key).build();
 
             if (value == null)
             {
@@ -246,14 +248,13 @@ public abstract class Maps
             }
             else
             {
-                ByteBuffer bytes = ((Constants.Value)value).bytes;
                 // We don't support value > 64K because the serialization 
format encode the length as an unsigned short.
-                if (bytes.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
+                if (value.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
                     throw new InvalidRequestException(String.format("Map value 
is too long. Map values are limited to %d bytes but %d bytes value provided",
                                                                     
FBUtilities.MAX_UNSIGNED_SHORT,
-                                                                    
bytes.remaining()));
+                                                                    
value.remaining()));
 
-                cf.addColumn(params.makeColumn(cellName, bytes));
+                cf.addColumn(params.makeColumn(cellName, value));
             }
         }
     }

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cf84ea71/src/java/org/apache/cassandra/cql3/Sets.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Sets.java 
b/src/java/org/apache/cassandra/cql3/Sets.java
index fb57542..8d67761 100644
--- a/src/java/org/apache/cassandra/cql3/Sets.java
+++ b/src/java/org/apache/cassandra/cql3/Sets.java
@@ -81,6 +81,9 @@ public abstract class Sets
                 }
 
                 ByteBuffer bytes = ((Constants.Value)t).bytes;
+                if (bytes == null)
+                    throw new InvalidRequestException("null is not supported 
inside collections");
+
                 // We don't support value > 64K because the serialization 
format encode the length as an unsigned short.
                 if (bytes.remaining() > FBUtilities.MAX_UNSIGNED_SHORT)
                     throw new InvalidRequestException(String.format("Set value 
is too long. Set values are limited to %d bytes but %d bytes value provided",
@@ -215,7 +218,7 @@ public abstract class Sets
             if (value == null)
                 return;
 
-            assert value instanceof Sets.Value;
+            assert value instanceof Sets.Value : value;
 
             Set<ByteBuffer> toAdd = ((Sets.Value)value).elements;
             for (ByteBuffer bb : toAdd)

http://git-wip-us.apache.org/repos/asf/cassandra/blob/cf84ea71/src/java/org/apache/cassandra/cql3/Term.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/Term.java 
b/src/java/org/apache/cassandra/cql3/Term.java
index 3cdb70f..d2d7975 100644
--- a/src/java/org/apache/cassandra/cql3/Term.java
+++ b/src/java/org/apache/cassandra/cql3/Term.java
@@ -125,7 +125,8 @@ public interface Term
     {
         public ByteBuffer bindAndGet(List<ByteBuffer> values) throws 
InvalidRequestException
         {
-            return bind(values).get();
+            Terminal t = bind(values);
+            return t == null ? null : t.get();
         }
     }
 }

Reply via email to