diff --git a/doc/native_protocol.spec b/doc/native_protocol.spec index ae3c1fda78..0092f5d1ac 100644 --- a/doc/native_protocol.spec +++ b/doc/native_protocol.spec @@ -49,6 +49,8 @@ Table of Contents . . +---------------------------------------- + The protocol is big-endian (network byte order). + Each frame contains a fixed size header (8 bytes) followed by a variable size body. The header is described in Section 2. The content of the body depends on the header opcode value (the body can in particular be empty for some @@ -355,6 +357,12 @@ Table of Contents 0x000D Varchar 0x000E Varint 0x000F Timeuuid + 0x0020 List: the value is an [option], representing the type + of the elements of the list. + 0x0021 Map: the value is two [option], representing the types of the + keys and values of the map + 0x0022 Set: the value is an [option], representing the type + of the elements of the set - is an [int] representing the number of rows present in this result. Those rows are serialized in the part. - is composed of ... where m is . diff --git a/src/java/org/apache/cassandra/cql3/ResultSet.java b/src/java/org/apache/cassandra/cql3/ResultSet.java index cb5e89f92f..152edb9c80 100644 --- a/src/java/org/apache/cassandra/cql3/ResultSet.java +++ b/src/java/org/apache/cassandra/cql3/ResultSet.java @@ -204,7 +204,6 @@ public class ResultSet public static class Metadata { - private static OptionCodec dataTypeCodec = new OptionCodec(DataType.class); public static final CBCodec codec = new Codec(); public final EnumSet flags; @@ -277,7 +276,7 @@ public class ResultSet String ksName = globalTablesSpec ? globalKsName : CBUtil.readString(body); String cfName = globalTablesSpec ? globalCfName : CBUtil.readString(body); ColumnIdentifier colName = new ColumnIdentifier(CBUtil.readString(body), true); - AbstractType type = DataType.toType(dataTypeCodec.decodeOne(body)); + AbstractType type = DataType.toType(DataType.codec.decodeOne(body)); names.add(new ColumnSpecification(ksName, cfName, colName, type)); } return new Metadata(flags, names); @@ -309,7 +308,7 @@ public class ResultSet builder.addString(name.cfName); } builder.addString(name.toString()); - builder.add(dataTypeCodec.encodeOne(DataType.fromType(name.type))); + builder.add(DataType.codec.encodeOne(DataType.fromType(name.type))); } return builder.build(); } diff --git a/src/java/org/apache/cassandra/transport/DataType.java b/src/java/org/apache/cassandra/transport/DataType.java index 525494570b..9a8c2f0283 100644 --- a/src/java/org/apache/cassandra/transport/DataType.java +++ b/src/java/org/apache/cassandra/transport/DataType.java @@ -17,8 +17,11 @@ */ package org.apache.cassandra.transport; +import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import java.util.List; import com.google.common.base.Charsets; import org.jboss.netty.buffer.ChannelBuffer; @@ -44,7 +47,12 @@ public enum DataType implements OptionCodec.Codecable UUID (12, UUIDType.instance), VARCHAR (13, UTF8Type.instance), VARINT (14, IntegerType.instance), - TIMEUUID (15, TimeUUIDType.instance); + TIMEUUID (15, TimeUUIDType.instance), + LIST (32, null), + MAP (33, null), + SET (34, null); + + public static final OptionCodec codec = new OptionCodec(DataType.class); private final int id; private final AbstractType type; @@ -75,6 +83,15 @@ public enum DataType implements OptionCodec.Codecable { case CUSTOM: return CBUtil.readString(cb); + case LIST: + return DataType.toType(codec.decodeOne(cb)); + case SET: + return DataType.toType(codec.decodeOne(cb)); + case MAP: + List l = new ArrayList(2); + l.add(DataType.toType(codec.decodeOne(cb))); + l.add(DataType.toType(codec.decodeOne(cb))); + return l; default: return null; } @@ -88,6 +105,17 @@ public enum DataType implements OptionCodec.Codecable assert value instanceof String; cb.writeBytes(CBUtil.stringToCB((String)value)); break; + case LIST: + cb.writeBytes(codec.encodeOne(DataType.fromType((AbstractType)value))); + break; + case SET: + cb.writeBytes(codec.encodeOne(DataType.fromType((AbstractType)value))); + break; + case MAP: + List l = (List)value; + cb.writeBytes(codec.encodeOne(DataType.fromType(l.get(0)))); + cb.writeBytes(codec.encodeOne(DataType.fromType(l.get(1)))); + break; } } @@ -97,6 +125,15 @@ public enum DataType implements OptionCodec.Codecable { case CUSTOM: return 2 + ((String)value).getBytes(Charsets.UTF_8).length; + case LIST: + case SET: + return codec.oneSerializedSize(DataType.fromType((AbstractType)value)); + case MAP: + List l = (List)value; + int s = 0; + s += codec.oneSerializedSize(DataType.fromType(l.get(0))); + s += codec.oneSerializedSize(DataType.fromType(l.get(1))); + return s; default: return 0; } @@ -106,19 +143,50 @@ public enum DataType implements OptionCodec.Codecable { DataType dt = dataTypeMap.get(type); if (dt == null) + { + if (type.isCollection()) + { + if (type instanceof ListType) + { + return Pair.create(LIST, ((ListType)type).elements); + } + else if (type instanceof MapType) + { + MapType mt = (MapType)type; + return Pair.create(MAP, Arrays.asList(mt.keys, mt.values)); + } + else + { + assert type instanceof SetType; + return Pair.create(LIST, ((SetType)type).elements); + } + } return Pair.create(CUSTOM, type.toString()); + } else + { return Pair.create(dt, null); + } } public static AbstractType toType(Pair entry) { try { - if (entry.left == CUSTOM) - return TypeParser.parse((String)entry.right); - else - return entry.left.type; + switch (entry.left) + { + case CUSTOM: + return TypeParser.parse((String)entry.right); + case LIST: + return ListType.getInstance((AbstractType)entry.right); + case SET: + return SetType.getInstance((AbstractType)entry.right); + case MAP: + List l = (List)entry.right; + return MapType.getInstance(l.get(0), l.get(1)); + default: + return entry.left.type; + } } catch (ConfigurationException e) { diff --git a/src/java/org/apache/cassandra/transport/OptionCodec.java b/src/java/org/apache/cassandra/transport/OptionCodec.java index f5e702f1b2..7652c24eed 100644 --- a/src/java/org/apache/cassandra/transport/OptionCodec.java +++ b/src/java/org/apache/cassandra/transport/OptionCodec.java @@ -109,11 +109,17 @@ public class OptionCodec & OptionCodec.Codecable> T opt = option.left; Object obj = option.right; - int l = 2 + opt.serializedValueSize(obj); - ChannelBuffer cb = ChannelBuffers.buffer(l); + ChannelBuffer cb = ChannelBuffers.buffer(oneSerializedSize(option)); cb.writeShort(opt.getId()); opt.writeValue(obj, cb); return cb; } + + public int oneSerializedSize(Pair option) + { + T opt = option.left; + Object obj = option.right; + return 2 + opt.serializedValueSize(obj); + } }