You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cassandra.apache.org by sl...@apache.org on 2014/05/23 18:56:38 UTC
git commit: Support nul/non-existant fields in UDT
Repository: cassandra
Updated Branches:
refs/heads/cassandra-2.1 0b9b1fca0 -> ca7e9d5c4
Support nul/non-existant fields in UDT
patch by slebresne; reviewed by iamaleskey for CASSANDRA-7206
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/ca7e9d5c
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/ca7e9d5c
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/ca7e9d5c
Branch: refs/heads/cassandra-2.1
Commit: ca7e9d5c49b08fa4981d5986ef68c82b3777e282
Parents: 0b9b1fc
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Fri May 23 18:49:44 2014 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Fri May 23 18:56:29 2014 +0200
----------------------------------------------------------------------
CHANGES.txt | 1 +
.../org/apache/cassandra/cql3/UserTypes.java | 16 +++-----
.../apache/cassandra/db/marshal/UserType.java | 39 ++++++++++++++------
3 files changed, 34 insertions(+), 22 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ca7e9d5c/CHANGES.txt
----------------------------------------------------------------------
diff --git a/CHANGES.txt b/CHANGES.txt
index 108c859..9bde1f3 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -24,6 +24,7 @@
* Use prepared statements internally (CASSANDRA-6975)
* Fix broken paging state with prepared statement (CASSANDRA-7120)
* Fix IllegalArgumentException in CqlStorage (CASSANDRA-7287)
+ * Allow nulls/non-existant fields in UDT (CASSANDRA-7206)
Merged from 2.0:
* Always reallocate buffers in HSHA (CASSANDRA-6285)
* (Hadoop) support authentication in CqlRecordReader (CASSANDRA-7221)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ca7e9d5c/src/java/org/apache/cassandra/cql3/UserTypes.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/cql3/UserTypes.java b/src/java/org/apache/cassandra/cql3/UserTypes.java
index e9da6e5..ecffe31 100644
--- a/src/java/org/apache/cassandra/cql3/UserTypes.java
+++ b/src/java/org/apache/cassandra/cql3/UserTypes.java
@@ -20,7 +20,6 @@ package org.apache.cassandra.cql3;
import java.nio.ByteBuffer;
import java.util.*;
-import org.apache.cassandra.db.marshal.CompositeType;
import org.apache.cassandra.db.marshal.UserType;
import org.apache.cassandra.db.marshal.UTF8Type;
import org.apache.cassandra.exceptions.InvalidRequestException;
@@ -59,7 +58,10 @@ public abstract class UserTypes
for (int i = 0; i < ut.fieldTypes.size(); i++)
{
ColumnIdentifier field = new ColumnIdentifier(ut.fieldNames.get(i), UTF8Type.instance);
- Term value = entries.get(field).prepare(keyspace, fieldSpecOf(receiver, i));
+ Term.Raw raw = entries.get(field);
+ if (raw == null)
+ raw = Constants.NULL_LITERAL;
+ Term value = raw.prepare(keyspace, fieldSpecOf(receiver, i));
if (value instanceof Term.NonTerminal)
allTerminal = false;
@@ -81,7 +83,7 @@ public abstract class UserTypes
ColumnIdentifier field = new ColumnIdentifier(ut.fieldNames.get(i), UTF8Type.instance);
Term.Raw value = entries.get(field);
if (value == null)
- throw new InvalidRequestException(String.format("Invalid user type literal for %s: missing field %s", receiver, field));
+ continue;
ColumnSpecification fieldSpec = fieldSpecOf(receiver, i);
if (!value.isAssignableTo(keyspace, fieldSpec))
@@ -154,13 +156,7 @@ public abstract class UserTypes
ByteBuffer[] buffers = new ByteBuffer[values.size()];
for (int i = 0; i < type.fieldTypes.size(); i++)
- {
- ByteBuffer buffer = values.get(i).bindAndGet(options);
- if (buffer == null)
- throw new InvalidRequestException("null is not supported inside user type literals");
-
- buffers[i] = buffer;
- }
+ buffers[i] = values.get(i).bindAndGet(options);
return buffers;
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/ca7e9d5c/src/java/org/apache/cassandra/db/marshal/UserType.java
----------------------------------------------------------------------
diff --git a/src/java/org/apache/cassandra/db/marshal/UserType.java b/src/java/org/apache/cassandra/db/marshal/UserType.java
index 50b3fbb..6656fd6 100644
--- a/src/java/org/apache/cassandra/db/marshal/UserType.java
+++ b/src/java/org/apache/cassandra/db/marshal/UserType.java
@@ -126,9 +126,10 @@ public class UserType extends AbstractType<ByteBuffer>
throw new MarshalException(String.format("Not enough bytes to read size of %dth field %s", i, fieldNames.get(i)));
int size = input.getInt();
- // We don't handle null just yet, but we should fix that soon (CASSANDRA-7206)
+
+ // size < 0 means null value
if (size < 0)
- throw new MarshalException("Nulls are not yet supported inside UDT values");
+ continue;
if (input.remaining() < size)
throw new MarshalException(String.format("Not enough bytes to read %dth field %s", i, fieldNames.get(i)));
@@ -164,13 +165,20 @@ public class UserType extends AbstractType<ByteBuffer>
{
int totalLength = 0;
for (ByteBuffer field : fields)
- totalLength += 4 + field.remaining();
+ totalLength += 4 + (field == null ? 0 : field.remaining());
ByteBuffer result = ByteBuffer.allocate(totalLength);
for (ByteBuffer field : fields)
{
- result.putInt(field.remaining());
- result.put(field.duplicate());
+ if (field == null)
+ {
+ result.putInt(-1);
+ }
+ else
+ {
+ result.putInt(field.remaining());
+ result.put(field.duplicate());
+ }
}
result.rewind();
return result;
@@ -191,11 +199,15 @@ public class UserType extends AbstractType<ByteBuffer>
AbstractType<?> type = fieldTypes.get(i);
int size = input.getInt();
- assert size >= 0; // We don't support nulls yet, but we will likely do with #7206 and we'll need
- // a way to represent it as a string (without it conflicting with a user value)
+ if (size < 0)
+ {
+ sb.append("@");
+ continue;
+ }
+
ByteBuffer field = ByteBufferUtil.readBytes(input, size);
- // We use ':' as delimiter so escape it if it's in the generated string
- sb.append(field == null ? "null" : type.getString(value).replaceAll(":", "\\\\:"));
+ // We use ':' as delimiter, and @ to represent null, so escape them in the generated string
+ sb.append(type.getString(field).replaceAll(":", "\\\\:").replaceAll("@", "\\\\@"));
}
return sb.toString();
}
@@ -207,10 +219,13 @@ public class UserType extends AbstractType<ByteBuffer>
ByteBuffer[] fields = new ByteBuffer[fieldStrings.size()];
for (int i = 0; i < fieldStrings.size(); i++)
{
+ String fieldString = fieldStrings.get(i);
+ // We use @ to represent nulls
+ if (fieldString.equals("@"))
+ continue;
+
AbstractType<?> type = fieldTypes.get(i);
- // TODO: we'll need to handle null somehow here once we support them
- String fieldString = fieldStrings.get(i).replaceAll("\\\\:", ":");
- fields[i] = type.fromString(fieldString);
+ fields[i] = type.fromString(fieldString.replaceAll("\\\\:", ":").replaceAll("\\\\@", "@"));
}
return buildValue(fields);
}