Merge branch 'cassandra-2.0' into cassandra-2.1 Conflicts: src/java/org/apache/cassandra/config/CFMetaData.java src/java/org/apache/cassandra/config/Schema.java src/java/org/apache/cassandra/cql/QueryProcessor.java src/java/org/apache/cassandra/cql/SelectStatement.java src/java/org/apache/cassandra/cql/UpdateStatement.java src/java/org/apache/cassandra/db/Column.java src/java/org/apache/cassandra/thrift/ThriftValidation.java src/java/org/apache/cassandra/tools/SSTableExport.java src/java/org/apache/cassandra/tools/SSTableImport.java test/unit/org/apache/cassandra/SchemaLoader.java test/unit/org/apache/cassandra/db/ScrubTest.java test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java test/unit/org/apache/cassandra/tools/SSTableExportTest.java
Project: http://git-wip-us.apache.org/repos/asf/cassandra/repo Commit: http://git-wip-us.apache.org/repos/asf/cassandra/commit/8afe1090 Tree: http://git-wip-us.apache.org/repos/asf/cassandra/tree/8afe1090 Diff: http://git-wip-us.apache.org/repos/asf/cassandra/diff/8afe1090 Branch: refs/heads/trunk Commit: 8afe1090bc4d04346197be6aa696b3af174f3674 Parents: 92b40fd b42feea Author: Sylvain Lebresne <sylv...@datastax.com> Authored: Wed Apr 2 14:01:43 2014 +0200 Committer: Sylvain Lebresne <sylv...@datastax.com> Committed: Wed Apr 2 14:01:43 2014 +0200 ---------------------------------------------------------------------- CHANGES.txt | 1 + .../org/apache/cassandra/config/CFMetaData.java | 39 +++++------- .../cassandra/config/ColumnDefinition.java | 9 +++ .../apache/cassandra/cql/QueryProcessor.java | 2 +- .../apache/cassandra/cql3/QueryProcessor.java | 4 +- .../cassandra/thrift/ThriftValidation.java | 5 +- .../apache/cassandra/tools/SSTableImport.java | 2 +- .../unit/org/apache/cassandra/SchemaLoader.java | 7 ++- .../unit/org/apache/cassandra/db/ScrubTest.java | 65 ++++++++++++++++++++ .../cassandra/thrift/ThriftValidationTest.java | 53 ++++++++++++++-- .../cassandra/tools/SSTableExportTest.java | 35 +++++++++++ 11 files changed, 188 insertions(+), 34 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/CHANGES.txt ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/src/java/org/apache/cassandra/config/CFMetaData.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/config/CFMetaData.java index b46fafd,be18d1b..e930de4 --- a/src/java/org/apache/cassandra/config/CFMetaData.java +++ b/src/java/org/apache/cassandra/config/CFMetaData.java @@@ -919,25 -853,13 +919,10 @@@ public final class CFMetaDat .toHashCode(); } - public AbstractType<?> getValueValidator(CellName name) - /** - * Like getColumnDefinitionFromColumnName, the argument must be an internal column/cell name. - */ - public AbstractType<?> getValueValidatorFromColumnName(ByteBuffer columnName) ++ public AbstractType<?> getValueValidator(CellName cellName) { - return getValueValidator(getColumnDefinition(name)); - } - - public AbstractType<?> getValueValidatorForFullCellName(ByteBuffer name) - { - // If this is a CQL table, we need to pull out the CQL column name to look up the correct column type. - if (!isCQL3Table()) - return getValueValidator(getColumnDefinition(name)); - - return getValueValidator(getColumnDefinition(comparator.cellFromByteBuffer(name))); - } - - public AbstractType<?> getValueValidator(ColumnDefinition columnDefinition) - { - return columnDefinition == null - ? defaultValidator - : columnDefinition.type; - ColumnDefinition def = getColumnDefinitionFromColumnName(columnName); - return def == null ? defaultValidator : def.getValidator(); ++ ColumnDefinition def = getColumnDefinition(cellName); ++ return def == null ? defaultValidator : def.type; } /** applies implicit defaults to cf definition. useful in updates */ @@@ -1312,14 -1201,46 +1297,24 @@@ } /** - * Returns a ColumnDefinition given a full (internal) column name. + * Returns a ColumnDefinition given a cell name. */ - public ColumnDefinition getColumnDefinitionFromColumnName(ByteBuffer columnName) + public ColumnDefinition getColumnDefinition(CellName cellName) { - if (!isSuper() && (comparator instanceof CompositeType)) - { - CompositeType composite = (CompositeType)comparator; - ByteBuffer[] components = composite.split(columnName); - for (ColumnDefinition def : regularAndStaticColumns()) - { - ByteBuffer toCompare; - if (def.componentIndex == null) - { - toCompare = columnName; - } - else - { - if (def.componentIndex >= components.length) - break; + ColumnIdentifier id = cellName.cql3ColumnName(); - return id == null - ? getColumnDefinition(cellName.toByteBuffer()) // Means a dense layout, try the full column name - : getColumnDefinition(id); ++ ColumnDefinition def = id == null ++ ? getColumnDefinition(cellName.toByteBuffer()) // Means a dense layout, try the full column name ++ : getColumnDefinition(id); + - toCompare = components[def.componentIndex]; - } - if (def.name.equals(toCompare)) - return def; - } - return null; - } - else - { - ColumnDefinition def = column_metadata.get(columnName); - // It's possible that the def is a PRIMARY KEY or COMPACT_VALUE one in case a concrete cell - // name conflicts with a CQL column name, which can happen in 2 cases: - // 1) because the user inserted a cell through Thrift that conflicts with a default "alias" used - // by CQL for thrift tables (see #6892). - // 2) for COMPACT STORAGE tables with a single utf8 clustering column, the cell name can be anything, - // including a CQL column name (without this being a problem). - // In any case, this is fine, this just mean that columnDefinition is not the ColumnDefinition we are - // looking for. - return def != null && def.isPartOfCellName() ? def : null; - } ++ // It's possible that the def is a PRIMARY KEY or COMPACT_VALUE one in case a concrete cell ++ // name conflicts with a CQL column name, which can happen in 2 cases: ++ // 1) because the user inserted a cell through Thrift that conflicts with a default "alias" used ++ // by CQL for thrift tables (see #6892). ++ // 2) for COMPACT STORAGE tables with a single utf8 clustering column, the cell name can be anything, ++ // including a CQL column name (without this being a problem). ++ // In any case, this is fine, this just mean that columnDefinition is not the ColumnDefinition we are ++ // looking for. ++ return def != null && def.isPartOfCellName() ? def : null; } public ColumnDefinition getColumnDefinitionForIndex(String indexName) @@@ -1930,18 -1850,18 +1925,18 @@@ droppedColumns.put(def.name, FBUtilities.timestampMicros()); } - public void renameColumn(ByteBuffer from, String strFrom, ByteBuffer to, String strTo) throws InvalidRequestException + public void renameColumn(ColumnIdentifier from, ColumnIdentifier to) throws InvalidRequestException { - ColumnDefinition def = column_metadata.get(from); + ColumnDefinition def = getColumnDefinition(from); if (def == null) - throw new InvalidRequestException(String.format("Cannot rename unknown column %s in keyspace %s", strFrom, cfName)); + throw new InvalidRequestException(String.format("Cannot rename unknown column %s in keyspace %s", from, cfName)); - if (column_metadata.get(to) != null) - throw new InvalidRequestException(String.format("Cannot rename column %s to %s in keyspace %s; another column of that name already exist", strFrom, strTo, cfName)); + if (getColumnDefinition(to) != null) + throw new InvalidRequestException(String.format("Cannot rename column %s to %s in keyspace %s; another column of that name already exist", from, to, cfName)); - if (def.kind == ColumnDefinition.Kind.REGULAR || def.kind == ColumnDefinition.Kind.STATIC) + if (def.isPartOfCellName()) { - throw new InvalidRequestException(String.format("Cannot rename non PRIMARY KEY part %s", strFrom)); + throw new InvalidRequestException(String.format("Cannot rename non PRIMARY KEY part %s", from)); } else if (def.isIndexed()) { http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/src/java/org/apache/cassandra/config/ColumnDefinition.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/config/ColumnDefinition.java index bb1dd71,1223db8..ee8884e --- a/src/java/org/apache/cassandra/config/ColumnDefinition.java +++ b/src/java/org/apache/cassandra/config/ColumnDefinition.java @@@ -243,6 -193,15 +243,15 @@@ public class ColumnDefinition extends C return thriftDefs; } + /** + * Whether the name of this definition is serialized in the cell nane, i.e. whether + * it's not just a non-stored CQL metadata. + */ + public boolean isPartOfCellName() + { - return type == Type.REGULAR || type == Type.STATIC; ++ return kind == Kind.REGULAR || kind == Kind.STATIC; + } + public ColumnDef toThrift() { ColumnDef cd = new ColumnDef(); http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/src/java/org/apache/cassandra/cql/QueryProcessor.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/cql/QueryProcessor.java index 458f131,f160374..baf89b2 --- a/src/java/org/apache/cassandra/cql/QueryProcessor.java +++ b/src/java/org/apache/cassandra/cql/QueryProcessor.java @@@ -189,11 -189,11 +189,11 @@@ public class QueryProcesso for (Relation columnRelation : columnRelations) { // Left and right side of relational expression encoded according to comparator/validator. - ByteBuffer entity = columnRelation.getEntity().getByteBuffer(metadata.comparator, variables); - ByteBuffer value = columnRelation.getValue().getByteBuffer(metadata.getValueValidatorFromColumnName(entity), variables); + ByteBuffer entity = columnRelation.getEntity().getByteBuffer(metadata.comparator.asAbstractType(), variables); - ByteBuffer value = columnRelation.getValue().getByteBuffer(metadata.getValueValidatorForFullCellName(entity), variables); ++ ByteBuffer value = columnRelation.getValue().getByteBuffer(metadata.getValueValidator(metadata.comparator.cellFromByteBuffer(entity)), variables); expressions.add(new IndexExpression(entity, - IndexOperator.valueOf(columnRelation.operator().toString()), + IndexExpression.Operator.valueOf(columnRelation.operator().toString()), value)); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/src/java/org/apache/cassandra/cql3/QueryProcessor.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/src/java/org/apache/cassandra/thrift/ThriftValidation.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/thrift/ThriftValidation.java index 49cf39b,b387871..222a904 --- a/src/java/org/apache/cassandra/thrift/ThriftValidation.java +++ b/src/java/org/apache/cassandra/thrift/ThriftValidation.java @@@ -439,13 -443,9 +439,12 @@@ public class ThriftValidatio if (!column.isSetTimestamp()) throw new org.apache.cassandra.exceptions.InvalidRequestException("Column timestamp is required"); + CellName cn = scName == null + ? metadata.comparator.cellFromByteBuffer(column.name) + : metadata.comparator.makeCellName(scName, column.name); - ColumnDefinition columnDef = metadata.getColumnDefinition(cn); try { - AbstractType<?> validator = metadata.getValueValidator(columnDef); - AbstractType<?> validator = metadata.getValueValidatorFromColumnName(column.name); ++ AbstractType<?> validator = metadata.getValueValidator(cn); if (validator != null) validator.validate(column.value); } @@@ -462,10 -462,10 +461,10 @@@ } // Indexed column values cannot be larger than 64K. See CASSANDRA-3057/4240 for more details - if (!Keyspace.open(metadata.ksName).getColumnFamilyStore(metadata.cfName).indexManager.validate(asDBColumn(column))) + if (!Keyspace.open(metadata.ksName).getColumnFamilyStore(metadata.cfName).indexManager.validate(asDBColumn(cn, column))) throw new org.apache.cassandra.exceptions.InvalidRequestException(String.format("Can't index column value of size %d for index %s in CF %s of KS %s", column.value.remaining(), - columnDef.getIndexName(), - metadata.getColumnDefinitionFromColumnName(column.name).getIndexName(), ++ metadata.getColumnDefinition(cn).getIndexName(), metadata.cfName, metadata.ksName)); } http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/src/java/org/apache/cassandra/tools/SSTableImport.java ---------------------------------------------------------------------- diff --cc src/java/org/apache/cassandra/tools/SSTableImport.java index 2a516a4,11bfc81..c0d8e00 --- a/src/java/org/apache/cassandra/tools/SSTableImport.java +++ b/src/java/org/apache/cassandra/tools/SSTableImport.java @@@ -162,7 -161,7 +162,7 @@@ public class SSTableImpor } else { - value = stringAsType((String) fields.get(1), meta.getValueValidatorForFullCellName(name)); - value = stringAsType((String) fields.get(1), meta.getValueValidatorFromColumnName(name)); ++ value = stringAsType((String) fields.get(1), meta.getValueValidator(meta.comparator.cellFromByteBuffer(name))); } } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/test/unit/org/apache/cassandra/SchemaLoader.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/SchemaLoader.java index 5fb5697,daff0de..43a6dc3 --- a/test/unit/org/apache/cassandra/SchemaLoader.java +++ b/test/unit/org/apache/cassandra/SchemaLoader.java @@@ -147,12 -167,31 +147,13 @@@ public class SchemaLoade superCFMD(ks1, "Super6", LexicalUUIDType.instance, UTF8Type.instance), indexCFMD(ks1, "Indexed1", true), indexCFMD(ks1, "Indexed2", false), - new CFMetaData(ks1, - "StandardInteger1", - st, - IntegerType.instance, - null), - new CFMetaData(ks1, - "StandardLong3", - st, - LongType.instance, - null), - new CFMetaData(ks1, - "Counter1", - st, - bytes, - null) - .defaultValidator(CounterColumnType.instance), - new CFMetaData(ks1, - "SuperCounter1", - su, - bytes, - bytes) - .defaultValidator(CounterColumnType.instance), + CFMetaData.denseCFMetaData(ks1, "StandardInteger1", IntegerType.instance), ++ CFMetaData.denseCFMetaData(ks1, "StandardLong3", IntegerType.instance), + CFMetaData.denseCFMetaData(ks1, "Counter1", bytes).defaultValidator(CounterColumnType.instance), + CFMetaData.denseCFMetaData(ks1, "SuperCounter1", bytes, bytes).defaultValidator(CounterColumnType.instance), superCFMD(ks1, "SuperDirectGC", BytesType.instance).gcGraceSeconds(0), - jdbcCFMD(ks1, "JdbcInteger", IntegerType.instance).columnMetadata(integerColumn), - jdbcCFMD(ks1, "JdbcUtf8", UTF8Type.instance).columnMetadata(utf8Column), + jdbcSparseCFMD(ks1, "JdbcInteger", IntegerType.instance).addColumnDefinition(integerColumn(ks1, "JdbcInteger")), + jdbcSparseCFMD(ks1, "JdbcUtf8", UTF8Type.instance).addColumnDefinition(utf8Column(ks1, "JdbcUtf8")), jdbcCFMD(ks1, "JdbcLong", LongType.instance), jdbcCFMD(ks1, "JdbcBytes", bytes), jdbcCFMD(ks1, "JdbcAscii", AsciiType.instance), @@@ -165,10 -216,17 +166,14 @@@ standardCFMD(ks1, "legacyleveled") .compactionStrategyClass(LeveledCompactionStrategy.class) .compactionStrategyOptions(leveledOptions), + standardCFMD(ks1, "StandardLowIndexInterval").minIndexInterval(8) + .maxIndexInterval(256) - .caching(CachingOptions.NONE))); ++ .caching(CachingOptions.NONE), + + standardCFMD(ks1, "UUIDKeys").keyValidator(UUIDType.instance), - new CFMetaData(ks1, - "MixedTypes", - st, - LongType.instance, - null).keyValidator(UUIDType.instance).defaultValidator(BooleanType.instance), - new CFMetaData(ks1, - "MixedTypesComposite", - st, - composite, - null).keyValidator(composite).defaultValidator(BooleanType.instance))); ++ CFMetaData.denseCFMetaData(ks1, "MixedTypes", LongType.instance).keyValidator(UUIDType.instance).defaultValidator(BooleanType.instance), ++ CFMetaData.denseCFMetaData(ks1, "MixedTypesComposite", composite).keyValidator(composite).defaultValidator(BooleanType.instance) ++ )); // Keyspace 2 schema.add(KSMetaData.testMetadata(ks2, http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/test/unit/org/apache/cassandra/db/ScrubTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/db/ScrubTest.java index ebdce0e,23e9381..b8c7980 --- a/test/unit/org/apache/cassandra/db/ScrubTest.java +++ b/test/unit/org/apache/cassandra/db/ScrubTest.java @@@ -273,4 -278,63 +279,63 @@@ public class ScrubTest extends SchemaLo cfs.forceBlockingFlush(); } + @Test + public void testScrubColumnValidation() throws InterruptedException, RequestExecutionException, ExecutionException + { + QueryProcessor.process("CREATE TABLE \"Keyspace1\".test_compact_static_columns (a bigint, b timeuuid, c boolean static, d text, PRIMARY KEY (a, b))", ConsistencyLevel.ONE); + + Keyspace keyspace = Keyspace.open("Keyspace1"); + ColumnFamilyStore cfs = keyspace.getColumnFamilyStore("test_compact_static_columns"); + + QueryProcessor.processInternal("INSERT INTO \"Keyspace1\".test_compact_static_columns (a, b, c, d) VALUES (123, c3db07e8-b602-11e3-bc6b-e0b9a54a6d93, true, 'foobar')"); + cfs.forceBlockingFlush(); + CompactionManager.instance.performScrub(cfs, false); + } + + /** + * Tests CASSANDRA-6892 (key aliases being used improperly for validation) + */ + @Test + public void testColumnNameEqualToDefaultKeyAlias() throws ExecutionException, InterruptedException + { + Keyspace keyspace = Keyspace.open("Keyspace1"); + ColumnFamilyStore cfs = keyspace.getColumnFamilyStore("UUIDKeys"); + - ColumnFamily cf = TreeMapBackedSortedColumns.factory.create("Keyspace1", "UUIDKeys"); ++ ColumnFamily cf = ArrayBackedSortedColumns.factory.create("Keyspace1", "UUIDKeys"); + cf.addColumn(column(CFMetaData.DEFAULT_KEY_ALIAS, "not a uuid", 1L)); - RowMutation rm = new RowMutation("Keyspace1", ByteBufferUtil.bytes(UUIDGen.getTimeUUID()), cf); - rm.applyUnsafe(); ++ Mutation mutation = new Mutation("Keyspace1", ByteBufferUtil.bytes(UUIDGen.getTimeUUID()), cf); ++ mutation.applyUnsafe(); + cfs.forceBlockingFlush(); + CompactionManager.instance.performScrub(cfs, false); + + assertEquals(1, cfs.getSSTables().size()); + } + + /** + * For CASSANDRA-6892 too, check that for a compact table with one cluster column, we can insert whatever + * we want as value for the clustering column, including something that would conflict with a CQL column definition. + */ + @Test + public void testValidationCompactStorage() throws Exception + { + QueryProcessor.process("CREATE TABLE \"Keyspace1\".test_compact_dynamic_columns (a int, b text, c text, PRIMARY KEY (a, b)) WITH COMPACT STORAGE", ConsistencyLevel.ONE); + + Keyspace keyspace = Keyspace.open("Keyspace1"); + ColumnFamilyStore cfs = keyspace.getColumnFamilyStore("test_compact_dynamic_columns"); + + QueryProcessor.processInternal("INSERT INTO \"Keyspace1\".test_compact_dynamic_columns (a, b, c) VALUES (0, 'a', 'foo')"); + QueryProcessor.processInternal("INSERT INTO \"Keyspace1\".test_compact_dynamic_columns (a, b, c) VALUES (0, 'b', 'bar')"); + QueryProcessor.processInternal("INSERT INTO \"Keyspace1\".test_compact_dynamic_columns (a, b, c) VALUES (0, 'c', 'boo')"); + cfs.forceBlockingFlush(); + CompactionManager.instance.performScrub(cfs, true); + + // Scrub is silent, but it will remove broken records. So reading everything back to make sure nothing to "scrubbed away" + UntypedResultSet rs = QueryProcessor.processInternal("SELECT * FROM \"Keyspace1\".test_compact_dynamic_columns"); + assertEquals(3, rs.size()); + + Iterator<UntypedResultSet.Row> iter = rs.iterator(); + assertEquals("foo", iter.next().getString("c")); + assertEquals("bar", iter.next().getString("c")); + assertEquals("boo", iter.next().getString("c")); + } } http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java index 05ac588,0e8bbb8..1d47c18 --- a/test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java +++ b/test/unit/org/apache/cassandra/thrift/ThriftValidationTest.java @@@ -46,10 -51,10 +51,10 @@@ public class ThriftValidationTest exten } @Test - public void testColumnNameEqualToKeyAlias() + public void testColumnNameEqualToKeyAlias() throws org.apache.cassandra.exceptions.InvalidRequestException { CFMetaData metaData = Schema.instance.getCFMetaData("Keyspace1", "Standard1"); - CFMetaData newMetadata = metaData.clone(); + CFMetaData newMetadata = metaData.copy(); boolean gotException = false; @@@ -57,7 -62,7 +62,7 @@@ // should not throw IRE here try { - newMetadata.addColumnDefinition(ColumnDefinition.partitionKeyDef(metaData, AsciiType.instance.decompose("id"), UTF8Type.instance, null)); - newMetadata.addColumnDefinition(ColumnDefinition.partitionKeyDef(AsciiType.instance.decompose("id"), LongType.instance, null)); ++ newMetadata.addColumnDefinition(ColumnDefinition.partitionKeyDef(metaData, AsciiType.instance.decompose("id"), LongType.instance, null)); newMetadata.validate(); } catch (ConfigurationException e) @@@ -73,7 -78,7 +78,7 @@@ // add a column with name = "id" try { - newMetadata.addColumnDefinition(ColumnDefinition.regularDef(metaData, ByteBufferUtil.bytes("id"), UTF8Type.instance, null)); - newMetadata.addColumnDefinition(ColumnDefinition.regularDef(ByteBufferUtil.bytes("id"), LongType.instance, null)); ++ newMetadata.addColumnDefinition(ColumnDefinition.regularDef(metaData, ByteBufferUtil.bytes("id"), LongType.instance, null)); newMetadata.validate(); } catch (ConfigurationException e) @@@ -82,6 -87,44 +87,44 @@@ } assert gotException : "expected ConfigurationException but not received."; + + // make sure the key alias does not affect validation of columns with the same name (CASSANDRA-6892) + Column column = new Column(ByteBufferUtil.bytes("id")); + column.setValue(ByteBufferUtil.bytes("not a long")); + column.setTimestamp(1234); - ThriftValidation.validateColumnData(newMetadata, column, false); ++ ThriftValidation.validateColumnData(newMetadata, null, column); + } + + @Test + public void testColumnNameEqualToDefaultKeyAlias() throws org.apache.cassandra.exceptions.InvalidRequestException + { + CFMetaData metaData = Schema.instance.getCFMetaData("Keyspace1", "UUIDKeys"); + ColumnDefinition definition = metaData.getColumnDefinition(ByteBufferUtil.bytes(CFMetaData.DEFAULT_KEY_ALIAS)); + assertNotNull(definition); - assertEquals(ColumnDefinition.Type.PARTITION_KEY, definition.type); ++ assertEquals(ColumnDefinition.Kind.PARTITION_KEY, definition.type); + + // make sure the key alias does not affect validation of columns with the same name (CASSANDRA-6892) + Column column = new Column(ByteBufferUtil.bytes(CFMetaData.DEFAULT_KEY_ALIAS)); + column.setValue(ByteBufferUtil.bytes("not a uuid")); + column.setTimestamp(1234); - ThriftValidation.validateColumnData(metaData, column, false); ++ ThriftValidation.validateColumnData(metaData, null, column); + + IndexExpression expression = new IndexExpression(ByteBufferUtil.bytes(CFMetaData.DEFAULT_KEY_ALIAS), IndexOperator.EQ, ByteBufferUtil.bytes("a")); + ThriftValidation.validateFilterClauses(metaData, Arrays.asList(expression)); + } + + @Test + public void testColumnNameEqualToDefaultColumnAlias() throws org.apache.cassandra.exceptions.InvalidRequestException + { + CFMetaData metaData = Schema.instance.getCFMetaData("Keyspace1", "StandardLong3"); + ColumnDefinition definition = metaData.getColumnDefinition(ByteBufferUtil.bytes(CFMetaData.DEFAULT_COLUMN_ALIAS + 1)); + assertNotNull(definition); + + // make sure the column alias does not affect validation of columns with the same name (CASSANDRA-6892) + Column column = new Column(ByteBufferUtil.bytes(CFMetaData.DEFAULT_COLUMN_ALIAS + 1)); + column.setValue(ByteBufferUtil.bytes("not a long")); + column.setTimestamp(1234); - ThriftValidation.validateColumnData(metaData, column, false); ++ ThriftValidation.validateColumnData(metaData, null, column); } @Test http://git-wip-us.apache.org/repos/asf/cassandra/blob/8afe1090/test/unit/org/apache/cassandra/tools/SSTableExportTest.java ---------------------------------------------------------------------- diff --cc test/unit/org/apache/cassandra/tools/SSTableExportTest.java index b74ba1a,d0ab6a2..454600d --- a/test/unit/org/apache/cassandra/tools/SSTableExportTest.java +++ b/test/unit/org/apache/cassandra/tools/SSTableExportTest.java @@@ -38,8 -43,9 +40,9 @@@ import org.apache.cassandra.db.marshal. import org.apache.cassandra.io.sstable.Descriptor; import org.apache.cassandra.io.sstable.SSTableReader; import org.apache.cassandra.io.sstable.SSTableWriter; +import org.apache.cassandra.service.ActiveRepairService; import org.apache.cassandra.utils.ByteBufferUtil; -import org.apache.cassandra.utils.FBUtilities; + import org.apache.cassandra.utils.UUIDGen; import org.json.simple.JSONArray; import org.json.simple.JSONObject; import org.json.simple.JSONValue; @@@ -330,4 -336,36 +333,36 @@@ public class SSTableExportTest extends assertEquals("column value did not match", ByteBufferUtil.bytes("val1"), hexToBytes((String) col2.get(1))); } + + /** + * Tests CASSANDRA-6892 (key aliases being used improperly for validation) + */ + @Test + public void testColumnNameEqualToDefaultKeyAlias() throws IOException, ParseException + { + File tempSS = tempSSTableFile("Keyspace1", "UUIDKeys"); - ColumnFamily cfamily = TreeMapBackedSortedColumns.factory.create("Keyspace1", "UUIDKeys"); - SSTableWriter writer = new SSTableWriter(tempSS.getPath(), 2); ++ ColumnFamily cfamily = ArrayBackedSortedColumns.factory.create("Keyspace1", "UUIDKeys"); ++ SSTableWriter writer = new SSTableWriter(tempSS.getPath(), 2, ActiveRepairService.UNREPAIRED_SSTABLE); + + // Add a row + cfamily.addColumn(column(CFMetaData.DEFAULT_KEY_ALIAS, "not a uuid", 1L)); + writer.append(Util.dk(ByteBufferUtil.bytes(UUIDGen.getTimeUUID())), cfamily); + + SSTableReader reader = writer.closeAndOpenReader(); + // Export to JSON and verify + File tempJson = File.createTempFile("CFWithColumnNameEqualToDefaultKeyAlias", ".json"); + SSTableExport.export(reader, new PrintStream(tempJson.getPath()), new String[0]); + + JSONArray json = (JSONArray)JSONValue.parseWithException(new FileReader(tempJson)); + assertEquals(1, json.size()); + + JSONObject row = (JSONObject)json.get(0); + JSONArray cols = (JSONArray) row.get("columns"); + assertEquals(1, cols.size()); + + // check column name and value + JSONArray col = (JSONArray) cols.get(0); + assertEquals(CFMetaData.DEFAULT_KEY_ALIAS, ByteBufferUtil.string(hexToBytes((String) col.get(0)))); + assertEquals("not a uuid", ByteBufferUtil.string(hexToBytes((String) col.get(1)))); + } }