Merge branch 'cassandra-2.2' into cassandra-3.0

This commit is contained in:
Robert Stupp 2015-09-18 09:52:08 +02:00
commit e6f23e63c5
10 changed files with 108 additions and 1 deletions

View File

@ -13,6 +13,7 @@ Merged from 2.2:
* Defer default role manager setup until all nodes are on 2.2+ (CASSANDRA-9761)
* Handle missing RoleManager in config after upgrade to 2.2 (CASSANDRA-10209)
Merged from 2.1:
* Prevent ALTER TYPE from creating circular references (CASSANDRA-10339)
* Fix cache handling of 2i and base tables (CASSANDRA-10155, 10359)
* Fix NPE in nodetool compactionhistory (CASSANDRA-9758)
* (Pig) support BulkOutputFormat as a URL parameter (CASSANDRA-7410)

View File

@ -264,9 +264,13 @@ public abstract class AlterTypeStatement extends SchemaAlteringStatement
newNames.addAll(toUpdate.fieldNames());
newNames.add(fieldName.bytes);
AbstractType<?> addType = type.prepare(keyspace()).getType();
if (addType.references(toUpdate))
throw new InvalidRequestException(String.format("Cannot add new field %s of type %s to type %s as this would create a circular reference", fieldName, type, name));
List<AbstractType<?>> newTypes = new ArrayList<>(toUpdate.size() + 1);
newTypes.addAll(toUpdate.fieldTypes());
newTypes.add(type.prepare(keyspace()).getType());
newTypes.add(addType);
return new UserType(toUpdate.keyspace, toUpdate.name, newNames, newTypes);
}

View File

@ -400,6 +400,14 @@ public abstract class AbstractType<T> implements Comparator<ByteBuffer>
ByteBufferUtil.skipWithVIntLength(in);
}
/**
* Checks whether this type or any of the types this type contains references the given type.
*/
public boolean references(AbstractType<?> check)
{
return this.equals(check);
}
/**
* This must be overriden by subclasses if necessary so that for any
* AbstractType, this == TypeParser.parse(toString()).

View File

@ -116,6 +116,17 @@ public class CompositeType extends AbstractCompositeType
this.types = ImmutableList.copyOf(types);
}
@Override
public boolean references(AbstractType<?> check)
{
if (super.references(check))
return true;
for (AbstractType<?> type : types)
if (type.references(check))
return true;
return false;
}
protected AbstractType<?> getComparator(int i, ByteBuffer bb)
{
try

View File

@ -74,6 +74,12 @@ public class ListType<T> extends CollectionType<List<T>>
this.isMultiCell = isMultiCell;
}
@Override
public boolean references(AbstractType<?> check)
{
return super.references(check) || elements.references(check);
}
public AbstractType<T> getElementsType()
{
return elements;

View File

@ -74,6 +74,12 @@ public class MapType<K, V> extends CollectionType<Map<K, V>>
this.isMultiCell = isMultiCell;
}
@Override
public boolean references(AbstractType<?> check)
{
return super.references(check) || keys.references(check) || values.references(check);
}
public AbstractType<K> getKeysType()
{
return keys;

View File

@ -135,6 +135,11 @@ public class ReversedType<T> extends AbstractType<T>
return baseType.getSerializer();
}
public boolean references(AbstractType<?> check)
{
return super.references(check) || baseType.references(check);
}
@Override
protected int valueLengthIfFixed()
{

View File

@ -68,6 +68,12 @@ public class SetType<T> extends CollectionType<Set<T>>
this.isMultiCell = isMultiCell;
}
@Override
public boolean references(AbstractType<?> check)
{
return super.references(check) || elements.references(check);
}
public AbstractType<T> getElementsType()
{
return elements;

View File

@ -55,6 +55,17 @@ public class TupleType extends AbstractType<ByteBuffer>
return new TupleType(types);
}
@Override
public boolean references(AbstractType<?> check)
{
if (super.references(check))
return true;
for (AbstractType<?> type : types)
if (type.references(check))
return true;
return false;
}
public AbstractType<?> type(int i)
{
return types.get(i);

View File

@ -402,4 +402,53 @@ public class UserTypesTest extends CQLTester
execute("ALTER TYPE " + keyspace() + "." + typeName + " ADD foomap map <int,text>");
execute("INSERT INTO %s (key, data) VALUES (1, {fooint: 1, fooset: {'2'}, foomap: {3 : 'bar'}})");
}
@Test
public void testCircularReferences() throws Throwable
{
String type1 = createType("CREATE TYPE %s (foo int)");
String typeX = createType("CREATE TYPE %s (bar frozen<" + typeWithKs(type1) + ">)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
typeX = createType("CREATE TYPE %s (bar frozen<list<" + typeWithKs(type1) + ">>)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
typeX = createType("CREATE TYPE %s (bar frozen<set<" + typeWithKs(type1) + ">>)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
typeX = createType("CREATE TYPE %s (bar frozen<map<text, " + typeWithKs(type1) + ">>)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
typeX = createType("CREATE TYPE %s (bar frozen<map<" + typeWithKs(type1) + ", text>>)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
//
String type2 = createType("CREATE TYPE %s (foo frozen<" + typeWithKs(type1) + ">)");
typeX = createType("CREATE TYPE %s (bar frozen<" + keyspace() + '.' + type2 + ">)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
typeX = createType("CREATE TYPE %s (bar frozen<list<" + keyspace() + '.' + type2 + ">>)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
typeX = createType("CREATE TYPE %s (bar frozen<set<" + keyspace() + '.' + type2 + ">>)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
typeX = createType("CREATE TYPE %s (bar frozen<map<text, " + keyspace() + '.' + type2 + ">>)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
typeX = createType("CREATE TYPE %s (bar frozen<map<" + keyspace() + '.' + type2 + ", text>>)");
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<" + typeWithKs(typeX) + '>');
//
assertInvalidMessage("would create a circular reference", "ALTER TYPE " + typeWithKs(type1) + " ADD needs_to_fail frozen<list<" + typeWithKs(type1) + ">>");
}
private String typeWithKs(String type1)
{
return keyspace() + '.' + type1;
}
}