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 2016/06/30 09:30:42 UTC
[5/6] cassandra git commit: Merge commit
'e4c344c58f8ca8f69224855080de4ec266fb671e' into cassandra-3.9
Merge commit 'e4c344c58f8ca8f69224855080de4ec266fb671e' into cassandra-3.9
* commit 'e4c344c58f8ca8f69224855080de4ec266fb671e':
Avoid deserialization error after altering column type
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo
Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/1f014b2c
Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/1f014b2c
Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/1f014b2c
Branch: refs/heads/cassandra-3.9
Commit: 1f014b2cac739439bcf97adb34ae5b8ede6d2fed
Parents: c7547e0 e4c344c
Author: Sylvain Lebresne <sy...@datastax.com>
Authored: Thu Jun 30 11:14:48 2016 +0200
Committer: Sylvain Lebresne <sy...@datastax.com>
Committed: Thu Jun 30 11:16:06 2016 +0200
----------------------------------------------------------------------
CHANGES.txt | 2 +
.../apache/cassandra/db/rows/BufferCell.java | 1 -
src/java/org/apache/cassandra/db/rows/Cell.java | 16 +++----
.../cassandra/db/rows/UnfilteredSerializer.java | 30 +++++++++----
.../org/apache/cassandra/cql3/CQLTester.java | 39 +++++++++++++++--
.../cql3/validation/operations/AlterTest.java | 46 +++++++++++++-------
6 files changed, 97 insertions(+), 37 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1f014b2c/CHANGES.txt
----------------------------------------------------------------------
diff --cc CHANGES.txt
index 463cf78,573f704..ed884a9
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@@ -1,35 -1,10 +1,37 @@@
-3.0.9
+3.9
++Merged from 3.0:
+ * Fix EOF exception when altering column type (CASSANDRA-11820)
Merged from 2.2:
* MemoryUtil.getShort() should return an unsigned short also for architectures not supporting unaligned memory accesses (CASSANDRA-11973)
+Merged from 2.1:
+ * Avoid stalling paxos when the paxos state expires (CASSANDRA-12043)
+ * Remove finished incoming streaming connections from MessagingService (CASSANDRA-11854)
+
-3.0.8
- * Fix potential race in schema during new table creation (CASSANDRA-12083)
+3.8
+ * Improve details in compaction log message (CASSANDRA-12080)
+ * Allow unset values in CQLSSTableWriter (CASSANDRA-11911)
+ * Chunk cache to request compressor-compatible buffers if pool space is exhausted (CASSANDRA-11993)
+ * Remove DatabaseDescriptor dependencies from SequentialWriter (CASSANDRA-11579)
+ * Move skip_stop_words filter before stemming (CASSANDRA-12078)
+ * Support seek() in EncryptedFileSegmentInputStream (CASSANDRA-11957)
+ * SSTable tools mishandling LocalPartitioner (CASSANDRA-12002)
+ * When SEPWorker assigned work, set thread name to match pool (CASSANDRA-11966)
+ * Add cross-DC latency metrics (CASSANDRA-11596)
+ * Allow terms in selection clause (CASSANDRA-10783)
+ * Add bind variables to trace (CASSANDRA-11719)
+ * Switch counter shards' clock to timestamps (CASSANDRA-9811)
+ * Introduce HdrHistogram and response/service/wait separation to stress tool (CASSANDRA-11853)
+ * entry-weighers in QueryProcessor should respect partitionKeyBindIndexes field (CASSANDRA-11718)
+ * Support older ant versions (CASSANDRA-11807)
+ * Estimate compressed on disk size when deciding if sstable size limit reached (CASSANDRA-11623)
+ * cassandra-stress profiles should support case sensitive schemas (CASSANDRA-11546)
+ * Remove DatabaseDescriptor dependency from FileUtils (CASSANDRA-11578)
+ * Faster streaming (CASSANDRA-9766)
+ * Add prepared query parameter to trace for "Execute CQL3 prepared query" session (CASSANDRA-11425)
+ * Add repaired percentage metric (CASSANDRA-11503)
+ * Add Change-Data-Capture (CASSANDRA-8844)
+Merged from 3.0:
* cqlsh: fix error handling in rare COPY FROM failure scenario (CASSANDRA-12070)
* Disable autocompaction during drain (CASSANDRA-11878)
* Add a metrics timer to MemtablePool and use it to track time spent blocked on memory in MemtableAllocator (CASSANDRA-11327)
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1f014b2c/src/java/org/apache/cassandra/db/rows/BufferCell.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/rows/BufferCell.java
index d998d69,db0ded5..7bb1f4b
--- a/src/java/org/apache/cassandra/db/rows/BufferCell.java
+++ b/src/java/org/apache/cassandra/db/rows/BufferCell.java
@@@ -125,5 -200,166 +125,4 @@@ public class BufferCell extends Abstrac
{
return EMPTY_SIZE + ObjectSizes.sizeOnHeapExcludingData(value) + (path == null ? 0 : path.unsharedHeapSizeExcludingData());
}
-
- /**
- * The serialization format for cell is:
- * [ flags ][ timestamp ][ deletion time ][ ttl ][ path size ][ path ][ value size ][ value ]
- * [ 1b ][ 8b (vint) ][ 4b (vint) ][ 4b (vint) ][ 4b (vint) ][ arb ][ 4b (vint) ][ arb ]
- *
- * where not all field are always present (in fact, only the [ flags ] are guaranteed to be present). The fields have the following
- * meaning:
- * - [ flags ] is the cell flags. It is a byte for which each bit represents a flag whose meaning is explained below (*_MASK constants)
- * - [ timestamp ] is the cell timestamp. Present unless the cell has the USE_TIMESTAMP_MASK.
- * - [ deletion time]: the local deletion time for the cell. Present if either the cell is deleted (IS_DELETED_MASK)
- * or it is expiring (IS_EXPIRING_MASK) but doesn't have the USE_ROW_TTL_MASK.
- * - [ ttl ]: the ttl for the cell. Present if the row is expiring (IS_EXPIRING_MASK) but doesn't have the
- * USE_ROW_TTL_MASK.
- * - [ value size ] is the size of the [ value ] field. It's present unless either the cell has the HAS_EMPTY_VALUE_MASK, or the value
- * for columns of this type have a fixed length.
- * - [ path size ] is the size of the [ path ] field. Present iff this is the cell of a complex column.
- * - [ value ]: the cell value, unless it has the HAS_EMPTY_VALUE_MASK.
- * - [ path ]: the cell path if the column this is a cell of is complex.
- */
- static class Serializer implements Cell.Serializer
- {
- private final static int IS_DELETED_MASK = 0x01; // Whether the cell is a tombstone or not.
- private final static int IS_EXPIRING_MASK = 0x02; // Whether the cell is expiring.
- private final static int HAS_EMPTY_VALUE_MASK = 0x04; // Wether the cell has an empty value. This will be the case for tombstone in particular.
- private final static int USE_ROW_TIMESTAMP_MASK = 0x08; // Wether the cell has the same timestamp than the row this is a cell of.
- private final static int USE_ROW_TTL_MASK = 0x10; // Wether the cell has the same ttl than the row this is a cell of.
-
- public void serialize(Cell cell, ColumnDefinition column, DataOutputPlus out, LivenessInfo rowLiveness, SerializationHeader header) throws IOException
- {
- assert cell != null;
- boolean hasValue = cell.value().hasRemaining();
- boolean isDeleted = cell.isTombstone();
- boolean isExpiring = cell.isExpiring();
- boolean useRowTimestamp = !rowLiveness.isEmpty() && cell.timestamp() == rowLiveness.timestamp();
- boolean useRowTTL = isExpiring && rowLiveness.isExpiring() && cell.ttl() == rowLiveness.ttl() && cell.localDeletionTime() == rowLiveness.localExpirationTime();
- int flags = 0;
- if (!hasValue)
- flags |= HAS_EMPTY_VALUE_MASK;
-
- if (isDeleted)
- flags |= IS_DELETED_MASK;
- else if (isExpiring)
- flags |= IS_EXPIRING_MASK;
-
- if (useRowTimestamp)
- flags |= USE_ROW_TIMESTAMP_MASK;
- if (useRowTTL)
- flags |= USE_ROW_TTL_MASK;
-
- out.writeByte((byte)flags);
-
- if (!useRowTimestamp)
- header.writeTimestamp(cell.timestamp(), out);
-
- if ((isDeleted || isExpiring) && !useRowTTL)
- header.writeLocalDeletionTime(cell.localDeletionTime(), out);
- if (isExpiring && !useRowTTL)
- header.writeTTL(cell.ttl(), out);
-
- if (column.isComplex())
- column.cellPathSerializer().serialize(cell.path(), out);
-
- if (hasValue)
- header.getType(column).writeValue(cell.value(), out);
- }
-
- public Cell deserialize(DataInputPlus in, LivenessInfo rowLiveness, ColumnDefinition column, SerializationHeader header, SerializationHelper helper) throws IOException
- {
- int flags = in.readUnsignedByte();
- boolean hasValue = (flags & HAS_EMPTY_VALUE_MASK) == 0;
- boolean isDeleted = (flags & IS_DELETED_MASK) != 0;
- boolean isExpiring = (flags & IS_EXPIRING_MASK) != 0;
- boolean useRowTimestamp = (flags & USE_ROW_TIMESTAMP_MASK) != 0;
- boolean useRowTTL = (flags & USE_ROW_TTL_MASK) != 0;
-
- long timestamp = useRowTimestamp ? rowLiveness.timestamp() : header.readTimestamp(in);
-
- int localDeletionTime = useRowTTL
- ? rowLiveness.localExpirationTime()
- : (isDeleted || isExpiring ? header.readLocalDeletionTime(in) : NO_DELETION_TIME);
-
- int ttl = useRowTTL ? rowLiveness.ttl() : (isExpiring ? header.readTTL(in) : NO_TTL);
-
- CellPath path = column.isComplex()
- ? column.cellPathSerializer().deserialize(in)
- : null;
-
- boolean isCounter = localDeletionTime == NO_DELETION_TIME && column.type.isCounter();
-
- ByteBuffer value = ByteBufferUtil.EMPTY_BYTE_BUFFER;
- if (hasValue)
- {
- if (helper.canSkipValue(column) || (path != null && helper.canSkipValue(path)))
- {
- header.getType(column).skipValue(in);
- }
- else
- {
- value = header.getType(column).readValue(in, DatabaseDescriptor.getMaxValueSize());
- if (isCounter)
- value = helper.maybeClearCounterValue(value);
- }
- }
-
- return new BufferCell(column, timestamp, ttl, localDeletionTime, value, path);
- }
-
- public long serializedSize(Cell cell, ColumnDefinition column, LivenessInfo rowLiveness, SerializationHeader header)
- {
- long size = 1; // flags
- boolean hasValue = cell.value().hasRemaining();
- boolean isDeleted = cell.isTombstone();
- boolean isExpiring = cell.isExpiring();
- boolean useRowTimestamp = !rowLiveness.isEmpty() && cell.timestamp() == rowLiveness.timestamp();
- boolean useRowTTL = isExpiring && rowLiveness.isExpiring() && cell.ttl() == rowLiveness.ttl() && cell.localDeletionTime() == rowLiveness.localExpirationTime();
-
- if (!useRowTimestamp)
- size += header.timestampSerializedSize(cell.timestamp());
-
- if ((isDeleted || isExpiring) && !useRowTTL)
- size += header.localDeletionTimeSerializedSize(cell.localDeletionTime());
- if (isExpiring && !useRowTTL)
- size += header.ttlSerializedSize(cell.ttl());
-
- if (column.isComplex())
- size += column.cellPathSerializer().serializedSize(cell.path());
-
- if (hasValue)
- size += header.getType(column).writtenLength(cell.value());
-
- return size;
- }
-
- // Returns if the skipped cell was an actual cell (i.e. it had its presence flag).
- public boolean skip(DataInputPlus in, ColumnDefinition column, SerializationHeader header) throws IOException
- {
- int flags = in.readUnsignedByte();
- boolean hasValue = (flags & HAS_EMPTY_VALUE_MASK) == 0;
- boolean isDeleted = (flags & IS_DELETED_MASK) != 0;
- boolean isExpiring = (flags & IS_EXPIRING_MASK) != 0;
- boolean useRowTimestamp = (flags & USE_ROW_TIMESTAMP_MASK) != 0;
- boolean useRowTTL = (flags & USE_ROW_TTL_MASK) != 0;
-
- if (!useRowTimestamp)
- header.skipTimestamp(in);
-
- if (!useRowTTL && (isDeleted || isExpiring))
- header.skipLocalDeletionTime(in);
-
- if (!useRowTTL && isExpiring)
- header.skipTTL(in);
-
- if (column.isComplex())
- column.cellPathSerializer().skip(in);
-
- if (hasValue)
- header.getType(column).skipValue(in);
--
- return true;
- }
- }
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1f014b2c/src/java/org/apache/cassandra/db/rows/Cell.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/rows/Cell.java
index 0b7c46e,d10cc74..19d1f30
--- a/src/java/org/apache/cassandra/db/rows/Cell.java
+++ b/src/java/org/apache/cassandra/db/rows/Cell.java
@@@ -144,165 -143,15 +144,165 @@@ public abstract class Cell extends Colu
// Overrides super type to provide a more precise return type.
public abstract Cell purge(DeletionPurger purger, int nowInSec);
- public interface Serializer
+ /**
+ * The serialization format for cell is:
+ * [ flags ][ timestamp ][ deletion time ][ ttl ][ path size ][ path ][ value size ][ value ]
+ * [ 1b ][ 8b (vint) ][ 4b (vint) ][ 4b (vint) ][ 4b (vint) ][ arb ][ 4b (vint) ][ arb ]
+ *
+ * where not all field are always present (in fact, only the [ flags ] are guaranteed to be present). The fields have the following
+ * meaning:
+ * - [ flags ] is the cell flags. It is a byte for which each bit represents a flag whose meaning is explained below (*_MASK constants)
+ * - [ timestamp ] is the cell timestamp. Present unless the cell has the USE_TIMESTAMP_MASK.
+ * - [ deletion time]: the local deletion time for the cell. Present if either the cell is deleted (IS_DELETED_MASK)
+ * or it is expiring (IS_EXPIRING_MASK) but doesn't have the USE_ROW_TTL_MASK.
+ * - [ ttl ]: the ttl for the cell. Present if the row is expiring (IS_EXPIRING_MASK) but doesn't have the
+ * USE_ROW_TTL_MASK.
+ * - [ value size ] is the size of the [ value ] field. It's present unless either the cell has the HAS_EMPTY_VALUE_MASK, or the value
+ * for columns of this type have a fixed length.
+ * - [ path size ] is the size of the [ path ] field. Present iff this is the cell of a complex column.
+ * - [ value ]: the cell value, unless it has the HAS_EMPTY_VALUE_MASK.
+ * - [ path ]: the cell path if the column this is a cell of is complex.
+ */
+ static class Serializer
{
- public void serialize(Cell cell, ColumnDefinition column, DataOutputPlus out, LivenessInfo rowLiveness, SerializationHeader header) throws IOException;
+ private final static int IS_DELETED_MASK = 0x01; // Whether the cell is a tombstone or not.
+ private final static int IS_EXPIRING_MASK = 0x02; // Whether the cell is expiring.
+ private final static int HAS_EMPTY_VALUE_MASK = 0x04; // Wether the cell has an empty value. This will be the case for tombstone in particular.
+ private final static int USE_ROW_TIMESTAMP_MASK = 0x08; // Wether the cell has the same timestamp than the row this is a cell of.
+ private final static int USE_ROW_TTL_MASK = 0x10; // Wether the cell has the same ttl than the row this is a cell of.
+
- public void serialize(Cell cell, DataOutputPlus out, LivenessInfo rowLiveness, SerializationHeader header) throws IOException
++ public void serialize(Cell cell, ColumnDefinition column, DataOutputPlus out, LivenessInfo rowLiveness, SerializationHeader header) throws IOException
+ {
+ assert cell != null;
+ boolean hasValue = cell.value().hasRemaining();
+ boolean isDeleted = cell.isTombstone();
+ boolean isExpiring = cell.isExpiring();
+ boolean useRowTimestamp = !rowLiveness.isEmpty() && cell.timestamp() == rowLiveness.timestamp();
+ boolean useRowTTL = isExpiring && rowLiveness.isExpiring() && cell.ttl() == rowLiveness.ttl() && cell.localDeletionTime() == rowLiveness.localExpirationTime();
+ int flags = 0;
+ if (!hasValue)
+ flags |= HAS_EMPTY_VALUE_MASK;
+
+ if (isDeleted)
+ flags |= IS_DELETED_MASK;
+ else if (isExpiring)
+ flags |= IS_EXPIRING_MASK;
+
+ if (useRowTimestamp)
+ flags |= USE_ROW_TIMESTAMP_MASK;
+ if (useRowTTL)
+ flags |= USE_ROW_TTL_MASK;
+
+ out.writeByte((byte)flags);
+
+ if (!useRowTimestamp)
+ header.writeTimestamp(cell.timestamp(), out);
+
+ if ((isDeleted || isExpiring) && !useRowTTL)
+ header.writeLocalDeletionTime(cell.localDeletionTime(), out);
+ if (isExpiring && !useRowTTL)
+ header.writeTTL(cell.ttl(), out);
+
- if (cell.column().isComplex())
- cell.column().cellPathSerializer().serialize(cell.path(), out);
++ if (column.isComplex())
++ column.cellPathSerializer().serialize(cell.path(), out);
+
+ if (hasValue)
- header.getType(cell.column()).writeValue(cell.value(), out);
++ header.getType(column).writeValue(cell.value(), out);
+ }
+
+ public Cell deserialize(DataInputPlus in, LivenessInfo rowLiveness, ColumnDefinition column, SerializationHeader header, SerializationHelper helper) throws IOException
+ {
+ int flags = in.readUnsignedByte();
+ boolean hasValue = (flags & HAS_EMPTY_VALUE_MASK) == 0;
+ boolean isDeleted = (flags & IS_DELETED_MASK) != 0;
+ boolean isExpiring = (flags & IS_EXPIRING_MASK) != 0;
+ boolean useRowTimestamp = (flags & USE_ROW_TIMESTAMP_MASK) != 0;
+ boolean useRowTTL = (flags & USE_ROW_TTL_MASK) != 0;
+
+ long timestamp = useRowTimestamp ? rowLiveness.timestamp() : header.readTimestamp(in);
+
+ int localDeletionTime = useRowTTL
+ ? rowLiveness.localExpirationTime()
+ : (isDeleted || isExpiring ? header.readLocalDeletionTime(in) : NO_DELETION_TIME);
+
+ int ttl = useRowTTL ? rowLiveness.ttl() : (isExpiring ? header.readTTL(in) : NO_TTL);
- public Cell deserialize(DataInputPlus in, LivenessInfo rowLiveness, ColumnDefinition column, SerializationHeader header, SerializationHelper helper) throws IOException;
+ CellPath path = column.isComplex()
+ ? column.cellPathSerializer().deserialize(in)
+ : null;
- public long serializedSize(Cell cell, ColumnDefinition column, LivenessInfo rowLiveness, SerializationHeader header);
+ ByteBuffer value = ByteBufferUtil.EMPTY_BYTE_BUFFER;
+ if (hasValue)
+ {
+ if (helper.canSkipValue(column) || (path != null && helper.canSkipValue(path)))
+ {
+ header.getType(column).skipValue(in);
+ }
+ else
+ {
+ boolean isCounter = localDeletionTime == NO_DELETION_TIME && column.type.isCounter();
+
+ value = header.getType(column).readValue(in, DatabaseDescriptor.getMaxValueSize());
+ if (isCounter)
+ value = helper.maybeClearCounterValue(value);
+ }
+ }
+
+ return new BufferCell(column, timestamp, ttl, localDeletionTime, value, path);
+ }
+
- public long serializedSize(Cell cell, LivenessInfo rowLiveness, SerializationHeader header)
++ public long serializedSize(Cell cell, ColumnDefinition column, LivenessInfo rowLiveness, SerializationHeader header)
+ {
+ long size = 1; // flags
+ boolean hasValue = cell.value().hasRemaining();
+ boolean isDeleted = cell.isTombstone();
+ boolean isExpiring = cell.isExpiring();
+ boolean useRowTimestamp = !rowLiveness.isEmpty() && cell.timestamp() == rowLiveness.timestamp();
+ boolean useRowTTL = isExpiring && rowLiveness.isExpiring() && cell.ttl() == rowLiveness.ttl() && cell.localDeletionTime() == rowLiveness.localExpirationTime();
+
+ if (!useRowTimestamp)
+ size += header.timestampSerializedSize(cell.timestamp());
+
+ if ((isDeleted || isExpiring) && !useRowTTL)
+ size += header.localDeletionTimeSerializedSize(cell.localDeletionTime());
+ if (isExpiring && !useRowTTL)
+ size += header.ttlSerializedSize(cell.ttl());
+
- if (cell.column().isComplex())
- size += cell.column().cellPathSerializer().serializedSize(cell.path());
++ if (column.isComplex())
++ size += column.cellPathSerializer().serializedSize(cell.path());
+
+ if (hasValue)
- size += header.getType(cell.column()).writtenLength(cell.value());
++ size += header.getType(column).writtenLength(cell.value());
+
+ return size;
+ }
// Returns if the skipped cell was an actual cell (i.e. it had its presence flag).
- public boolean skip(DataInputPlus in, ColumnDefinition column, SerializationHeader header) throws IOException;
+ public boolean skip(DataInputPlus in, ColumnDefinition column, SerializationHeader header) throws IOException
+ {
+ int flags = in.readUnsignedByte();
+ boolean hasValue = (flags & HAS_EMPTY_VALUE_MASK) == 0;
+ boolean isDeleted = (flags & IS_DELETED_MASK) != 0;
+ boolean isExpiring = (flags & IS_EXPIRING_MASK) != 0;
+ boolean useRowTimestamp = (flags & USE_ROW_TIMESTAMP_MASK) != 0;
+ boolean useRowTTL = (flags & USE_ROW_TTL_MASK) != 0;
+
+ if (!useRowTimestamp)
+ header.skipTimestamp(in);
+
+ if (!useRowTTL && (isDeleted || isExpiring))
+ header.skipLocalDeletionTime(in);
+
+ if (!useRowTTL && isExpiring)
+ header.skipTTL(in);
+
+ if (column.isComplex())
+ column.cellPathSerializer().skip(in);
+
+ if (hasValue)
+ header.getType(column).skipValue(in);
+
+ return true;
+ }
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1f014b2c/src/java/org/apache/cassandra/db/rows/UnfilteredSerializer.java
----------------------------------------------------------------------
diff --cc src/java/org/apache/cassandra/db/rows/UnfilteredSerializer.java
index 890806c,dc6f187..5ca7e03
--- a/src/java/org/apache/cassandra/db/rows/UnfilteredSerializer.java
+++ b/src/java/org/apache/cassandra/db/rows/UnfilteredSerializer.java
@@@ -25,8 -24,8 +25,9 @@@ import net.nicoulaj.compilecommand.anno
import org.apache.cassandra.config.ColumnDefinition;
import org.apache.cassandra.db.*;
import org.apache.cassandra.io.util.DataInputPlus;
+import org.apache.cassandra.io.util.DataOutputBuffer;
import org.apache.cassandra.io.util.DataOutputPlus;
+ import org.apache.cassandra.utils.SearchIterator;
/**
* Serialize/deserialize a single Unfiltered (both on-wire and on-disk).
@@@ -222,15 -175,24 +223,24 @@@ public class UnfilteredSerialize
if ((flags & HAS_DELETION) != 0)
header.writeDeletionTime(deletion.time(), out);
- if (!hasAllColumns)
+ if ((flags & HAS_ALL_COLUMNS) == 0)
Columns.serializer.serializeSubset(Collections2.transform(row, ColumnData::column), headerColumns, out);
+ SearchIterator<ColumnDefinition, ColumnDefinition> si = headerColumns.iterator();
for (ColumnData data : row)
{
+ // We can obtain the column for data directly from data.column(). However, if the cell/complex data
+ // originates from a sstable, the column we'll get will have the type used when the sstable was serialized,
+ // and if that type have been recently altered, that may not be the type we want to serialize the column
+ // with. So we use the ColumnDefinition from the "header" which is "current". Also see #11810 for what
+ // happens if we don't do that.
+ ColumnDefinition column = si.next(data.column());
+ assert column != null;
+
if (data.column.isSimple())
- Cell.serializer.serialize((Cell) data, out, pkLiveness, header);
+ Cell.serializer.serialize((Cell) data, column, out, pkLiveness, header);
else
- writeComplexColumn((ComplexColumnData) data, (flags & HAS_COMPLEX_DELETION) != 0, pkLiveness, header, out);
- writeComplexColumn((ComplexColumnData) data, column, hasComplexDeletion, pkLiveness, header, out);
++ writeComplexColumn((ComplexColumnData) data, column, (flags & HAS_COMPLEX_DELETION) != 0, pkLiveness, header, out);
}
}
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1f014b2c/test/unit/org/apache/cassandra/cql3/CQLTester.java
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cassandra/blob/1f014b2c/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
----------------------------------------------------------------------
diff --cc test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
index 3eb55fd,509aeac..bb4bf48
--- a/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
+++ b/test/unit/org/apache/cassandra/cql3/validation/operations/AlterTest.java
@@@ -325,84 -323,19 +323,100 @@@ public class AlterTest extends CQLTeste
assertInvalidThrow(InvalidRequestException.class, "ALTER TABLE %s ALTER column1 TYPE ascii");
}
+ /*
+ * Test case to check addition of one column
+ */
+ @Test
+ public void testAlterAddOneColumn() throws Throwable
+ {
+ createTable("CREATE TABLE IF NOT EXISTS %s (id int, name text, PRIMARY KEY (id))");
+ alterTable("ALTER TABLE %s add mail text;");
+
+ assertColumnNames(execute("SELECT * FROM %s"), "id", "mail", "name");
+ }
+
+ /*
+ * Test case to check addition of more than one column
+ */
+ @Test
+ public void testAlterAddMultiColumn() throws Throwable
+ {
+ createTable("CREATE TABLE IF NOT EXISTS %s (id int, yearofbirth int, PRIMARY KEY (id))");
+ alterTable("ALTER TABLE %s add (firstname text, password blob, lastname text, \"SOME escaped col\" bigint)");
+
+ assertColumnNames(execute("SELECT * FROM %s"), "id", "SOME escaped col", "firstname", "lastname", "password", "yearofbirth");
+ }
+
+ /*
+ * Should throw SyntaxException if multiple columns are added using wrong syntax.
+ * Expected Syntax : Alter table T1 add (C1 datatype,C2 datatype,C3 datatype)
+ */
+ @Test(expected = SyntaxException.class)
+ public void testAlterAddMultiColumnWithoutBraces() throws Throwable
+ {
+ execute("ALTER TABLE %s.users add lastname text, password blob, yearofbirth int;");
+ }
+
+ /*
+ * Test case to check deletion of one column
+ */
+ @Test
+ public void testAlterDropOneColumn() throws Throwable
+ {
+ createTable("CREATE TABLE IF NOT EXISTS %s (id text, telephone int, yearofbirth int, PRIMARY KEY (id))");
+ alterTable("ALTER TABLE %s drop telephone");
+
+ assertColumnNames(execute("SELECT * FROM %s"), "id", "yearofbirth");
+ }
+
+ @Test
+ /*
+ * Test case to check deletion of more than one column
+ */
+ public void testAlterDropMultiColumn() throws Throwable
+ {
+ createTable("CREATE TABLE IF NOT EXISTS %s (id text, address text, telephone int, yearofbirth int, \"SOME escaped col\" bigint, PRIMARY KEY (id))");
+ alterTable("ALTER TABLE %s drop (address, telephone, \"SOME escaped col\");");
+
+ assertColumnNames(execute("SELECT * FROM %s"), "id", "yearofbirth");
+ }
+
+ /*
+ * Should throw SyntaxException if multiple columns are dropped using wrong syntax.
+ */
+ @Test(expected = SyntaxException.class)
+ public void testAlterDeletionColumnWithoutBraces() throws Throwable
+ {
+ execute("ALTER TABLE %s.users drop name,address;");
+ }
+
+ @Test(expected = InvalidRequestException.class)
+ public void testAlterAddDuplicateColumn() throws Throwable
+ {
+ createTable("CREATE TABLE IF NOT EXISTS %s (id text, address text, telephone int, yearofbirth int, PRIMARY KEY (id))");
+ execute("ALTER TABLE %s add (salary int, salary int);");
+ }
+
+ @Test(expected = InvalidRequestException.class)
+ public void testAlterDropDuplicateColumn() throws Throwable
+ {
+ createTable("CREATE TABLE IF NOT EXISTS %s (id text, address text, telephone int, yearofbirth int, PRIMARY KEY (id))");
+ execute("ALTER TABLE %s drop (address, address);");
+ }
++
+ @Test
+ public void testAlterToBlob() throws Throwable
+ {
+ // This tests for the bug from #11820 in particular
+
+ createTable("CREATE TABLE %s (a int PRIMARY KEY, b int)");
+
+ execute("INSERT INTO %s (a, b) VALUES (1, 1)");
+
+ executeNet(Server.CURRENT_VERSION, "ALTER TABLE %s ALTER b TYPE BLOB");
+
+ assertRowsNet(Server.CURRENT_VERSION, executeNet(Server.CURRENT_VERSION, "SELECT * FROM %s WHERE a = 1"),
+ row(1, ByteBufferUtil.bytes(1))
+ );
+ }
}