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