From 9e0efa3dbbeddf382c8e0f45cfdf2ebb91bc9db0 Mon Sep 17 00:00:00 2001 From: Jonathan Ellis Date: Thu, 8 Aug 2013 15:33:39 -0500 Subject: [PATCH 1/2] Correctly validate sparse composite cells patch by Tyler Hobbs; reviewed by jbellis for CASSANDRA-5855 --- CHANGES.txt | 2 ++ src/java/org/apache/cassandra/db/Column.java | 19 ++++++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/CHANGES.txt b/CHANGES.txt index 859e7f90d7..30ce976ef7 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -13,6 +13,8 @@ * Future-proof inter-major-version schema migrations (CASSANDRA-5845) * (Hadoop) add CqlPagingRecordReader support for ReversedType in Thrift table (CASSANDRA-5718) +Merged from 1.1: + * Correctly validate sparse composite cells in scrub (CASSANDRA-5855) 1.2.8 diff --git a/src/java/org/apache/cassandra/db/Column.java b/src/java/org/apache/cassandra/db/Column.java index 616f3c0ac7..7b614f51c9 100644 --- a/src/java/org/apache/cassandra/db/Column.java +++ b/src/java/org/apache/cassandra/db/Column.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.List; import org.apache.cassandra.config.CFMetaData; +import org.apache.cassandra.cql3.CFDefinition; import org.apache.cassandra.db.marshal.*; import org.apache.cassandra.io.util.DataOutputBuffer; import org.apache.cassandra.utils.Allocator; @@ -287,7 +288,23 @@ public class Column implements IColumn public void validateFields(CFMetaData metadata) throws MarshalException { validateName(metadata); - AbstractType valueValidator = metadata.getValueValidator(name()); + CFDefinition cfdef = metadata.getCfDef(); + + // If this is a CQL table, we need to pull out the CQL column name to look up the correct column type. + // (Note that COMPACT composites are handled by validateName, above.) + ByteBuffer internalName; + if (cfdef.isComposite && !cfdef.isCompact) + { + AbstractCompositeType comparator = (AbstractCompositeType) metadata.comparator; + List components = comparator.deconstruct(name); + internalName = components.get(components.size() - 1).value; + } + else + { + internalName = name; + } + + AbstractType valueValidator = metadata.getValueValidator(internalName); if (valueValidator != null) valueValidator.validate(value()); } From 73b0ffba82f431d6fca2a876504fe9f0631ef0a6 Mon Sep 17 00:00:00 2001 From: Jonathan Ellis Date: Thu, 8 Aug 2013 17:06:56 -0500 Subject: [PATCH 2/2] make scrubbing collection-aware --- src/java/org/apache/cassandra/db/Column.java | 13 +++------- .../cassandra/db/marshal/CompositeType.java | 24 +++++++++++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/java/org/apache/cassandra/db/Column.java b/src/java/org/apache/cassandra/db/Column.java index 7b614f51c9..632392f740 100644 --- a/src/java/org/apache/cassandra/db/Column.java +++ b/src/java/org/apache/cassandra/db/Column.java @@ -293,16 +293,9 @@ public class Column implements IColumn // If this is a CQL table, we need to pull out the CQL column name to look up the correct column type. // (Note that COMPACT composites are handled by validateName, above.) ByteBuffer internalName; - if (cfdef.isComposite && !cfdef.isCompact) - { - AbstractCompositeType comparator = (AbstractCompositeType) metadata.comparator; - List components = comparator.deconstruct(name); - internalName = components.get(components.size() - 1).value; - } - else - { - internalName = name; - } + internalName = (cfdef.isComposite && !cfdef.isCompact) + ? ((CompositeType) metadata.comparator).extractLastComponent(name) + : name; AbstractType valueValidator = metadata.getValueValidator(internalName); if (valueValidator != null) diff --git a/src/java/org/apache/cassandra/db/marshal/CompositeType.java b/src/java/org/apache/cassandra/db/marshal/CompositeType.java index 522be13f39..2a27617f0b 100644 --- a/src/java/org/apache/cassandra/db/marshal/CompositeType.java +++ b/src/java/org/apache/cassandra/db/marshal/CompositeType.java @@ -124,6 +124,30 @@ public class CompositeType extends AbstractCompositeType return build(serialized); } + // Extract component idx from bb. Return null if there is not enough component. + public static ByteBuffer extractComponent(ByteBuffer bb, int idx) + { + bb = bb.duplicate(); + int i = 0; + while (bb.remaining() > 0) + { + ByteBuffer c = getWithShortLength(bb); + if (i == idx) + return c; + + bb.get(); // skip end-of-component + ++i; + } + return null; + } + + // Extract CQL3 column name from the full column name. + public ByteBuffer extractLastComponent(ByteBuffer bb) + { + int idx = types.get(types.size() - 1) instanceof ColumnToCollectionType ? types.size() - 2 : types.size() - 1; + return extractComponent(bb, idx); + } + @Override public boolean isCompatibleWith(AbstractType previous) {